pax_global_header00006660000000000000000000000064146450643620014524gustar00rootroot0000000000000052 comment=b0d68c20f49b8f833afa21450e0e8874c87c13c4 mupen64plus-core-src-2.6.0/000077500000000000000000000000001464506436200154465ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/.gitattributes000066400000000000000000000010121464506436200203330ustar00rootroot00000000000000* text=auto # normal text files *.6 text AUTHORS text *.c text *.cfg text *.cht text *.conf text COPYING text *.cpp text *.def text *-license text *.h text *.html text *.ini text INSTALL text LICENSES text Makefile text *.py text README text RELEASE text *.S text *.sh text *.txt text *.ver text # windows specific text files *.cmd text eol=crlf *.sln text eol=crlf *.vcproj text eol=crlf *.vcxproj text eol=crlf *.vcxproj.filters text eol=crlf # binary files *.gz binary *.ttf binary cursor.tex binary font.tex binary mupen64plus-core-src-2.6.0/.github/000077500000000000000000000000001464506436200170065ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/.github/workflows/000077500000000000000000000000001464506436200210435ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/.github/workflows/build.yml000066400000000000000000000130051464506436200226640ustar00rootroot00000000000000name: Core on: push: paths-ignore: - '.{gitattributes,gitignore,travis.yml}' - '*.md,appveyor.yml,README' pull_request: paths-ignore: - '.{gitattributes,gitignore,travis.yml}' - '*.md,appveyor.yml,README' workflow_dispatch: jobs: Linux: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 - cc: GCC arch: x86 - cc: Clang arch: x64 - cc: Clang arch: x86 name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: Get build dependencies and arrange the environment run: | export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev libvulkan-dev zlib1g-dev" ./.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Build and related stuff, backup binaries run: | export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export PATH="$(pwd)/.github/workflows/scripts:${PATH}" export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl2-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl-config" POSTFIX="-old"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl2-config" POSTFIX="-old"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg - name: Upload artifact if: matrix.cc == 'GCC' uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/*.tar.gz MSYS2: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 cross: x86_64 env: MINGW64 - cc: GCC arch: x86 cross: i686 env: MINGW32 name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: windows-2022 defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.env }} update: true install: >- git libtool make mingw-w64-${{ matrix.cross }}-gcc mingw-w64-${{ matrix.cross }}-toolchain mingw-w64-${{ matrix.cross }}-freetype mingw-w64-${{ matrix.cross }}-libpng mingw-w64-${{ matrix.cross }}-nasm mingw-w64-${{ matrix.cross }}-ntldd mingw-w64-${{ matrix.cross }}-SDL2 mingw-w64-${{ matrix.cross }}-vulkan-headers mingw-w64-${{ matrix.cross }}-zlib - name: Build and related stuff, backup binaries run: | export PATH="$(pwd)/.github/workflows/scripts:${PATH}" export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Backup dependencies, etc... run: | ./.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }} - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* MSVC: strategy: fail-fast: false matrix: include: - toolset: v143 arch: x64 vs: 2022 - toolset: v141_xp arch: x86 vs: 2019 name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }} runs-on: windows-${{ matrix.vs }} defaults: run: shell: cmd steps: - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v2 - name: Build and related stuff, backup binaries run: | set PATH=%CD%\.github\workflows\scripts;%PATH% set TOOLSET=${{ matrix.toolset }} call ci_msvc_build.cmd ${{ matrix.arch }} ci_msvc_build.cmd ${{ matrix.arch }} newdyn - name: Backup dependencies, etc... run: | .\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} freetype.dll libpng16.dll SDL2.dll SDL2_net.dll zlib.dll - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* Nightly-build: runs-on: ubuntu-latest if: github.ref_name == 'master' needs: [Linux, MSYS2, MSVC] steps: - uses: actions/checkout@v4 - name: Download artifacts uses: actions/download-artifact@v4 with: path: binaries - name: Get some tools run: | sudo apt-get update sudo apt-get -y install hashdeep - name: Creating new artifacts and update nightly-build run: | ./.github/workflows/scripts/ci_nightly_artifacts.sh - name: Nightly-build uses: ncipollo/release-action@v1 with: prerelease: true allowUpdates: true removeArtifacts: true replacesArtifacts: false tag: nightly-build artifacts: pkg/* mupen64plus-core-src-2.6.0/.github/workflows/schedule.yml000066400000000000000000000127651464506436200233750ustar00rootroot00000000000000name: Core - Scheduled on: schedule: - cron: '55 14 21 * *' jobs: Linux: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 - cc: GCC arch: x86 - cc: Clang arch: x64 - cc: Clang arch: x86 name: Linux / ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: ubuntu-22.04 if: github.repository == 'mupen64plus/mupen64plus-core' steps: - uses: actions/checkout@v4 - name: Get build dependencies and arrange the environment run: | export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export BUILD_DEPS="libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev libvulkan-dev zlib1g-dev" ./.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Build and related stuff, backup binaries run: | export C_CLANG_SUFFIX="-15" C_GCC_SUFFIX="-12" export PATH="$(pwd)/.github/workflows/scripts:${PATH}" export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1 SDL_CONFIG="sdl2-config"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl-config" POSTFIX="-old"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 SDL_CONFIG="sdl2-config" POSTFIX="-old"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg - name: Upload artifact if: matrix.cc == 'GCC' uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/*.tar.gz MSYS2: strategy: fail-fast: false matrix: include: - cc: GCC arch: x64 cross: x86_64 env: MINGW64 - cc: GCC arch: x86 cross: i686 env: MINGW32 name: Windows / MSYS2 ${{ matrix.cc }} / ${{ matrix.arch }} runs-on: windows-2022 if: github.repository == 'mupen64plus/mupen64plus-core' defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.env }} update: true install: >- git libtool make mingw-w64-${{ matrix.cross }}-gcc mingw-w64-${{ matrix.cross }}-toolchain mingw-w64-${{ matrix.cross }}-freetype mingw-w64-${{ matrix.cross }}-libpng mingw-w64-${{ matrix.cross }}-nasm mingw-w64-${{ matrix.cross }}-ntldd mingw-w64-${{ matrix.cross }}-SDL2 mingw-w64-${{ matrix.cross }}-vulkan-headers mingw-w64-${{ matrix.cross }}-zlib - name: Build and related stuff, backup binaries run: | export PATH="$(pwd)/.github/workflows/scripts:${PATH}" export CONFIG_OVERRIDE="ACCURATE_FPU=1 NEW_DYNAREC=1" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} export CONFIG_OVERRIDE="ACCURATE_FPU=0 NEW_DYNAREC=0 POSTFIX="-old"" ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} - name: Backup dependencies, etc... run: | ./.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }} - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* MSVC: strategy: fail-fast: false matrix: include: - toolset: v143 arch: x64 vs: 2022 - toolset: v141_xp arch: x86 vs: 2019 name: Windows / MSVC with ${{ matrix.toolset }} / ${{ matrix.arch }} runs-on: windows-${{ matrix.vs }} if: github.repository == 'mupen64plus/mupen64plus-core' defaults: run: shell: cmd steps: - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v2 - name: Build and related stuff, backup binaries run: | set PATH=%CD%\.github\workflows\scripts;%PATH% set TOOLSET=${{ matrix.toolset }} call ci_msvc_build.cmd ${{ matrix.arch }} ci_msvc_build.cmd ${{ matrix.arch }} newdyn - name: Backup dependencies, etc... run: | .\.github\workflows\scripts\ci_backup_msvc_deps.cmd ${{ matrix.arch }} freetype.dll libpng16.dll SDL2.dll SDL2_net.dll zlib.dll - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ env.PKG_NAME }} path: pkg/* Nightly-build: runs-on: ubuntu-latest if: github.ref_name == 'master' needs: [Linux, MSYS2, MSVC] steps: - uses: actions/checkout@v4 - name: Download artifacts uses: actions/download-artifact@v4 with: path: binaries - name: Get some tools run: | sudo apt-get update sudo apt-get -y install hashdeep - name: Creating new artifacts and update nightly-build run: | ./.github/workflows/scripts/ci_nightly_artifacts.sh - name: Nightly-build uses: ncipollo/release-action@v1 with: prerelease: true allowUpdates: true removeArtifacts: true replacesArtifacts: false tag: nightly-build artifacts: pkg/* mupen64plus-core-src-2.6.0/.github/workflows/scripts/000077500000000000000000000000001464506436200225325ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/.github/workflows/scripts/ci_backup_mingw_deps.sh000077500000000000000000000006321464506436200272260ustar00rootroot00000000000000#!/usr/bin/env bash set -e +u if [[ ${#} -ne 1 ]]; then exit 9; fi export ENV_MSYS="$(echo "${1}" | tr [A-Z] [a-z])" export DEPS="$(LC_ALL=C grep "${ENV_MSYS}" pkg/ldd.log | tr -s '\t' ' ' | sort | cut -d ' ' -f4 | tr '\\' '/' | tr -d ':')" rm -f pkg/ldd.log if [[ "${DEPS}" == "" ]]; then echo ":: None..." exit 0 fi for LIB in ${DEPS}; do echo ":: Copying ${LIB##*/}" cp "/${LIB}" pkg/ done exit 0 mupen64plus-core-src-2.6.0/.github/workflows/scripts/ci_backup_msvc_deps.cmd000066400000000000000000000014211464506436200272000ustar00rootroot00000000000000@echo off setlocal enableextensions enabledelayedexpansion cls if not exist "projects\msvc\" exit /b 9 set ARCH= set DEPS= if "%*" == "" exit /b 8 for %%P in (%*) do ( if /i "%%P" == "x86" (set ARCH=x86) else ( if /i "%%P" == "x64" (set ARCH=x64) else ( set "DEPS=!DEPS! %%P") ) ) if not defined ARCH exit /b 7 if exist "data\" xcopy /e data pkg if errorlevel 1 exit /b 6 if exist "pkg\mupen64plus.desktop" del /f /q pkg\mupen64plus.desktop if not defined DEPS ( echo :: None... exit /b 0 ) set PKG=%CD%\pkg cd ..\mupen64plus-win32-deps if errorlevel 1 exit /b 5 for %%D in (%DEPS%) do ( for /f "tokens=*" %%T in ('dir /b /s %%D ^| findstr "%ARCH%"') do ( if exist "%%T" xcopy "%%T" "%PKG%\" if errorlevel 1 exit /b 4 ) ) exit /b 0 mupen64plus-core-src-2.6.0/.github/workflows/scripts/ci_build.sh000077500000000000000000000055661464506436200246570ustar00rootroot00000000000000#!/usr/bin/env bash set -e +u if [[ ${#} -lt 2 ]]; then exit 9; fi unset ARCH_ARG CC_ARG export MAKE_PKG=0 MULTILIB=0 export ENV_ARGS="$(echo "${*}" | tr [A-Z] [a-z])" for ARG in ${ENV_ARGS}; do case "${ARG}" in clang ) export CC_ARG="Clang" CC="clang${C_CLANG_SUFFIX}" CXX="clang++${C_CLANG_SUFFIX}" ;; gcc ) export CC_ARG="GCC" CC="gcc${C_GCC_SUFFIX}" CXX="g++${C_GCC_SUFFIX}" ;; makepkg ) export MAKE_PKG=1 ;; multilib ) export MULTILIB=1 ;; x64 ) export ARCH_ARG="x64" CPU_TUNE="-march=nocona" BITS=64 ;; x86 ) export ARCH_ARG="x86" CPU_TUNE="-march=pentium4" BITS=32 ;; esac done if [[ -z ${ARCH_ARG} ]]; then exit 8; fi if [[ -z ${CC_ARG} ]]; then exit 7; fi export REPO="${PWD##*/}" if [[ "${REPO}" == "" ]]; then exit 6; fi export BIN_OS="$(uname -s | tr [A-Z] [a-z])" if [[ ! -z ${MSYSTEM} ]]; then export BIN_OS="msys2"; fi export ENV_NAME="$(uname -s)" export LDD="ldd" export PKG_PATH="usr/local/lib/mupen64plus/" if [[ "${REPO}" == *"core"* ]]; then export PKG_PATH="usr/local/lib/" elif [[ "${REPO}" == *"ui-console"* ]]; then export PKG_PATH="usr/local/bin/" fi if [[ "${ENV_NAME}" == *"Linux"* ]]; then if [[ "${ARCH_ARG}" == "x86" ]]; then export PIC=1 PIE=1; fi if [[ ${MULTILIB} -eq 0 ]]; then if [[ "${CC_ARG}" == "GCC" ]]; then if [[ "${ARCH_ARG}" == "x86" ]]; then export CC="i686-linux-gnu-${CC}" CXX="i686-linux-gnu-${CXX}"; fi fi fi fi if [[ "${ENV_NAME}" == *"MINGW"* ]]; then export INSTALL_OVERRIDE="PLUGINDIR="" SHAREDIR="" BINDIR="" MANDIR="" LIBDIR="" APPSDIR="" ICONSDIR="icons" INCDIR="api"" export LDD="ntldd -R" unset PKG_PATH fi export G_REV="$(git rev-parse --short HEAD)" export PKG_NAME="${REPO}-${BIN_OS}-${ARCH_ARG}-g${G_REV}" if [[ -f "${GITHUB_ENV}" ]]; then set +e grep "PKG_NAME=${PKG_NAME}" "${GITHUB_ENV}" > /dev/null if [[ ${?} -ne 0 ]]; then echo "PKG_NAME=${PKG_NAME}" >> "${GITHUB_ENV}"; fi set -e fi if [[ -z ${OPTFLAGS} ]]; then export OPTFLAGS="-O3 -flto ${CPU_TUNE}"; fi echo "" echo ":: CC=${CC} CXX=${CXX} BITS=${BITS} ${CONFIG_OVERRIDE} ::" echo "" ${CC} --version echo "" make_clean () { make CC="${CC}" CXX="${CXX}" BITS=${BITS} ${CONFIG_OVERRIDE} -C projects/unix clean echo "" } make_clean make CC="${CC}" CXX="${CXX}" BITS=${BITS} ${CONFIG_OVERRIDE} -C projects/unix all -j4 echo "" if [[ ! -d pkg ]]; then mkdir pkg chmod -R 755 pkg fi pushd projects/unix > /dev/null export ARTIFACT="$(find *mupen64plus* -type f 2> /dev/null | head -n 1)" popd > /dev/null make CC="${CC}" CXX="${CXX}" BITS=${BITS} ${CONFIG_OVERRIDE} -C projects/unix install ${INSTALL_OVERRIDE} DESTDIR="$(pwd)/pkg/" echo "" make_clean if [[ -z ${ARTIFACT} ]]; then exit 5 else cd pkg ls -gG "${PKG_PATH}${ARTIFACT}" echo "" ${LDD} "${PKG_PATH}${ARTIFACT}" > ldd.log cat ldd.log echo "" if [[ ${MAKE_PKG} -eq 1 ]]; then tar --owner=0 --group=0 --mode='og-w' -czf "${PKG_NAME}.tar.gz" usr; fi fi exit 0 mupen64plus-core-src-2.6.0/.github/workflows/scripts/ci_get_libglew_i386.sh000077500000000000000000000013421464506436200266010ustar00rootroot00000000000000#!/usr/bin/env bash set -e +u # NOTE: There is no native "libglew-dev:i386" in Ubuntu 22.04, we will use Debian ones... export GLEWVER="$(apt list libglew-dev | grep "amd64" | cut -d ' ' -f2)" export PKGS="$(apt list libglew* | grep "${GLEWVER}" | cut -d '/' -f1)" export DEBSOURCE="http://http.us.debian.org/debian/pool/main/g/glew/" export PKGVER_LS="$(curl -sS ${DEBSOURCE} | grep "${GLEWVER}" | grep "amd64" | cut -d '_' -f2 | sort)" if [[ "${PKGVER_LS}" != "" ]]; then for VER in ${PKGVER_LS}; do export PKGVER="${VER}"; done cd /tmp for PKG in ${PKGS}; do for ARCH in amd64 i386; do curl -L -O "${DEBSOURCE}${PKG}_${PKGVER}_${ARCH}.deb"; done done sudo dpkg -i libglew*${PKGVER}*.deb else exit 9 fi sudo ldconfig exit 0 mupen64plus-core-src-2.6.0/.github/workflows/scripts/ci_install_ubuntu_deps.sh000077500000000000000000000025331464506436200276320ustar00rootroot00000000000000#!/usr/bin/env bash set -e +u if [[ ${#} -lt 2 ]]; then exit 9; fi unset ARCH_DEP CC_DEP export BUILD_DEPS_I386="crossbuild-essential-i386 g++${C_GCC_SUFFIX}-i686-linux-gnu gcc${C_GCC_SUFFIX}-i686-linux-gnu libc6-i386" export HOTFIX_I386="libatomic1:i386 libgcc-s1:i386 libstdc++6:i386 ${HOTFIX_I386}" export ENV_ARGS="$(echo "${*}" | tr [A-Z] [a-z])" for ARG in ${ENV_ARGS}; do case "${ARG}" in clang ) export CC_DEP="clang${C_CLANG_SUFFIX}" ;; gcc ) export CC_DEP="g++${C_GCC_SUFFIX} gcc${C_GCC_SUFFIX}" ;; multilib ) export BUILD_DEPS_I386="g++${C_GCC_SUFFIX}-multilib gcc${C_GCC_SUFFIX}-multilib libc6-dev-i386" ;; x64 ) export ARCH_DEP="x64" ;; x86 ) export ARCH_DEP="x86" ;; esac done if [[ -z ${ARCH_DEP} ]]; then exit 8; fi if [[ -z ${CC_DEP} ]]; then exit 7; fi sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test if [[ "${ARCH_DEP}" == "x86" ]]; then sudo dpkg --add-architecture i386; fi sudo apt-get update sudo apt-get -y install build-essential git nasm pkg-config ${CC_DEP} ${BUILD_DEPS} if [[ "${ARCH_DEP}" == "x86" ]]; then if [[ "${BUILD_DEPS}" != "" ]]; then for DEP in ${BUILD_DEPS}; do if [[ "${DEP}" != "libglew-dev" ]]; then export BUILD_DEPS_I386="${BUILD_DEPS_I386} ${DEP}:i386"; fi done fi sudo apt-get --reinstall -y install ${BUILD_DEPS_I386} ${HOTFIX_I386} fi sudo ldconfig exit 0 mupen64plus-core-src-2.6.0/.github/workflows/scripts/ci_msvc_build.cmd000066400000000000000000000033531464506436200260250ustar00rootroot00000000000000@echo off setlocal enableextensions disabledelayedexpansion cls if not exist "projects\msvc\" exit /b 9 set ARCH= set CONF=Release if "%*" == "" exit /b 8 for %%P in (%*) do ( if /i "%%P" == "x86" set ARCH_ARG=x86& set ARCH=Win32 if /i "%%P" == "x64" set ARCH_ARG=x64& set ARCH=x64 if /i "%%P" == "newdyn" set CONF=New_Dynarec_Release ) if not defined ARCH exit /b 7 for %%T in (.) do set REPO=%%~nxT if not defined REPO exit /b 6 set ARTIFACT= set FPROJ= set EXT=dll echo %REPO% | findstr "ui-console" >nul 2>&1 if not errorlevel 1 set EXT=exe if not defined TOOLSET set TOOLSET=v143 for /f "tokens=1" %%R in ('git rev-parse --short HEAD') do set G_REV=%%R set PKG_NAME=%REPO%-msvc-%ARCH_ARG%-g%G_REV% if exist "%GITHUB_ENV%" ( type "%GITHUB_ENV%" | findstr "PKG_NAME=%PKG_NAME%" >nul 2>&1 if errorlevel 1 echo PKG_NAME=%PKG_NAME%>> "%GITHUB_ENV%" ) echo. msbuild --version echo. if not exist "..\mupen64plus-win32-deps\" git clone --depth 1 https://github.com/mupen64plus/mupen64plus-win32-deps.git ..\mupen64plus-win32-deps pushd projects\msvc\ for /f "tokens=*" %%F in ('dir /b *.vcxproj') do set FPROJ=%%F popd if not defined FPROJ exit /b 5 echo. msbuild "projects\msvc\%FPROJ%" /p:Configuration=%CONF%;Platform=%ARCH%;PlatformToolset=%TOOLSET% /t:Rebuild if errorlevel 1 exit /b 4 echo. if exist "projects\msvc\%ARCH%\Release\mupen64plus.dll" ren "projects\msvc\%ARCH%\Release\mupen64plus.dll" mupen64plus-old.dll pushd projects\msvc\%ARCH%\%CONF%\ for /f "tokens=*" %%S in ('dir /b mupen64plus*%EXT%') do set ARTIFACT=%%S popd if not defined ARTIFACT exit /b 3 md pkg 2>nul xcopy "projects\msvc\%ARCH%\%CONF%\%ARTIFACT%" pkg\ if errorlevel 1 exit /b 2 dir "pkg\%ARTIFACT%" exit /b 0 mupen64plus-core-src-2.6.0/.github/workflows/scripts/ci_nightly_artifacts.sh000077500000000000000000000015131464506436200272620ustar00rootroot00000000000000#!/usr/bin/env bash set -e +u export REPO="${PWD##*/}" if [[ "${REPO}" == "" ]]; then exit 9; fi rm -fr pkg mkdir pkg cd binaries for BIN in *; do cd "${BIN}" case "${BIN}" in *msvc* | *msys2* ) echo ":: Creating ${BIN}.zip" zip -r "../../pkg/${BIN}.zip" * ;; * ) echo ":: Recovering ${BIN}.tar.gz" mv *.tar.gz ../../pkg/ ;; esac cd .. done cd ../pkg echo "" for ZIP in *; do ls -gG ${ZIP} tigerdeep -lz ${ZIP} >> ../${REPO}.tiger.txt sha256sum ${ZIP} >> ../${REPO}.sha256.txt sha512sum ${ZIP} >> ../${REPO}.sha512.txt b2sum ${ZIP} >> ../${REPO}.blake2.txt done mv ../${REPO}.*.txt . echo "" for HASH in tiger sha256 sha512 blake2; do echo "${HASH}:" | tr [a-z] [A-Z] cat *.${HASH}.txt echo "" done if [[ -f "${GITHUB_ENV}" ]]; then git tag -f nightly-build git push -f origin nightly-build fi exit 0 mupen64plus-core-src-2.6.0/.gitignore000066400000000000000000000001541464506436200174360ustar00rootroot00000000000000/projects/unix/_obj*/ /projects/unix/libmupen64plus*.so* /.vscode /projects/unix/*.dll /src/asm_defines/*.h mupen64plus-core-src-2.6.0/.travis.yml000066400000000000000000000106161464506436200175630ustar00rootroot00000000000000sudo: required dist: xenial language: cpp compiler: - gcc - clang addons: apt: packages: - libsdl1.2-dev - libsdl-net1.2-dev - libsdl2-dev - libsdl2-net-dev - libfreetype6-dev - libgl1-mesa-dev - libglu1-mesa-dev - libpng-dev - pkg-config - zlib1g-dev - liblircclient-dev - binutils-dev - nasm - libopencv-dev env: - OSD=0 - OSD=1 - NO_ASM=1 - LIRC=1 - PROFILE=1 - DEBUGGER=1 - DBG_CORE=1 - DBG_COUNT=1 - DBG_COMPARE=1 - COUNT_INSTR=1 - NETPLAY=1 script: - make -C projects/unix V=1 clean && LDFLAGS="-Wl,--no-add-needed -Wl,--no-undefined" OPTFLAGS="-O2" make SDL_CONFIG=sdl-config CC="${CC}" CXX="${CXX}" -j$(nproc) -C projects/unix V=1 all - make -C projects/unix V=1 clean && LDFLAGS="-Wl,--no-add-needed -Wl,--no-undefined" OPTFLAGS="-O2" make SDL_CONFIG=sdl2-config CC="${CC}" CXX="${CXX}" -j$(nproc) -C projects/unix V=1 all # extra mxe build entries matrix: include: - env: - MXE_CPU=i686 - PATH="/usr/lib/mxe/usr/bin/:$PATH" before_install: - curl -sSL "https://mirror.mxe.cc/repos/apt/client-conf/mxeapt.gpg" | sudo -E apt-key add - - echo "deb https://mirror.mxe.cc/repos/apt xenial main" | sudo tee -a /etc/apt/sources.list - sudo apt-get update -qq - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-gcc - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-sdl2 - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-sdl2-net - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-freeglut - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-freetype - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-libpng - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-zlib - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-opencv - sudo apt-get -y --allow-unauthenticated install mxe-i686-w64-mingw32.shared-pkgconf - sudo apt-get -y --allow-unauthenticated install nasm script: - 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}" SDL_CONFIG="${MXE_CPU}-w64-mingw32.shared-sdl2-config" -C projects/unix V=1 clean && 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}" SDL_CONFIG="${MXE_CPU}-w64-mingw32.shared-sdl2-config" -C projects/unix V=1 -j$(nproc) all - env: - MXE_CPU=x86_64 - PATH="/usr/lib/mxe/usr/bin/:$PATH" before_install: - curl -sSL "https://mirror.mxe.cc/repos/apt/client-conf/mxeapt.gpg" | sudo -E apt-key add - - echo "deb https://mirror.mxe.cc/repos/apt xenial main" | sudo tee -a /etc/apt/sources.list - sudo apt-get update -qq - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-gcc - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-sdl2 - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-sdl2-net - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-freeglut - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-freetype - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-libpng - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-zlib - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-opencv - sudo apt-get -y --allow-unauthenticated install mxe-x86-64-w64-mingw32.shared-pkgconf - sudo apt-get -y --allow-unauthenticated install nasm script: - 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}" SDL_CONFIG="${MXE_CPU}-w64-mingw32.shared-sdl2-config" -C projects/unix V=1 clean && 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}" SDL_CONFIG="${MXE_CPU}-w64-mingw32.shared-sdl2-config" -C projects/unix V=1 -j$(nproc) all mupen64plus-core-src-2.6.0/CREDITS000066400000000000000000000154021464506436200164700ustar00rootroot00000000000000=================================================================================================== | Mupen64Plus 2.5 credits April 26th, 2015 | =================================================================================================== bentley - video-glide64mk2: - bugfix: use memmove() instead of memcpy() for overlapping buffers bsmiles32 - core: - refactor profiling: move from r4300 to main folder - major r4300 cpu core refactoring to improve code quality and organization - rsp-hle: - Game-specific fixes: Bottom of the 9th, Goldeneye - Support for MusyX microcodes (v1 and v2) - Huge quantity of code cleanup and refactorings in audio microcode and processing logic - Improve audio microcode identification - Add support for additional audio commands: #16, POLEF, RESAMPLE_ZOH - Move global variables into a struct so code is re-entrant - bugfix: microcode detection could sometimes fail after reset Conchur Navid - All Modules (audio, core, input, rsp-hle, ui-console, video-rice) - C header includes and forward declarations clean-ups - core: - fixes for minor issues revealed by coverity static analysis - input: - support for new SDL2 generic XInput device name - video-rice: - build fixes ecsv - All Modules (audio, core, input, rsp-hle, ui-console, video-glide64mk2, video-rice) - fix all line endings, convert SCM metadata files from Hg to Git - core: - pif_ram fix for Banjo Tooie - SDL2 fixes - game-specific override for # of clock cycles per cpu instruction - input: - convert SDL2 keycodes to sdl1.2 keysyms so that input section parameters in mupen64plus.cfg will work with sdl1.2 keysyms - SDL2: support for mapping mouse to controller analog x/y - use prioritization to decide among multiple matching auto-config sections (for SDL2 / XInput) - rsp-hle: - Huge quantity of code cleanups and refactoring to improve organization - video-glide64mk2 - fix colors in compressed fxt1 textures by importing mesa code - replace patented S3TC algorithm with S2TC - Enable the dump_cache to allow loading of dat files - bugfix: work around problem in OSD callback whereby core code doesn't re-activate shader - bugfix: Resident Evil II hang - allow user override of game-specific settings via mupen64plus.cfg fayvel - All Modules (audio, core, input, rsp-hle, ui-console, video-glide64mk2, video-rice) - Travis CI config file - core: - OpenGL ES support - wiki documentation fixes - input: - fix SDL2 build regression - video-glide64mk2: - remove unused #ifdef sections - various build fixes - video-rice: - fix for INI file loading under Windows - minor OpenGL ES fixes Gillou68310 - All Modules (audio, core, input, rsp-hle, ui-console, video-glide64mk2, video-rice) - MSVC2010 project file - core: - new_dynarec: fixes for various MIPS instructions - new_dynarec: port asm code to Intel format, add MSVC build support - video-rice: - OpenGL ES fixes - Add hack-fix to show last heart and map arrows in Zelda OoT & MM - Support screenshots with OpenGL ES gizmo98 - core: - raspberry pi fixes and build system improvements - input: - auto-configs for multiple devices - video-rice: - makefile build support for Raspberry Pi - OpenGL ES build fixes kode54 - rsp-hle: - Implement IIR filter for nAudio (for Conker's Bad Fur Day) krnlyng - audio: - implement audioresource support for integration with Linux-based Nemo Mobile OS - core: - add render callback to input plugin - video-glide64mk2: - add OpenGL ES support (2.0) (from mupen64plus-ae) - bugfix: chroma_color uniform variable name was not being set (from Themaister) - video-rice: - integrate OpenGL ES code into build system - support Rotate option in OpenGL ES littleguy77 - android makefile and project history (for: audio, core, rsp-hle) - core: - fix config parameter name for savestate slot - fixes to MD5 values in mupen64plus.ini - ui-console: - compile-time flag to support building ui-console as a library (used by Android frontend) - video-glide64mk2: - add config option to force polygon offset values (fixes artifacts on certains games / renderers) - Implement optional frameskip feature, which drops frames instead of rendering if game is going slow - video-rice: - Android build fix - opengl es minor fixes and cleanups - add config option to force polygon offset values (fixes artifacts on certains games / renderers) Narann - core: - implement ConfigSetParameterHelp - ui-console: - add support for loading savestate immediately on emulator startup - video-rice: - Lots of code cleanup, removal of deprecated code, and simplifications - Add config parameter versioning - Modernize OpenGL interfaces, remove code for supporting very old opengl versions - Graphics fixes for: fog, RDP InsertMatrix Nebuleon - simplify makefiles (for: audio, input) - core: - floating-point optimizations (don't set rounding modes when not needed) - compatibility fixes regarding FPU rounding modes - decouple pure interpreter from cached interpreter - use stdint.h types Paulscode - core: - fix bug in speed limiter Richard42 - All Modules (audio, core, input, rsp-hle, ui-console, video-glide64mk2, video-rice) - Visual Studio 2013 project/solution files - fix and maintain OSX builds - core: - regression test improvements - input: - merge new auto-configurations from users - When Mouse=True but pointer is un-grabbed, fall back to joystick settings for analog x/y - video-glide64mk2: - use SDL threads instead of C++11 threads, which are not currntly supported in Apple's clang compiler - fix texture pack read failure on some 64-bit platforms, found by EndoplasmaticReticulum on github - bugfix: memory bugs found by coverity in fxt1 code ricrpi - core: - rewrite speed limiter code to improve performance on Raspberry Pi - ARM build fixes and optimizations rlabrecque - video-glide64mk2: - on Win32, don't set gamma table because it breaks monitor calibration - video-rice: - bugfix: crash if RiceVideoLinux.ini not found s-verma - input: - Prevent mouse/trackpad auto-centering behavior by pressing left-Windows key twinaphex - glide64mk2: - Fix broken C version of MulMatricesC - correct N64 ROM header analysis for PAL/NTSC detection, to get proper frequency for frame skipper Ursula Abendroth - All Modules (audio, core, input, rsp-hle, ui-console, video-glide64mk2, video-rice) - makefile: use SDL2 by default if present - video-glide64mk2: - patch to clean up antialiasing patches from willrandship willrandship - video-glide64mk2: - add option to enable full-scene antialiasing wnayes - core: - code cleanups in debugger mupen64plus-core-src-2.6.0/INSTALL000066400000000000000000000015151464506436200165010ustar00rootroot00000000000000Mupen64Plus-Core INSTALL ------------------------ This text file was written to explain the installation process of the Mupen64Plus-Core module. If this module is part of a Mupen64Plus source code bundle, the user should run the "m64p_install.sh" script in the root of the unzipped bundle to install all of the included modules in the bundle. If this module is a standalone source code release, you should build the library from source code and install it via the makefile, like this: $ cd projects/unix $ make all $ sudo make install If you want to build the Mupen64Plus-Core module for installation in a home folder for a single user, you may build it like this (replacing with your desired local installation path): $ cd projects/unix $ make all SHAREDIR= $ make install LIBDIR= SHAREDIR= mupen64plus-core-src-2.6.0/LICENSES000066400000000000000000000041621464506436200166010ustar00rootroot00000000000000Mupen64Plus-Core LICENSES ------------------------- Mupen64Plus-Core is licensed under the GNU General Public License version 2. Please see the included doc/gpl-license file for the terms and conditions of the GNU General Public License. The authors of Mupen64Plus-Core are: * Richard Goedeken (Richard42) * Sven Eckelmann (ecsv) * John Chadwick (NMN) * James Hood (Ebenblues) * Scott Gorman (okaygo) * Scott Knauert (Tillin9) * Jesse Dean (DarkJezter) * Louai Al-Khanji (slougi) * Bob Forder (orbitaldecay) * Jason Espinosa (hasone) * Bobby Smiles (bsmiles32) * Dorian Fevrier (Narann) * Richard Hender (ricrpi) * Will Nayes (wnayes) * Conchur Navid * Gillou68310 * HyperHacker * littleguy77 * Nebuleon * and others. The Mupen64Plus API documentation (located in doc/emuwiki-api-doc/*) is Copyright(C) 2009-2011 by Richard Goedeken and is licensed under the GNU General Public License version 2. Mupen64Plus is based on GPL-licensed source code from Mupen64 v0.5, originally written by: * Hacktarux * Dave2001 * Zilmar * Gregor Anich (Blight) * Juha Luotio (JttL) * and others. The OGLFT library used for the On-Screen Display is based on GPL/LGPL-licensed code Copyright 2002 lignum Computing. Please see the included doc/lgpl-license file for the terms and conditions of the GNU Lesser General Public License. More information about this library is available at the following websites: - http://oglft.sourceforge.net/index.html - http://directory.fsf.org/project/OGLFT/ Additionally, mupen includes a number of components licensed under other OSI approved licenses: The BSD license: * minizip by Gilles Vollant and others, ftp://ftp.info-zip.org/pub/infozip/license.html * src/memory/n64_cic_nus_6105.c/.h, by X-Scale The zlib/libpng license: * Adler-32 by Mark Adler * libpng by Glenn Randers-Pehrson, Peter Deutsch, and Guy Eric Schalnat * MD5 hasing code by Peter Deutsch The Bitstream license: * The TrueType font (data/font.ttf) is licensed by the Bitstream license. Please see the included doc/font-license file for the terms and conditions of the Bitstream license. mupen64plus-core-src-2.6.0/README000066400000000000000000000207031464506436200163300ustar00rootroot00000000000000Mupen64Plus-Core README ----------------------- More documentation can be found on the Mupen64Plus website. (https://mupen64plus.org/docs/) You can find a more complete README file on the wiki: https://mupen64plus.org/wiki/index.php/README Mupen64Plus is based off of mupen64, originally created by Hacktarux. This package contains the only the Mupen64Plus core library. For a fully functional emulator, the user must also install graphics, sound, input, and RSP plugins, as well as a user interface program (called a front-end). README Sections 1. Requirements for building or running Mupen64Plus 2. Building From Source 3. Installation 4. Key Commands In Emulator 1. Requirements and Pre-requisites ---------------------------------- *Binary Package Requirements* - SDL 1.2 or 2.0 - libpng - freetype 2 - zlib *Source Build Requirements* In addition to the binary libraries, the following packages are required if you build Mupen64Plus from source: - GNU C and C++ compiler, libraries, and headers - GNU make - Nasm - Development packages for all the libraries above 2. Building From Source ----------------------- If you downloaded the binary distribution of Mupen64Plus, skip to the Installation section. To build the source distribution, unzip and cd into the projects/unix directory, then build using make: $ unzip mupen64plus-core-x-y-z-src.zip $ cd mupen64plus-core-x-y-z-src/projects/unix $ make all Type 'make' by itself to view all available build options: $ make Mupen64Plus-core makefile. Targets: all == Build Mupen64Plus core library clean == remove object files install == Install Mupen64Plus core library uninstall == Uninstall Mupen64Plus core library Build Options: BITS=32 == build 32-bit binaries on 64-bit machine LIRC=1 == enable LIRC support NO_ASM=1 == build without assembly (no dynamic recompiler or MMX/SSE code) USE_GLES=1 == build against GLESv2 instead of OpenGL VC=1 == build against Broadcom Videocore GLESv2 NEON=1 == (ARM only) build for hard floating point environments VFP_HARD=1 == (ARM only) full hardware floating point ABI SHAREDIR=path == extra path to search for shared data files OPTFLAGS=flag == compiler optimization (default: -O3 -flto) WARNFLAGS=flag == compiler warning levels (default: -Wall) PIC=(1|0) == Force enable/disable of position independent code OSD=(1|0) == Enable/disable build of OpenGL On-screen display NETPLAY=1 == Enable netplay functionality, requires SDL2_net NEW_DYNAREC=1 == Replace dynamic recompiler with Ari64's experimental dynarec KEYBINDINGS=0 == Disables the default keybindings ACCURATE_FPU=1 == Enables accurate FPU behavior (i.e correct cause bits) OPENCV=1 == Enable OpenCV support VULKAN=0 == Disable vulkan support for the default video extension implementation POSTFIX=name == String added to the name of the the build (default: '') Install Options: PREFIX=path == install/uninstall prefix (default: /usr/local/) SHAREDIR=path == path to install shared data files (default: PREFIX/share/mupen64plus) LIBDIR=path == path to install core library (default: PREFIX/lib) INCDIR=path == path to install core header files (default: PREFIX/include/mupen64plus) DESTDIR=path == path to prepend to all installation paths (only for packagers) Debugging Options: PROFILE=1 == build gprof instrumentation into binaries for profiling DEBUG=1 == add debugging symbols to binaries DEBUGGER=1 == build debugger API into core for front-ends. runs slower. DBG_CORE=1 == print debugging info in r4300 core DBG_COUNT=1 == print R4300 instruction count totals (64-bit dynarec only) DBG_COMPARE=1 == enable core-synchronized r4300 debugging DBG_TIMING=1 == print timing data DBG_PROFILE=1 == dump profiling data for r4300 dynarec to data file V=1 == show verbose compiler output 3. Installation --------------- *Binary Distribution* To install the binary distribution of Mupen64Plus, su to root and run the provided install.sh script: $ su # ./install.sh # exit $ The install script will copy the executable to /usr/local/bin and a directory called /usr/local/share/mupen64plus will be created to hold plugins and other files used by mupen64plus. NOTE: By default, install.sh uses /usr/local for the install prefix. Although the user can specify an alternate prefix to install.sh at the commandline, the mupen64plus binary was compiled to look for the install directory in /usr/local, so specifying an alternate prefix to install.sh will cause problems (the mupen64plus front-end application will not find the directory containing the core library) unless the directory to which you install it is known by your dynamic library loader (ie, included in /etc/ld.conf.so) If you want to use a prefix other than /usr/local, you may also download the source code package and build with the PREFIX option (see below). *Source Distribution* After building mupen64plus and all plugins, su to root and type 'make install' to install Mupen64Plus. The install process will copy the executable to $PREFIX/bin and a directory called $PREFIX/share/mupen64plus will be created to hold plugins and other files used by mupen64plus. By default, PREFIX is set to /usr/local. This can be changed by passing the PREFIX option to make. NOTE: you must pass the prefix, when building AND installing. For example, to install mupen64plus to /usr, do this: $ make PREFIX=/usr all $ sudo make PREFIX=/usr install $ *Custom Installation Paths* You may customize the installation of the Mupen64Plus program by using the options for the install.sh script: usage: install.sh [PREFIX] [SHAREDIR] [BINDIR] [LIBDIR] [MANDIR] PREFIX - installation directories prefix (default: /usr/local) SHAREDIR - path to Mupen64Plus shared data files (default: $PREFIX/share/mupen64plus) BINDIR - path to Mupen64Plus binary program files (default: $PREFIX/bin) LIBDIR - path to Mupen64Plus plugin files (default: $SHAREDIR/plugins) MANDIR - path to manual files (default: $PREFIX/man/man1) You must pass the same options to the uninstall.sh script when uninstalling in order to remove all of the Mupen64Plus files. You should install the Mupen64Plus plugins (libraries) in their own folder. If you install them in a common directory such as /usr/lib and then later uninstall them with "sudo uninstall.sh LIBDIR=/usr/lib", it will delete all system libraries. If you install with SHAREDIR in a place other than /usr/local/share/mupen64plus or /usr/share/mupen64plus, and BINDIR is not the same as SHAREDIR, then users will have to run Mupen64Plus with the --installdir= option, otherwise they will get an error. The mupen64plus executable looks in up to 5 different directories in order to find the Shared Data Directory. The order in which the directories are searched is: - directory specified on command line with --installdir - same directory as the mupen64plus binary - /usr/local/share/mupen64plus - /usr/share/mupen64plus - current working directory If you choose to install the plugins in a non-standard location (someplace other than $SHAREDIR/plugins), then you must set the PluginDirectory parameter in the mupen64plus.conf config file to the directory path in which the plugins have been installed. 4. Key Commands In Emulator --------------------------- The keys or joystick/mouse inputs which will be mapped to the N64 controller for playing the games are determined by the input plugin. The emulator core also supports several key commands during emulation, which may be configured by editing the ~/.config/mupen64plus/mupen64plus.cfg file. They are: Escape == Quit the emulator 0-9 == Select virtual 'slot' for save/load state (F5 and F7) commands F5 == Save emulator state F7 == Load emulator state F9 == Reset emulator F10 == slow down emulator by 5% F11 == speed up emulator by 5% F12 == take screenshot Alt-Enter == Toggle between windowed and fullscreen (may not be supported by all video plugins) p or P == Pause on/off m or M == Mute/unmute sound g or G == Press "Game Shark" button (only if cheats are enabled) / or ? == single frame advance while paused F == Fast Forward (playback at 250% normal speed while F key is pressed) [ == Decrease volume ] == Increase volume mupen64plus-core-src-2.6.0/README.md000066400000000000000000000220261464506436200167270ustar00rootroot00000000000000# Mupen64Plus-Core README [![GitHub Actions Build Status](https://github.com/mupen64plus/mupen64plus-core/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/mupen64plus/mupen64plus-core/actions) [![Coverity Scan Build Status](https://scan.coverity.com/projects/4381/badge.svg)](https://scan.coverity.com/projects/mupen64plus-core) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/a1ua5t87n2w8a7fc?svg=true)](https://ci.appveyor.com/project/Narann/mupen64plus-core) More documentation can be found on the [Mupen64Plus website](https://mupen64plus.org/docs/) and you can find a more complete README file on the [wiki](https://mupen64plus.org/wiki/index.php/README). Mupen64Plus is based off of mupen64, originally created by Hacktarux. This package contains only the Mupen64Plus core library. For a fully functional emulator, the user must also install graphics, sound, input, and RSP plugins, as well as a user interface program (called a front-end). ### README Sections 1. Requirements and Prerequisites - Binary - Source 2. Building From Source 3. Installation - Binary - Source - Custom Installation Path 4. Key Commands In Emulator ## 1. Requirements and Pre-requisites **Binary Package Requirements** - SDL 1.2 or 2.0 - libpng - freetype 2 - zlib **Source Build Requirements** In addition to the binary libraries, the following packages are required if you build Mupen64Plus from source: - GNU C and C++ compiler, libraries, and headers - GNU make - Nasm - Development packages for all the libraries above ## 2. Building From Source If you downloaded the binary distribution of Mupen64Plus, skip to the Installation process (Section 3). To build the source distribution, unzip and cd into the projects/unix directory, then build using make: ``` $ unzip mupen64plus-core-x-y-z-src.zip $ cd mupen64plus-core-x-y-z-src/projects/unix $ make all ``` Type `make` by itself to view all available build options: ``` $ make Mupen64Plus-core makefile. Targets: all == Build Mupen64Plus core library clean == remove object files install == Install Mupen64Plus core library uninstall == Uninstall Mupen64Plus core library Build Options: BITS=32 == build 32-bit binaries on 64-bit machine LIRC=1 == enable LIRC support NO_ASM=1 == build without assembly (no dynamic recompiler or MMX/SSE code) USE_GLES=1 == build against GLESv2 instead of OpenGL VC=1 == build against Broadcom Videocore GLESv2 NEON=1 == (ARM only) build for hard floating point environments VFP_HARD=1 == (ARM only) full hardware floating point ABI SHAREDIR=path == extra path to search for shared data files OPTFLAGS=flag == compiler optimization (default: -O3 -flto) WARNFLAGS=flag == compiler warning levels (default: -Wall) PIC=(1|0) == Force enable/disable of position independent code OSD=(1|0) == Enable/disable build of OpenGL On-screen display NETPLAY=1 == Enable netplay functionality, requires SDL2_net NEW_DYNAREC=1 == Replace dynamic recompiler with Ari64's experimental dynarec KEYBINDINGS=0 == Disables the default keybindings ACCURATE_FPU=1 == Enables accurate FPU behavior (i.e correct cause bits) OPENCV=1 == Enable OpenCV support VULKAN=0 == Disable vulkan support for the default video extension implementation POSTFIX=name == String added to the name of the the build (default: '') Install Options: PREFIX=path == install/uninstall prefix (default: /usr/local/) SHAREDIR=path == path to install shared data files (default: PREFIX/share/mupen64plus) LIBDIR=path == path to install core library (default: PREFIX/lib) INCDIR=path == path to install core header files (default: PREFIX/include/mupen64plus) DESTDIR=path == path to prepend to all installation paths (only for packagers) Debugging Options: PROFILE=1 == build gprof instrumentation into binaries for profiling DEBUG=1 == add debugging symbols to binaries DEBUGGER=1 == build debugger API into core for front-ends. runs slower. DBG_CORE=1 == print debugging info in r4300 core DBG_COUNT=1 == print R4300 instruction count totals (64-bit dynarec only) DBG_COMPARE=1 == enable core-synchronized r4300 debugging DBG_TIMING=1 == print timing data DBG_PROFILE=1 == dump profiling data for r4300 dynarec to data file V=1 == show verbose compiler output ``` ## 3. Installation **Binary Distribution** To install the binary distribution of Mupen64Plus, su to root and run the provided install.sh script: ``` $ su # ./install.sh # exit $ ``` The install script will copy the executable to __*/usr/local/bin*__ and a directory called __*/usr/local/share/mupen64plus*__ will be created to hold plugins and other files used by mupen64plus. >NOTE: By default, install.sh uses __*/usr/local*__ for the install prefix. Although the user can specify an alternate prefix to install.sh at the commandline, the mupen64plus binary was compiled to look for the install directory in __*/usr/local*__, so specifying an alternate prefix to install.sh will cause problems (the mupen64plus front-end application will not find the directory containing the core library) unless the directory to which you install it is known by your dynamic library loader (ie, included in __*/etc/ld.conf.so*__) > >If you want to use a prefix other than /usr/local, you may also download the source code package and build with the PREFIX option (see below). **Source Distribution** After building mupen64plus and all plugins, su to root and type `make install` to install Mupen64Plus. The install process will copy the executable to __*$PREFIX/bin*__ and a directory called __*$PREFIX/share/mupen64plus*__ will be created to hold plugins and other files used by mupen64plus. By default, PREFIX is set to __*/usr/local*__. This can be changed by passing the PREFIX option to make. >NOTE: You must pass the prefix, when building AND installing. For example, to install mupen64plus to __*/usr*__, do this: ``` $ make PREFIX=/usr all $ sudo make PREFIX=/usr install $ ``` **Custom Installation Paths** You may customize the instalation of Mupen64Plus by using the options for the install.sh script: > Usage: `install.sh [PREFIX] [SHAREDIR] [BINDIR] [LIBDIR] [MANDIR]` > >__PREFIX__ - installation directories prefix (default: __*/usr/local*__) __SHAREDIR__ - path to Mupen64Plus shared data files (default: __*PREFIX/share/mupen64plus*__) __BINDIR__ - path to Mupen64Plus binary program files (default: __*$PREFIX/bin*__) __LIBDIR__ - path to Mupen64Plus plugin files (default: __*$SHAREDIR/plugins*__) __MANDIR__ - path to manual files (default: __*$PREFIX/man/man1*__) You must pass the same options to the uninstall.sh script when uninstalling in order to remove all of the Mupen64Plus files. You should install the Mupen64Plus plugins (libraries) in their own folder. If you install them in a common directory such as __*/usr/lib*__ and then later uninstall them with `sudo uninstall.sh LIBDIR=/usr/lib`, it will delete all system libraries. If you install with SHAREDIR in a place other than __*/usr/local/share/mupen64plus*__ or __*/usr/share/mupen64plus*__, and BINDIR is not the same as SHAREDIR, then users will have to run Mupen64Plus with the `--installdir=` option, otherwise they will get an error. The mupen64plus executable looks in up to 5 different directories in order to find the Shared Data Directory. The order in which the directories are searched is: - directory specified on command line with `--installdir` - same directory as the mupen64plus binary - __*/usr/local/share/mupen64plus*__ - __*/usr/share/mupen64plus*__ - current working directory If you choose to install the plugins in a non-standard location (someplace other than __*$SHAREDIR/plugins*__), then you must set the PluginDirectory parameter in the `mupen64plus.conf` config file to the directory path in which the plugins have been installed. ## 4. Key Commands In Emulator The keys or joystick/mouse inputs which will be mapped to the N64 controller for playing the games are determined by the input plugin. The emulator core also supports several key commands during emulation, which may be configured by editing the __*~/.config/mupen64plus/mupen64plus.cfg*__ file. They are: - **Escape (Esc)** Quit the emulator - **0-9** Select virtual 'slot' for save/load state (F5 and F7) commands - **F5** Save emulator state - **F7** Load emulator state - **F9** Reset emulator - **F10** Slow down emulator by 5% - **F11** Speed up emulator by 5% - **F12** Take screenshot - **Alt-Enter** Toggle between windowed and fullscreen (may not be supported by all video plugins) - **p or P** Pause on/off - **m or M** Mute/unmute sound - **g or G** Press "Game Shark" button (only if cheats are enabled) - **/ or ?** Single frame advance while paused - **F** Fast Forward (playback at 250% normal speed while F key is pressed) - **[** Decrease volume - **]** Increase volume mupen64plus-core-src-2.6.0/RELEASE000066400000000000000000003461571464506436200164710ustar00rootroot00000000000000Mupen64Plus-Core Emulator Library RELEASE ----------------------------------------- ----------------------------------------- # Mupen64Plus-core v2.6.0 - July 14, 2024 ## Merged PRs * [1086](https://github.com/mupen64plus/mupen64plus-core/pull/1086): Backport mupen64plus-libretro-nx dynarec fix for OoTMM randomizer * [1085](https://github.com/mupen64plus/mupen64plus-core/pull/1085): savestates: Only notify SAVECOMPLETE once save is actually done. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/1031 * [1084](https://github.com/mupen64plus/mupen64plus-core/pull/1084): Add support for new PIF ROM and reset PIF * [1082](https://github.com/mupen64plus/mupen64plus-core/pull/1082): Update "libmd5-rfc" code to the one used in CPython v2.7 repository * [1079](https://github.com/mupen64plus/mupen64plus-core/pull/1079): CI/CD: Rearranged some parts of the logic, many details and more... * [1077](https://github.com/mupen64plus/mupen64plus-core/pull/1077): CI/CD: Upgrade, generic scripts, independent schedule, etc * [1076](https://github.com/mupen64plus/mupen64plus-core/pull/1076): Correct ROM file size checks * [1075](https://github.com/mupen64plus/mupen64plus-core/pull/1075): ci: install vulkan-headers package in MSYS2 (Fixes CI build failure) * [1074](https://github.com/mupen64plus/mupen64plus-core/pull/1074): Update minizip * [1061](https://github.com/mupen64plus/mupen64plus-core/pull/1061): RSP opcode fixes. Ported from: https://gitlab.com/parallel-launcher/parallel-n64 * [1060](https://github.com/mupen64plus/mupen64plus-core/pull/1060): src: fix the new_dynarec with musl * [1059](https://github.com/mupen64plus/mupen64plus-core/pull/1059): Add missing ROM file size checks * [1058](https://github.com/mupen64plus/mupen64plus-core/pull/1058): Added 3 translations and a game. * [1057](https://github.com/mupen64plus/mupen64plus-core/pull/1057): Fix Big-Endian Incompatibilities. (Tested on a Wii U.) * [1056](https://github.com/mupen64plus/mupen64plus-core/pull/1056): Add redumps/correct bad ROM IDs and add some unlicensed releases. Based on the latest (2024/5/1) version of the No-Intro database. * [1054](https://github.com/mupen64plus/mupen64plus-core/pull/1054): Increase maximum allowed overclocking factor to 20 * [1046](https://github.com/mupen64plus/mupen64plus-core/pull/1046): Added Italian translations. * [1040](https://github.com/mupen64plus/mupen64plus-core/pull/1040): Fix incorrect OSAL_DIR_SEPARATORS when compiling using mingw. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/937 * [1039](https://github.com/mupen64plus/mupen64plus-core/pull/1039): bfd version check fix for X.XX version number format * [1036](https://github.com/mupen64plus/mupen64plus-core/pull/1036): use CS4 for netplay DSCP * [1034](https://github.com/mupen64plus/mupen64plus-core/pull/1034): Added English translation of Bomberman 64 - Arcade Edition * [1033](https://github.com/mupen64plus/mupen64plus-core/pull/1033): use memchr instead of strchr in is_viewer.c * [1032](https://github.com/mupen64plus/mupen64plus-core/pull/1032): Adding 4 more translations and updating ROM database. * [1030](https://github.com/mupen64plus/mupen64plus-core/pull/1030): rom: Fix closing the ROM database * [1029](https://github.com/mupen64plus/mupen64plus-core/pull/1029): Update README* files * [1027](https://github.com/mupen64plus/mupen64plus-core/pull/1027): new_dynarec: fix FPU crashes. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/1026 * [1023](https://github.com/mupen64plus/mupen64plus-core/pull/1023): Added 3 more translations * [1022](https://github.com/mupen64plus/mupen64plus-core/pull/1022): Add Video Extension functions to support Vulkan * [1021](https://github.com/mupen64plus/mupen64plus-core/pull/1021): netplay fixes from simple64 * [1020](https://github.com/mupen64plus/mupen64plus-core/pull/1020): Updating rom database * [1019](https://github.com/mupen64plus/mupen64plus-core/pull/1019): Fix IS64 Truncating Lines * [1018](https://github.com/mupen64plus/mupen64plus-core/pull/1018): Added French translation of Conker's Bad Fur Day * [1017](https://github.com/mupen64plus/mupen64plus-core/pull/1017): Update xxhash to 0.8.2 * [1015](https://github.com/mupen64plus/mupen64plus-core/pull/1015): Fix building with libbfd >=2.39 * [1014](https://github.com/mupen64plus/mupen64plus-core/pull/1014): Add M64CORE_SCREENSHOT_CAPTURED to m64p_core_param. (Allows front-ends to know when a screenshot has been captured.) * [1012](https://github.com/mupen64plus/mupen64plus-core/pull/1012): Change IPL3 memory detection error to a warning * [1011](https://github.com/mupen64plus/mupen64plus-core/pull/1011): Add Xeno Crisis to the ROM database * [1009](https://github.com/mupen64plus/mupen64plus-core/pull/1009): Ensure out of bounds RDRAM reads 0 * [1008](https://github.com/mupen64plus/mupen64plus-core/pull/1008): Add some Spanish translations. * [1006](https://github.com/mupen64plus/mupen64plus-core/pull/1006): Implement unused RDRAM address range 0x0800000-0x03EFFFFF. (Fixes an in-game crash in Paper Mario when hitting a specific tree with a hammer.) * [1005](https://github.com/mupen64plus/mupen64plus-core/pull/1005): CI/CD: Fixes Ubuntu i386 builds, among other changes * [1002](https://github.com/mupen64plus/mupen64plus-core/pull/1002): vidext.c: Fix DPI scaling issues on Windows * [1001](https://github.com/mupen64plus/mupen64plus-core/pull/1001): Interpreter accuracy improvements * [998](https://github.com/mupen64plus/mupen64plus-core/pull/998): Introduce SaveFilenameFormat parameter * [995](https://github.com/mupen64plus/mupen64plus-core/pull/995): CI/CD: Integrate scheduled builds and other... * [994](https://github.com/mupen64plus/mupen64plus-core/pull/994): [64DD] Shorten extra cycles timing depending on motor state for stability * [993](https://github.com/mupen64plus/mupen64plus-core/pull/993): Sanitize save filename * [992](https://github.com/mupen64plus/mupen64plus-core/pull/992): Fix screenshots when compiling with OSD=0 * [990](https://github.com/mupen64plus/mupen64plus-core/pull/990): Improve 64DD emulation * [989](https://github.com/mupen64plus/mupen64plus-core/pull/989): Update that helps diagnose and in some cases circumvent issues... * [986](https://github.com/mupen64plus/mupen64plus-core/pull/986): Fix incorrect DDREGION being used for development disks * [983](https://github.com/mupen64plus/mupen64plus-core/pull/983): Introduce M64CMD_DISK_OPEN & M64CMD_DISK_CLOSE * [980](https://github.com/mupen64plus/mupen64plus-core/pull/980): Have netplay just use file extension for file syncing * [979](https://github.com/mupen64plus/mupen64plus-core/pull/979): use MD5 for save filename * [977](https://github.com/mupen64plus/mupen64plus-core/pull/977): Add support for Advanced Homebrew ROM Header save type * [976](https://github.com/mupen64plus/mupen64plus-core/pull/976): Add ROM version to m64p_rom_header * [974](https://github.com/mupen64plus/mupen64plus-core/pull/974): CI/CD: Update MSVC * [970](https://github.com/mupen64plus/mupen64plus-core/pull/970): Fix crash due to SDL_SetVideoMode in SDL 2 compatibility code. * [967](https://github.com/mupen64plus/mupen64plus-core/pull/967): Proper response when eeprom absent * [965](https://github.com/mupen64plus/mupen64plus-core/pull/965): Add Smash Remix 1.2.0 * [963](https://github.com/mupen64plus/mupen64plus-core/pull/963): Added GoldenEye X and Perfect Dark Plus to INI * [961](https://github.com/mupen64plus/mupen64plus-core/pull/961): CI/CD: Update * [960](https://github.com/mupen64plus/mupen64plus-core/pull/960): 3 LSBs of AI Length must be 0 * [958](https://github.com/mupen64plus/mupen64plus-core/pull/958): Initialize dd_rom_size to 0 if load_dd_disk fails to fix possible runtime errors during initialization * [954](https://github.com/mupen64plus/mupen64plus-core/pull/954): Add support for clang/mingw targets * [946](https://github.com/mupen64plus/mupen64plus-core/pull/946): Use a predictable seed when using netplay * [929](https://github.com/mupen64plus/mupen64plus-core/pull/929): CountPerOp=1 for Bottom of the 9th. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/927 * [926](https://github.com/mupen64plus/mupen64plus-core/pull/926): Add ROM entries for SM64 splitscreen hack * [925](https://github.com/mupen64plus/mupen64plus-core/pull/925): Entry for SmashRemix1.1.0 * [922](https://github.com/mupen64plus/mupen64plus-core/pull/922): Update xxhash to 0.8.1 * [920](https://github.com/mupen64plus/mupen64plus-core/pull/920): Allow frontends to know what DD ROM region they should use * [919](https://github.com/mupen64plus/mupen64plus-core/pull/919): Generate unique mempaks ID when formatting them * [912](https://github.com/mupen64plus/mupen64plus-core/pull/912): CI/CD: Implement GitHub Actions and public nightly builds * [911](https://github.com/mupen64plus/mupen64plus-core/pull/911): Add Donkey Kong 64 - Tag Anywhere V5 (U) * [910](https://github.com/mupen64plus/mupen64plus-core/pull/910): Native Apple Silicon (darwin-arm64) Support * [909](https://github.com/mupen64plus/mupen64plus-core/pull/909): Fix IS Viewer crash. Fixes a segfault in [The Missing Link](https://www.romhacking.net/hacks/5334/) when entering a door. * [901](https://github.com/mupen64plus/mupen64plus-core/pull/901): Add SmashRemix1.0.0/1.0.1 * [899](https://github.com/mupen64plus/mupen64plus-core/pull/899): Add NO_KEYBINDINGS for joy mappings * [898](https://github.com/mupen64plus/mupen64plus-core/pull/898): Add RISC-V Support * [893](https://github.com/mupen64plus/mupen64plus-core/pull/893): Add KEYBINDINGS=0 option to Makefile * [890](https://github.com/mupen64plus/mupen64plus-core/pull/890): Fix https://github.com/mupen64plus/mupen64plus-core/issues/889 * [887](https://github.com/mupen64plus/mupen64plus-core/pull/887): Fix https://github.com/mupen64plus/mupen64plus-core/issues/886 * [884](https://github.com/mupen64plus/mupen64plus-core/pull/884): Fix https://github.com/mupen64plus/mupen64plus-core/issues/883 * [881](https://github.com/mupen64plus/mupen64plus-core/pull/881): Fix for compiler warning * [880](https://github.com/mupen64plus/mupen64plus-core/pull/880): Fix 64DD Write Address Check Regression * [878](https://github.com/mupen64plus/mupen64plus-core/pull/878): Make 4K EEPROM default save type; support carts with no EEPROM * [876](https://github.com/mupen64plus/mupen64plus-core/pull/876): IS Viewer support. IS-Viewer 64 was a physical debugging tool (https://n64squid.com/homebrew/n64-sdk/development-hardware/). * [873](https://github.com/mupen64plus/mupen64plus-core/pull/873): VRU support and Hey You Pikachu audio fix * [872](https://github.com/mupen64plus/mupen64plus-core/pull/872): Fix address check for DD DMA Interrupt. Fixes the issue identified in https://github.com/mupen64plus/mupen64plus-core/pull/868#issuecomment-861760293 * [871](https://github.com/mupen64plus/mupen64plus-core/pull/871): Misc fixes * [869](https://github.com/mupen64plus/mupen64plus-core/pull/869): Update RSP alignment code as per CEN64 * [868](https://github.com/mupen64plus/mupen64plus-core/pull/868): Update PI DMA alignment as per CEN64 * [867](https://github.com/mupen64plus/mupen64plus-core/pull/867): Rearranged order of Core settings in the config file * [866](https://github.com/mupen64plus/mupen64plus-core/pull/866): invalidate alternate address on write. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/738 * [865](https://github.com/mupen64plus/mupen64plus-core/pull/865): Fix Pokemon Puzzle League saving * [863](https://github.com/mupen64plus/mupen64plus-core/pull/863): Get Xena (E) to boot * [860](https://github.com/mupen64plus/mupen64plus-core/pull/860): Support Unicode on Windows * [858](https://github.com/mupen64plus/mupen64plus-core/pull/858): Add SmashRemix0.9.7 * [854](https://github.com/mupen64plus/mupen64plus-core/pull/854): Revert "Prevents game freezing unrelated to dynarecs" * [853](https://github.com/mupen64plus/mupen64plus-core/pull/853): Prevents game freezing unrelated to dynarecs * [848](https://github.com/mupen64plus/mupen64plus-core/pull/848): Fix https://github.com/mupen64plus/mupen64plus-core/issues/842 * [847](https://github.com/mupen64plus/mupen64plus-core/pull/847): Netplay fixes from Android port * [843](https://github.com/mupen64plus/mupen64plus-core/pull/843): [new_dynarec] Trivial perf improvement on initial recompilation * [841](https://github.com/mupen64plus/mupen64plus-core/pull/841): Remove CountPerOp=1 for Dino Planet * [840](https://github.com/mupen64plus/mupen64plus-core/pull/840): Add Dinosaur Planet to ini * [836](https://github.com/mupen64plus/mupen64plus-core/pull/836): Fix some warnings about wrong pointer format "%p" needs a void* * [835](https://github.com/mupen64plus/mupen64plus-core/pull/835): Change mempak formatting * [834](https://github.com/mupen64plus/mupen64plus-core/pull/834): refactor lba_end computation to better convey intent * [832](https://github.com/mupen64plus/mupen64plus-core/pull/832): 64dd save rebased * [830](https://github.com/mupen64plus/mupen64plus-core/pull/830): Fix some unsigned/signed comparison warnings * [828](https://github.com/mupen64plus/mupen64plus-core/pull/828): Mention save slot keybindings in docs * [827](https://github.com/mupen64plus/mupen64plus-core/pull/827): Add prefix to m64p_rom_save_type members * [825](https://github.com/mupen64plus/mupen64plus-core/pull/825): Ai fixes * [820](https://github.com/mupen64plus/mupen64plus-core/pull/820): Add correct MD5 for SmashRemix0.9.5b to INI * [817](https://github.com/mupen64plus/mupen64plus-core/pull/817): Failing to explain the asm scripts in a better way... * [816](https://github.com/mupen64plus/mupen64plus-core/pull/816): [Disk] Make sure the wrong System Data is checked upon read of the System Area * [815](https://github.com/mupen64plus/mupen64plus-core/pull/815): Simplify and make the asm script more robust to 3rd party scripts * [814](https://github.com/mupen64plus/mupen64plus-core/pull/814): Add SmashRemix0.9.5b to INI * [811](https://github.com/mupen64plus/mupen64plus-core/pull/811): build: Allow out of tree builds. * [809](https://github.com/mupen64plus/mupen64plus-core/pull/809): docs: fix simple typo, unconditonal -> unconditional * [808](https://github.com/mupen64plus/mupen64plus-core/pull/808): Fix to MacOSX building * [803](https://github.com/mupen64plus/mupen64plus-core/pull/803): storage backend save method nows know about modified byte range * [801](https://github.com/mupen64plus/mupen64plus-core/pull/801): Fixes * [798](https://github.com/mupen64plus/mupen64plus-core/pull/798): Allow customizable save slot keybindings * [796](https://github.com/mupen64plus/mupen64plus-core/pull/796): Align memory for parallel-rdp * [794](https://github.com/mupen64plus/mupen64plus-core/pull/794): Clean up netplay linked list * [793](https://github.com/mupen64plus/mupen64plus-core/pull/793): Just stop frontend from enabling cheats during netplay * [791](https://github.com/mupen64plus/mupen64plus-core/pull/791): Allow front-ends to override user paths * [789](https://github.com/mupen64plus/mupen64plus-core/pull/789): Add count factor overclock * [788](https://github.com/mupen64plus/mupen64plus-core/pull/788): Add M64CMD_ROM_SET_SETTINGS * [785](https://github.com/mupen64plus/mupen64plus-core/pull/785): Tag outgoing UDP packets with EF DSCP * [784](https://github.com/mupen64plus/mupen64plus-core/pull/784): CountPerOp=1 for Smash * [782](https://github.com/mupen64plus/mupen64plus-core/pull/782): Update xxHash to 0.8.0 * [779](https://github.com/mupen64plus/mupen64plus-core/pull/779): Fix typo in M64CMD_NETPLAY_INIT docs * [775](https://github.com/mupen64plus/mupen64plus-core/pull/775): Improve compatibility on restrictive platforms and other minor changes * [771](https://github.com/mupen64plus/mupen64plus-core/pull/771): Makefile: add missing quotation mark. * [768](https://github.com/mupen64plus/mupen64plus-core/pull/768): CountPerOp=3 for Wave Race 64 - Shindou Edition * [766](https://github.com/mupen64plus/mupen64plus-core/pull/766): Allow to set custom platform toolset from commands * [764](https://github.com/mupen64plus/mupen64plus-core/pull/764): Get/Set Refresh Rate * [762](https://github.com/mupen64plus/mupen64plus-core/pull/762): [Disk] Major Disk Support Changes * [758](https://github.com/mupen64plus/mupen64plus-core/pull/758): Allow frontends to manage SDL's lifetime * [756](https://github.com/mupen64plus/mupen64plus-core/pull/756): NOT mempak checksum when pak is not present * [753](https://github.com/mupen64plus/mupen64plus-core/pull/753): Netplay * [752](https://github.com/mupen64plus/mupen64plus-core/pull/752): Mask DRAM address in PI DMA * [751](https://github.com/mupen64plus/mupen64plus-core/pull/751): Enable FBInfo for CPU-RDP rendering * [750](https://github.com/mupen64plus/mupen64plus-core/pull/750): Removed "not officially supported" for ARM * [748](https://github.com/mupen64plus/mupen64plus-core/pull/748): CountPerOp=1 for Top Gear Overdrive/Hyperbike * [747](https://github.com/mupen64plus/mupen64plus-core/pull/747): fix compilation on x86 * [746](https://github.com/mupen64plus/mupen64plus-core/pull/746): Fix hard reset crash * [745](https://github.com/mupen64plus/mupen64plus-core/pull/745): Implement trap instructions * [744](https://github.com/mupen64plus/mupen64plus-core/pull/744): CountPerOp=1 for Battle for Naboo * [743](https://github.com/mupen64plus/mupen64plus-core/pull/743): Rework flashram implementation * [741](https://github.com/mupen64plus/mupen64plus-core/pull/741): Fix path expansion when building with VisualStudio so directories with spaces will not cause the build to fail. * [740](https://github.com/mupen64plus/mupen64plus-core/pull/740): Use XXH3 hashing (v0.7.3) * [739](https://github.com/mupen64plus/mupen64plus-core/pull/739): IP0 and IP1 CAUSE bits are writeable * [737](https://github.com/mupen64plus/mupen64plus-core/pull/737): BattleTanx (U) games need CountPerOp=3 to boot * [736](https://github.com/mupen64plus/mupen64plus-core/pull/736): Fix multiple definition errors * [735](https://github.com/mupen64plus/mupen64plus-core/pull/735): PIF binary boot rom support * [734](https://github.com/mupen64plus/mupen64plus-core/pull/734): Support FBWrites with a size of 3 * [731](https://github.com/mupen64plus/mupen64plus-core/pull/731): Disable FTZ (flush to zero) mode for SSE when FS bit is set * [729](https://github.com/mupen64plus/mupen64plus-core/pull/729): Improve glue code generation * [727](https://github.com/mupen64plus/mupen64plus-core/pull/727): CountPerOp=1 for Elmo's Letter Adventure * [725](https://github.com/mupen64plus/mupen64plus-core/pull/725): Implement PIF write flags properly * [721](https://github.com/mupen64plus/mupen64plus-core/pull/721): Emulate RSP DMA FIFO queue * [718](https://github.com/mupen64plus/mupen64plus-core/pull/718): Adjust DD DMA timing * [717](https://github.com/mupen64plus/mupen64plus-core/pull/717): Don't check event count to test if event is pending * [716](https://github.com/mupen64plus/mupen64plus-core/pull/716): Change some DD logging to only happen in verbose mode * [714](https://github.com/mupen64plus/mupen64plus-core/pull/714): Use cheat code to allow Rat Attack to boot * [710](https://github.com/mupen64plus/mupen64plus-core/pull/710): Disable FBInfo support for dynarecs * [709](https://github.com/mupen64plus/mupen64plus-core/pull/709): Proper handling of divide by zero * [708](https://github.com/mupen64plus/mupen64plus-core/pull/708): Rework interrupt scheduling * [707](https://github.com/mupen64plus/mupen64plus-core/pull/707): Implement cart ROM writes as described by Jan Goldacker. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/609 * [706](https://github.com/mupen64plus/mupen64plus-core/pull/706): Enable transferpak write * [705](https://github.com/mupen64plus/mupen64plus-core/pull/705): Only align cart address in PI DMA. This PR fixes https://github.com/mupen64plus/mupen64plus-core/issues/600 * [702](https://github.com/mupen64plus/mupen64plus-core/pull/702): Remove next_vi. Should fix https://github.com/mupen64plus/mupen64plus-core/issues/554 * [699](https://github.com/mupen64plus/mupen64plus-core/pull/699): Revert "Don't call SDL_PumpEvents() in core" * [698](https://github.com/mupen64plus/mupen64plus-core/pull/698): Don't set DPC_STATUS_START/END_VALID bits * [697](https://github.com/mupen64plus/mupen64plus-core/pull/697): Update xxHash to 0.7.2 * [696](https://github.com/mupen64plus/mupen64plus-core/pull/696): if config parameter already exists, add help text if missing, before returning successfully * [694](https://github.com/mupen64plus/mupen64plus-core/pull/694): Let MSBuild do its job and implement a proper AppVeyor with artifact packaging * [692](https://github.com/mupen64plus/mupen64plus-core/pull/692): Fix VI interrupt not being called in certain cases * [687](https://github.com/mupen64plus/mupen64plus-core/pull/687): Database updates * [682](https://github.com/mupen64plus/mupen64plus-core/pull/682): MPAL's refresh rate is 60 Hz * [670](https://github.com/mupen64plus/mupen64plus-core/pull/670): Set VSync (SDL_GL_SetSwapInterval) after GL context is available. This fixes https://github.com/mupen64plus/mupen64plus-core/issues/663 * [666](https://github.com/mupen64plus/mupen64plus-core/pull/666): Add speed limiter toggle, reintroduce SDL_PumpEvents for non-android platforms * [632](https://github.com/mupen64plus/mupen64plus-core/pull/632): Add ppc64le support ## Closed Issues * [1031](https://github.com/mupen64plus/mupen64plus-core/issues/1031): M64CORE_STATE_SAVECOMPLETE callback happens too early with M64P_PARALLEL * [1081](https://github.com/mupen64plus/mupen64plus-core/issues/1081): Fix buffer overflow in RSP DMA - SECURITY CONCERN * [1065](https://github.com/mupen64plus/mupen64plus-core/issues/1065): [Proposal] Features for tool-assisted speedrunning * [622](https://github.com/mupen64plus/mupen64plus-core/issues/622): Kirby 64 texture stretching * [849](https://github.com/mupen64plus/mupen64plus-core/issues/849): Random Game Crash/Freeze in Ocarina of Time with Dynamic Recompiler * [551](https://github.com/mupen64plus/mupen64plus-core/issues/551): perfect dark flickers quite a bit. * [915](https://github.com/mupen64plus/mupen64plus-core/issues/915): South Park - Chef's Luv Shack Not working * [1049](https://github.com/mupen64plus/mupen64plus-core/issues/1049): Missing ROM file size validation * [1042](https://github.com/mupen64plus/mupen64plus-core/issues/1042): mupen64plus-core no longer builds on Apple Silicon * [1041](https://github.com/mupen64plus/mupen64plus-core/issues/1041): Help, unplayable stuttering * [937](https://github.com/mupen64plus/mupen64plus-core/issues/937): 64DD: Wrong path to save file [Windows] * [1037](https://github.com/mupen64plus/mupen64plus-core/issues/1037): Control Stick in Pokemon Snap not working * [1028](https://github.com/mupen64plus/mupen64plus-core/issues/1028): mupen64plus-core.svg missing in Readme.md * [1026](https://github.com/mupen64plus/mupen64plus-core/issues/1026): Crash (Segfault) on 32bit ARM & DynaRec enabled * [493](https://github.com/mupen64plus/mupen64plus-core/issues/493): FBInfo missing some data with dynarec * [1003](https://github.com/mupen64plus/mupen64plus-core/issues/1003): How To Correctly Install Mupen64Plus in Ubuntu * [1000](https://github.com/mupen64plus/mupen64plus-core/issues/1000): Mupen64Plus has own Screen Resolution on 1.15.0 * [999](https://github.com/mupen64plus/mupen64plus-core/issues/999): Error: dlopen('/usr/local/lib/libmupen64plus.so.2') failed: libminizip.so.1: cannot open shared object file: No such file or directory * [157](https://github.com/mupen64plus/mupen64plus-core/issues/157): Hey You, Pikachu! VRU Emulation Support * [646](https://github.com/mupen64plus/mupen64plus-core/issues/646): Pausing causes the emulator to lock up * [988](https://github.com/mupen64plus/mupen64plus-core/issues/988): asm_defines_nasm.h is not generated on Windows * [978](https://github.com/mupen64plus/mupen64plus-core/issues/978): With `AutoStateSlotIncrement = True` `CurrentStateSlot` is not updated * [875](https://github.com/mupen64plus/mupen64plus-core/issues/875): [Feature Request] Overclocking support * [823](https://github.com/mupen64plus/mupen64plus-core/issues/823): Various input-related bugs in Paper Mario * [971](https://github.com/mupen64plus/mupen64plus-core/issues/971): Crash from Core Error: SDL_SetVIdeoMode failure due to invalid 'pitch' * [975](https://github.com/mupen64plus/mupen64plus-core/issues/975): Coverity scan defects founds * [972](https://github.com/mupen64plus/mupen64plus-core/issues/972): Audio crackling problem with ParaLLEl-RDP * [969](https://github.com/mupen64plus/mupen64plus-core/issues/969): Crash with Core Error: SDL_SetVideoMode failed and multiple Core Warnings * [966](https://github.com/mupen64plus/mupen64plus-core/issues/966): Document Vidext_GL_GetDefaultFramebuffer * [956](https://github.com/mupen64plus/mupen64plus-core/issues/956): Add CMake project * [957](https://github.com/mupen64plus/mupen64plus-core/issues/957): "print_insn_i386 undeclared" when building with DEBUGGER=1 * [931](https://github.com/mupen64plus/mupen64plus-core/issues/931): Fix FBInfo implementation (for Jet Force Gemini) * [948](https://github.com/mupen64plus/mupen64plus-core/issues/948): Per-Rom configuration C# interop broken * [945](https://github.com/mupen64plus/mupen64plus-core/issues/945): Diddy Kong Racing freezes at 2nd Wizpig race cut scene * [877](https://github.com/mupen64plus/mupen64plus-core/issues/877): Travis CI not working * [159](https://github.com/mupen64plus/mupen64plus-core/issues/159): Mario Story (JPN) freeze * [933](https://github.com/mupen64plus/mupen64plus-core/issues/933): Buck Bumble hangs on the ending cutscene of Mission 3 * [927](https://github.com/mupen64plus/mupen64plus-core/issues/927): Bottom of the 9th sluggish when loading match * [928](https://github.com/mupen64plus/mupen64plus-core/issues/928): Bottom of the 9th - some images are Blue tinted * [885](https://github.com/mupen64plus/mupen64plus-core/issues/885): Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Por1.5BetaFinal] can crash with new dynarec * [917](https://github.com/mupen64plus/mupen64plus-core/issues/917): San Francisco Rush - No Sound * [822](https://github.com/mupen64plus/mupen64plus-core/issues/822): Illegal instruction (core dumped) * [245](https://github.com/mupen64plus/mupen64plus-core/issues/245): Mario Kart 64 item not usable bug * [761](https://github.com/mupen64plus/mupen64plus-core/issues/761): [Audio Sync] Super Smash Bros. (Europe) Intro speed issues * [861](https://github.com/mupen64plus/mupen64plus-core/issues/861): New Release * [902](https://github.com/mupen64plus/mupen64plus-core/issues/902): 2.5.9 Linux 64 binary bundle - Illegal instruction * [900](https://github.com/mupen64plus/mupen64plus-core/issues/900): [BUG] Zelda OOT, EnableFBEmulation = true * [897](https://github.com/mupen64plus/mupen64plus-core/issues/897): CPU type "riscv64" not supported. * [657](https://github.com/mupen64plus/mupen64plus-core/issues/657): Issue with the mupen64plus dynarec in Indiana Jones and the Infernal Machine * [894](https://github.com/mupen64plus/mupen64plus-core/issues/894): unzip.h not found * [889](https://github.com/mupen64plus/mupen64plus-core/issues/889): Dinosaur Planet crashes with new dynarec * [888](https://github.com/mupen64plus/mupen64plus-core/issues/888): MINGW32 -> x86 compilation * [886](https://github.com/mupen64plus/mupen64plus-core/issues/886): Road rush 64 black screen on new game with new dynarec * [441](https://github.com/mupen64plus/mupen64plus-core/issues/441): Banjo-Tooie freeze * [883](https://github.com/mupen64plus/mupen64plus-core/issues/883): NBA Jam '99/2000 crash on startup with dynarec (aarch64) * [610](https://github.com/mupen64plus/mupen64plus-core/issues/610): Jet force gimini (U) locks up * [372](https://github.com/mupen64plus/mupen64plus-core/issues/372): Top Gear Rally freezing frames * [704](https://github.com/mupen64plus/mupen64plus-core/issues/704): Random crashes when loading save states * [520](https://github.com/mupen64plus/mupen64plus-core/issues/520): Still some crashes, probably when loading save states * [600](https://github.com/mupen64plus/mupen64plus-core/issues/600): Command and conquer in-game save corruption * [171](https://github.com/mupen64plus/mupen64plus-core/issues/171): Glover crash * [174](https://github.com/mupen64plus/mupen64plus-core/issues/174): Audio cuts off in Army Men: Sarge's Heroes with new dynarec * [433](https://github.com/mupen64plus/mupen64plus-core/issues/433): MRC - Multi Racing Championship missing ground with new dynarec * [631](https://github.com/mupen64plus/mupen64plus-core/issues/631): arm dynarec crash with stop_after_jal=0 * [806](https://github.com/mupen64plus/mupen64plus-core/issues/806): World Driving Championship doesn't boot with new dynarec * [856](https://github.com/mupen64plus/mupen64plus-core/issues/856): Forcing ROM-side High VSync Mode Gets Ignored By ALL Mupen Forks * [679](https://github.com/mupen64plus/mupen64plus-core/issues/679): Cannot exit fullscreen with ALT+ENTER when launched with Glide64mk2 video plugin * [608](https://github.com/mupen64plus/mupen64plus-core/issues/608): Minizip header build failure * [633](https://github.com/mupen64plus/mupen64plus-core/issues/633): Display Issues when ResY > 1000 * [639](https://github.com/mupen64plus/mupen64plus-core/issues/639): Crash on hard reset using Pure Interpreter/Dynarec * [712](https://github.com/mupen64plus/mupen64plus-core/issues/712): fails to build with -fno-common or gcc-10 * [755](https://github.com/mupen64plus/mupen64plus-core/issues/755): Black bar in many games when framebuffer emulation is ticked * [821](https://github.com/mupen64plus/mupen64plus-core/issues/821): [mupen64plus:15] Failed to load library file * [845](https://github.com/mupen64plus/mupen64plus-core/issues/845): video-glide64mk2 won't start game * [594](https://github.com/mupen64plus/mupen64plus-core/issues/594): Compiling for ARM? * [517](https://github.com/mupen64plus/mupen64plus-core/issues/517): Unable to build on Raspberry Pi 3 / Raspbian - error: ‘EAX’ undeclared * [408](https://github.com/mupen64plus/mupen64plus-core/issues/408): Cant use emulation? * [378](https://github.com/mupen64plus/mupen64plus-core/issues/378): Can't compile on Linux ARM (64 bit kernel, 32 bit user land) * [292](https://github.com/mupen64plus/mupen64plus-core/issues/292): Mupen64plus.cfg changes being overwritten automatically after game launch. * [252](https://github.com/mupen64plus/mupen64plus-core/issues/252): Compile fails on src Linux Armv7l * [224](https://github.com/mupen64plus/mupen64plus-core/issues/224): Compilation not producing executable * [305](https://github.com/mupen64plus/mupen64plus-core/issues/305): Worms Armageddon new dynarec crash * [286](https://github.com/mupen64plus/mupen64plus-core/issues/286): FIFA 99: Players are floating (x64 Dynarec) * [738](https://github.com/mupen64plus/mupen64plus-core/issues/738): libdragon games only work with Pure Interpreter * [870](https://github.com/mupen64plus/mupen64plus-core/issues/870): Smash Remix 0.9.7 locked at 30fps on Retroarch Mupen64Plus-Next core * [864](https://github.com/mupen64plus/mupen64plus-core/issues/864): Core won't compile. * [862](https://github.com/mupen64plus/mupen64plus-core/issues/862): Error LNK1181 cannot open input file 'Win32\Release\dyna_start.obj' * [838](https://github.com/mupen64plus/mupen64plus-core/issues/838): Input doesn't work in Wolfenstein 3d N64 port * [850](https://github.com/mupen64plus/mupen64plus-core/issues/850): Mupen64Plus Core Configuring gamepad buggy * [842](https://github.com/mupen64plus/mupen64plus-core/issues/842): Dinosaur planet beta TLB exceptions in new dynarec * [846](https://github.com/mupen64plus/mupen64plus-core/issues/846): Virtual N64 controller Notches * [812](https://github.com/mupen64plus/mupen64plus-core/issues/812): Unknown "no name" ROMs passes as known without even checking the MD5/CRC * [640](https://github.com/mupen64plus/mupen64plus-core/issues/640): New dynarec crashing when opening 2nd ROM * [837](https://github.com/mupen64plus/mupen64plus-core/issues/837): Input * [673](https://github.com/mupen64plus/mupen64plus-core/issues/673): Uncached memory code execution support * [826](https://github.com/mupen64plus/mupen64plus-core/issues/826): PR #788 breaks build of mupen64plus-video-rice * [576](https://github.com/mupen64plus/mupen64plus-core/issues/576): banjo tooie tip-toe using keyboard (move banjo analog 5% to 10% range) * [786](https://github.com/mupen64plus/mupen64plus-core/issues/786): Undefined behaviour in rsp-hle * [813](https://github.com/mupen64plus/mupen64plus-core/issues/813): Video displays at the lower left corner, no full screen * [797](https://github.com/mupen64plus/mupen64plus-core/issues/797): Unable to start Mupen64Plus on Slackware Linux (2.5.0) * [800](https://github.com/mupen64plus/mupen64plus-core/issues/800): m64p_rom_header struct outdated? * [787](https://github.com/mupen64plus/mupen64plus-core/issues/787): Rat Attack Not Booting * [790](https://github.com/mupen64plus/mupen64plus-core/issues/790): Nuclear Escape button * [350](https://github.com/mupen64plus/mupen64plus-core/issues/350): RSP DMA double buffering not implemented * [732](https://github.com/mupen64plus/mupen64plus-core/issues/732): Donkey Kong 64 (U) [f2] does not boot * [730](https://github.com/mupen64plus/mupen64plus-core/issues/730): Binary PIF ROM support * [777](https://github.com/mupen64plus/mupen64plus-core/issues/777): Is there any way to add Gameshark Codes? * [780](https://github.com/mupen64plus/mupen64plus-core/issues/780): Illegal instruction (core dumped) * [778](https://github.com/mupen64plus/mupen64plus-core/issues/778): Every time I open mupen64plus-ui-console it crashes very quickly. * [776](https://github.com/mupen64plus/mupen64plus-core/issues/776): mupen64plus-gui DK64 - Severe Slowdown * [773](https://github.com/mupen64plus/mupen64plus-core/issues/773): Account creation on the wiki (or just answer to my question... 😅) * [763](https://github.com/mupen64plus/mupen64plus-core/issues/763): Dynamically switch output resolution to that of console * [760](https://github.com/mupen64plus/mupen64plus-core/issues/760): Fails to build under MSYS Windows 2004 * [686](https://github.com/mupen64plus/mupen64plus-core/issues/686): New dynarec and F-Zero X Expansion Kit hacked rom * [599](https://github.com/mupen64plus/mupen64plus-core/issues/599): N64 database errors? * [722](https://github.com/mupen64plus/mupen64plus-core/issues/722): AppVeyor is broken * [719](https://github.com/mupen64plus/mupen64plus-core/issues/719): Incorrect Folder Name In Source Code * [703](https://github.com/mupen64plus/mupen64plus-core/issues/703): Can't build core * [676](https://github.com/mupen64plus/mupen64plus-core/issues/676): CheckInterrupts is not implemented for Audio/Gfx/RSP plugins * [674](https://github.com/mupen64plus/mupen64plus-core/issues/674): Mupen32.exe, more like * [650](https://github.com/mupen64plus/mupen64plus-core/issues/650): Kaillera integration/support * [689](https://github.com/mupen64plus/mupen64plus-core/issues/689): Aero Fighters Assault - Startup Error * [749](https://github.com/mupen64plus/mupen64plus-core/issues/749): Missing "mupen64plus.dll" when compiling on windows * [570](https://github.com/mupen64plus/mupen64plus-core/issues/570): Battle of Naboo: wrong gfx in level selection (core bug) * [742](https://github.com/mupen64plus/mupen64plus-core/issues/742): Super Mario 64 not responding * [720](https://github.com/mupen64plus/mupen64plus-core/issues/720): Mupen64Plus Compiled With Visual Studio Solution File Has No Sound * [609](https://github.com/mupen64plus/mupen64plus-core/issues/609): WCW Backstage Assault locks up * [669](https://github.com/mupen64plus/mupen64plus-core/issues/669): Test ROM hangs emulator * [636](https://github.com/mupen64plus/mupen64plus-core/issues/636): Elmo's Letter Adventure - keys are not responsive * [723](https://github.com/mupen64plus/mupen64plus-core/issues/723): Audio stops in Army Men Sarges Heroes * [660](https://github.com/mupen64plus/mupen64plus-core/issues/660): Custom roms won't boot * [711](https://github.com/mupen64plus/mupen64plus-core/issues/711): Memory leak when playing Indiana Jones (musyx_v1/v2_task) * [713](https://github.com/mupen64plus/mupen64plus-core/issues/713): Adding webhook to Discord64 * [554](https://github.com/mupen64plus/mupen64plus-core/issues/554): VI_CURRENT_REG not calculated properly if CP0_COUNT_REG changed by software * [634](https://github.com/mupen64plus/mupen64plus-core/issues/634): screenshots can't be saved correctly when ROM had an invalid header. * [546](https://github.com/mupen64plus/mupen64plus-core/issues/546): Pokemon Puzzle League FMV not dealt with by RSP-HLE * [563](https://github.com/mupen64plus/mupen64plus-core/issues/563): Compiling for AARCH64/ARM64? * [663](https://github.com/mupen64plus/mupen64plus-core/issues/663): VidExt_GL_SetAttribute sets SDL_GL_SetSwapInterval prematurely * [675](https://github.com/mupen64plus/mupen64plus-core/issues/675): any way to take advantage of GLES 3.0 ES on rpi4? * [656](https://github.com/mupen64plus/mupen64plus-core/issues/656): Failed to create GL context on RPI3 under mesa with GLideN64 * [678](https://github.com/mupen64plus/mupen64plus-core/issues/678): segfault while loading World Driver Championship * [661](https://github.com/mupen64plus/mupen64plus-core/issues/661): Does Mupen64 work with Windows 10 64-Bit? Or Does 64-Bit Windows not work with the 32-Bit? * [658](https://github.com/mupen64plus/mupen64plus-core/issues/658): SetVideoMode returns NULL pointer to Screen * [265](https://github.com/mupen64plus/mupen64plus-core/issues/265): Banjo-Kazooie intro puzzle effect not displaying correctly with Rice * [655](https://github.com/mupen64plus/mupen64plus-core/issues/655): [Glide64] Compilation error on char signedness * [653](https://github.com/mupen64plus/mupen64plus-core/issues/653): Opening game crashes on Mac * [648](https://github.com/mupen64plus/mupen64plus-core/issues/648): How compile "mupen64plus-video-z64" on debian 9 * [645](https://github.com/mupen64plus/mupen64plus-core/issues/645): Retrolinc Controller not found - Arch Linux mupen64plus * [637](https://github.com/mupen64plus/mupen64plus-core/issues/637): LoS: Majoras Mask unable to move marker to items in inventory. * [638](https://github.com/mupen64plus/mupen64plus-core/issues/638): Command Line Ends Process After Starting And Request A More Detailed Install Readme File * [628](https://github.com/mupen64plus/mupen64plus-core/issues/628): 2.5.9: Print of size_t has to use z modifier * [630](https://github.com/mupen64plus/mupen64plus-core/issues/630): 2.5.9: Missing INPUT_API_VERSION change (2.5 Input plugin not working with 2.5.9 core) ## Top Contributors (2 or more commits) 1. Rosalie241 2. loganmc10 3. LuigiBlood 4. bsmiles32 5. Gillou68310 6. Jj0YzL5nvJ 7. richard42 8. Pcgaming575 9. meeq 10. GhostlyDark 11. mpharoah 12. Clownacy 13. obrea 14. m4xw 15. alice-mkh 16. flagrama 17. dankcushions --------------------------------------------- # Mupen64Plus-core v2.5.9 - February 10, 2019 ## Merged PRs * [619](https://github.com/mupen64plus/mupen64plus-core/pull/619): do not force saving config when file not present (Front-ends now ensure that configuration is saved (when desired) before starting the game.) * [618](https://github.com/mupen64plus/mupen64plus-core/pull/618): __clear_cache fix for ARM 64 devices plus ANDROID cleanup * [615](https://github.com/mupen64plus/mupen64plus-core/pull/615): Fixes for last save state update * [614](https://github.com/mupen64plus/mupen64plus-core/pull/614): Make stop_after_jal a save state parameter instead of configuration. * [612](https://github.com/mupen64plus/mupen64plus-core/pull/612): Allow valid interpretations of strings as non-strings * [611](https://github.com/mupen64plus/mupen64plus-core/pull/611): Remove DelaySI from wiki (This parameter was removed from the core in 0bcfd3cc7.) * [607](https://github.com/mupen64plus/mupen64plus-core/pull/607): Fix joy_max for initialize loop * [606](https://github.com/mupen64plus/mupen64plus-core/pull/606): new_dynarec fixes * [605](https://github.com/mupen64plus/mupen64plus-core/pull/605): Preserve floating-point configuration values. * [604](https://github.com/mupen64plus/mupen64plus-core/pull/604): Fix mingw build * [602](https://github.com/mupen64plus/mupen64plus-core/pull/602): new_dynarec: Initial support for x64 and arm64 * [598](https://github.com/mupen64plus/mupen64plus-core/pull/598): Fix errors introduced in #444 (These changes allow Rugrats and Xena to boot.) * [597](https://github.com/mupen64plus/mupen64plus-core/pull/597): Avoid nameless union in r4300_core.h (this is a non standard extension) * [596](https://github.com/mupen64plus/mupen64plus-core/pull/596): Fix access to DD_ROM memory pointer. * [593](https://github.com/mupen64plus/mupen64plus-core/pull/593): Two new debugger APIs: 'DebugBreakpointTriggeredBy' and 'DebugVirtualToPhysical' * [590](https://github.com/mupen64plus/mupen64plus-core/pull/590): Fix missing header in biopak.c * [589](https://github.com/mupen64plus/mupen64plus-core/pull/589): Cleanings * [588](https://github.com/mupen64plus/mupen64plus-core/pull/588): added support for aarch64 * [585](https://github.com/mupen64plus/mupen64plus-core/pull/585): Cleanings * [583](https://github.com/mupen64plus/mupen64plus-core/pull/583): Update nasm path to use latest stable release 2.13.03 * [582](https://github.com/mupen64plus/mupen64plus-core/pull/582): Move third-party code into subprojects directory. * [581](https://github.com/mupen64plus/mupen64plus-core/pull/581): Bugfixes (Various compilation fixes found while working on meson porting.) * [579](https://github.com/mupen64plus/mupen64plus-core/pull/579): Make --nosaveoptions not ever save options. * [578](https://github.com/mupen64plus/mupen64plus-core/pull/578): Update readme * [573](https://github.com/mupen64plus/mupen64plus-core/pull/573): Rework Video Capture backend to allow better isolation. * [569](https://github.com/mupen64plus/mupen64plus-core/pull/569): Cleanup tpak savestate loading. * [566](https://github.com/mupen64plus/mupen64plus-core/pull/566): Initial bio pak support. * [565](https://github.com/mupen64plus/mupen64plus-core/pull/565): Fix homepage link in dd_controller files. * [564](https://github.com/mupen64plus/mupen64plus-core/pull/564): GB Camera support * [561](https://github.com/mupen64plus/mupen64plus-core/pull/561): Update xxHash to 0.6.5 * [557](https://github.com/mupen64plus/mupen64plus-core/pull/557): Increase DebugMessage buffer size to prevent overflows * [556](https://github.com/mupen64plus/mupen64plus-core/pull/556): Add VidExt_GL_GetDefaultFramebuffer * [553](https://github.com/mupen64plus/mupen64plus-core/pull/553): Fix write_memory_8 (This was overflowing a u8, causing zeroes to be written most of the time instead of the intended value.) * [550](https://github.com/mupen64plus/mupen64plus-core/pull/550): Don't call SDL_PumpEvents() in core * [549](https://github.com/mupen64plus/mupen64plus-core/pull/549): Clear CLOCK_REG when requested * [548](https://github.com/mupen64plus/mupen64plus-core/pull/548): Added missing Joy Mappings (Added the 4 missing Joystick counterparts of the Keyboard Mappings: Reset, Speed Down, Speed Up, Frame Advance) * [547](https://github.com/mupen64plus/mupen64plus-core/pull/547): R4300 refactorings * [545](https://github.com/mupen64plus/mupen64plus-core/pull/545): Fix: try to keep savestates offsets aligned. * [544](https://github.com/mupen64plus/mupen64plus-core/pull/544): Fix DSLLV in x86 dynarec * [541](https://github.com/mupen64plus/mupen64plus-core/pull/541): Force alignment of PI DMA * [538](https://github.com/mupen64plus/mupen64plus-core/pull/538): Alternative implementation of "Don't deal with save states when RSP task is locked" * [537](https://github.com/mupen64plus/mupen64plus-core/pull/537): new_dynarec: Fix DMULT/DMULTU recompiled code * [535](https://github.com/mupen64plus/mupen64plus-core/pull/535): Allow game controllers to be unplugged and plugged in on the fly * [533](https://github.com/mupen64plus/mupen64plus-core/pull/533): Remove CountPerOp=1 for Vigilante games * [532](https://github.com/mupen64plus/mupen64plus-core/pull/532): If a ROM is not in the database, use 4 players, enable mempak, and enable rumble pak * [529](https://github.com/mupen64plus/mupen64plus-core/pull/529): Fix compile on MinGW * [526](https://github.com/mupen64plus/mupen64plus-core/pull/526): Fix undefined reference to print_insn_i386 with libopcode >= 2.29 * [521](https://github.com/mupen64plus/mupen64plus-core/pull/521): Fix empty dynarec * [519](https://github.com/mupen64plus/mupen64plus-core/pull/519): Less g dev (Reduce usage of global variable g_dev (and other derived variables) in emulation modules.) * [515](https://github.com/mupen64plus/mupen64plus-core/pull/515): Fix compilation of new dynarec. * [514](https://github.com/mupen64plus/mupen64plus-core/pull/514): Fix potential crash with FBInfo and save states * [513](https://github.com/mupen64plus/mupen64plus-core/pull/513): Add SiDmaDuration option. * [510](https://github.com/mupen64plus/mupen64plus-core/pull/510): Cleanings (This is just some more internal source cleanings such as reindentation, forward declaration, header inclusion or just moving some code around.) * [507](https://github.com/mupen64plus/mupen64plus-core/pull/507): Update homepage links * [505](https://github.com/mupen64plus/mupen64plus-core/pull/505): Update xxHash to 0.6.4 * [503](https://github.com/mupen64plus/mupen64plus-core/pull/503): Device: RDRAM: Use the R4300 helpers to get the R4300 registers * [502](https://github.com/mupen64plus/mupen64plus-core/pull/502): Bugfixes (Some small bugfixes found while looking around.) * [501](https://github.com/mupen64plus/mupen64plus-core/pull/501): Implement enough of RDRAM subsystem to remove rdram detection hack. * [500](https://github.com/mupen64plus/mupen64plus-core/pull/500): Fix reset bug introduced in commit 1c01c233. * [499](https://github.com/mupen64plus/mupen64plus-core/pull/499): Fix copy pasting error in MBC2 messages. * [498](https://github.com/mupen64plus/mupen64plus-core/pull/498): Fix crash when loading save state * [496](https://github.com/mupen64plus/mupen64plus-core/pull/496): Various GB cart enhancements. * [495](https://github.com/mupen64plus/mupen64plus-core/pull/495): Create files_macos.c (First try to get a proper Mupen64Plus app on macOS) * [494](https://github.com/mupen64plus/mupen64plus-core/pull/494): Update Makefile (First try to get it fixed for macOS) * [492](https://github.com/mupen64plus/mupen64plus-core/pull/492): If DEBUG not set, set NDEBUG * [491](https://github.com/mupen64plus/mupen64plus-core/pull/491): Remove orphaned line related to removed GoldenEye TLB hack (Needed to resolve build error on Raspberry Pi 3). * [490](https://github.com/mupen64plus/mupen64plus-core/pull/490): Warnings (With this PR all warnings except those about unused parameters should be gone. This is tested on GCC with -Wall -Wextra -pedantic.) * [487](https://github.com/mupen64plus/mupen64plus-core/pull/487): Remove GoldenEye TLB hack. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/447 * [485](https://github.com/mupen64plus/mupen64plus-core/pull/485): Modify DPC_STATUS_FREEZE hack * [483](https://github.com/mupen64plus/mupen64plus-core/pull/483): Extract PIF, RCP and RDRAM modules (Just moving some files around to isolate PIF and RCP modules.) * [481](https://github.com/mupen64plus/mupen64plus-core/pull/481): Add more FB writes and reads * [480](https://github.com/mupen64plus/mupen64plus-core/pull/480): Fix 40 winks ini * [478](https://github.com/mupen64plus/mupen64plus-core/pull/478): Fix FbInfo 2 * [476](https://github.com/mupen64plus/mupen64plus-core/pull/476): Preliminary refactorings (This PR is just a collection of preliminary refactoring commits extracted from PR #446. They are not directly related to 64DD so we can incorporate them hopefully sooner.) * [475](https://github.com/mupen64plus/mupen64plus-core/pull/475): Fix handlers[i].{read,write}32 comparison in dynarec. * [474](https://github.com/mupen64plus/mupen64plus-core/pull/474): Big alloc fallback (Another try at the memory allocation failure encountered in some Android devices.) * [473](https://github.com/mupen64plus/mupen64plus-core/pull/473): CountPerOp=1 for Bokujou Monogatari 2 * [472](https://github.com/mupen64plus/mupen64plus-core/pull/472): If an invalid controller pak is selected, use NONE instead * [471](https://github.com/mupen64plus/mupen64plus-core/pull/471): Fix LWL, LWR, LDL, LDR, SWL, SWR, SDL, SDR implementations * [470](https://github.com/mupen64plus/mupen64plus-core/pull/470): Build MXE targets as additional tests in travis build matrix * [466](https://github.com/mupen64plus/mupen64plus-core/pull/466): CountPerOp=1 for Densha de Go! 64 * [465](https://github.com/mupen64plus/mupen64plus-core/pull/465): new_dynarec: Fix Dance Dance revolution * [464](https://github.com/mupen64plus/mupen64plus-core/pull/464): Increase Delay DP Interrupt time * [461](https://github.com/mupen64plus/mupen64plus-core/pull/461): Get rid of USE_SDL flag * [460](https://github.com/mupen64plus/mupen64plus-core/pull/460): Add support for different flashram types. * [459](https://github.com/mupen64plus/mupen64plus-core/pull/459): Fix reset * [457](https://github.com/mupen64plus/mupen64plus-core/pull/457): Add support for SRAM cpu read/write * [455](https://github.com/mupen64plus/mupen64plus-core/pull/455): Complete (U) save types + Add four games * [454](https://github.com/mupen64plus/mupen64plus-core/pull/454): CountPerOp=1 for Gauntlet Legends (Allows for better performance when using GLideN64.) * [453](https://github.com/mupen64plus/mupen64plus-core/pull/453): Do SI DMA in 2 stages. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/452 * [451](https://github.com/mupen64plus/mupen64plus-core/pull/451): Enable CountPerOp=1 for Battletanx 2 & Army Men * [450](https://github.com/mupen64plus/mupen64plus-core/pull/450): Fix issues listed in #385 * [449](https://github.com/mupen64plus/mupen64plus-core/pull/449): Allow switching controller paks using CONTROLS.plugin API * [448](https://github.com/mupen64plus/mupen64plus-core/pull/448): Fix some Save Type entries * [446](https://github.com/mupen64plus/mupen64plus-core/pull/446): [WIP] Add support for 64 Disk Drive. * [444](https://github.com/mupen64plus/mupen64plus-core/pull/444): Re-work the way VI interrupts are timed * [443](https://github.com/mupen64plus/mupen64plus-core/pull/443): Remove CountPerOp=1 for Ep I Racer * [440](https://github.com/mupen64plus/mupen64plus-core/pull/440): Mempak/Rumble fixes * [439](https://github.com/mupen64plus/mupen64plus-core/pull/439): Fix crash when loading savestate. * [437](https://github.com/mupen64plus/mupen64plus-core/pull/437): ROM database update * [436](https://github.com/mupen64plus/mupen64plus-core/pull/436): PI refactorings * [430](https://github.com/mupen64plus/mupen64plus-core/pull/430): Fix a few indentation warnings * [428](https://github.com/mupen64plus/mupen64plus-core/pull/428): Raspberry Pi: use new vendor library names * [427](https://github.com/mupen64plus/mupen64plus-core/pull/427): Do a proper open bus read. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/418 * [425](https://github.com/mupen64plus/mupen64plus-core/pull/425): Add note about SP_STATUS_REG * [424](https://github.com/mupen64plus/mupen64plus-core/pull/424): SDL_Delay is only called just before input polling. * [423](https://github.com/mupen64plus/mupen64plus-core/pull/423): Add SP_STATUS_REG and RDRAM_SIZE to gfx_info * [422](https://github.com/mupen64plus/mupen64plus-core/pull/422): Stubbing some 64dd conversion roms into database. * [421](https://github.com/mupen64plus/mupen64plus-core/pull/421): CIC and Densha de Go Translation Patch * [420](https://github.com/mupen64plus/mupen64plus-core/pull/420): Don't use IO_BUSY flags for DMA * [417](https://github.com/mupen64plus/mupen64plus-core/pull/417): Fix rounding in interpreter * [415](https://github.com/mupen64plus/mupen64plus-core/pull/415): Randomize PI/SI interrupt timing * [411](https://github.com/mupen64plus/mupen64plus-core/pull/411): More si refactorings * [410](https://github.com/mupen64plus/mupen64plus-core/pull/410): Fix slowdowns in Mischief Makers * [407](https://github.com/mupen64plus/mupen64plus-core/pull/407): Add AppVeyor config * [406](https://github.com/mupen64plus/mupen64plus-core/pull/406): Bump savestate format to 1.2 * [404](https://github.com/mupen64plus/mupen64plus-core/pull/404): Add entry for 007 - Goldfinger * [403](https://github.com/mupen64plus/mupen64plus-core/pull/403): Fix save size for Custom Robo V2. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/402 * [401](https://github.com/mupen64plus/mupen64plus-core/pull/401): Add travisCI and coverity badges * [399](https://github.com/mupen64plus/mupen64plus-core/pull/399): Fix screenshots for games with colon in the title. Fix for https://github.com/mupen64plus/mupen64plus-core/issues/398 * [394](https://github.com/mupen64plus/mupen64plus-core/pull/394): CountPerOp=1 for Yakouchuu II - Satsujin Kouro * [393](https://github.com/mupen64plus/mupen64plus-core/pull/393): Fix description of some core config variables * [390](https://github.com/mupen64plus/mupen64plus-core/pull/390): Fix set_fpr_pointers * [388](https://github.com/mupen64plus/mupen64plus-core/pull/388): Remove DelaySI hack/option * [387](https://github.com/mupen64plus/mupen64plus-core/pull/387): Remove Rat Attack hack for new_dynarec * [386](https://github.com/mupen64plus/mupen64plus-core/pull/386): Switch from adler32 to xxHash * [382](https://github.com/mupen64plus/mupen64plus-core/pull/382): Use faster container based Travis CI * [381](https://github.com/mupen64plus/mupen64plus-core/pull/381): Let travis handle the package installation directly * [375](https://github.com/mupen64plus/mupen64plus-core/pull/375): Fix duplicate saving in Paper Mario. This fixes https://github.com/mupen64plus/mupen64plus-core/issues/154 * [373](https://github.com/mupen64plus/mupen64plus-core/pull/373): Remove Rat Attack hack * [371](https://github.com/mupen64plus/mupen64plus-core/pull/371): Have emulator signal RSP interrupts again * [370](https://github.com/mupen64plus/mupen64plus-core/pull/370): Base count_per_scanline on N64 clockrate * [367](https://github.com/mupen64plus/mupen64plus-core/pull/367): Fixing some warnings * [365](https://github.com/mupen64plus/mupen64plus-core/pull/365): Fix order of operations for AI interrupt timing * [364](https://github.com/mupen64plus/mupen64plus-core/pull/364): Get x86 new dynarec compiling again (when using PIC) * [363](https://github.com/mupen64plus/mupen64plus-core/pull/363): Round PI_WR_LEN_REG up to nearest even number * [362](https://github.com/mupen64plus/mupen64plus-core/pull/362): Add setting for Mischief Makers J * [360](https://github.com/mupen64plus/mupen64plus-core/pull/360): Rewrite PIF emulation. * [358](https://github.com/mupen64plus/mupen64plus-core/pull/358): Fix RevA (U) Rogue Squadron * [356](https://github.com/mupen64plus/mupen64plus-core/pull/356): Get rid of "alternate VI timing" * [355](https://github.com/mupen64plus/mupen64plus-core/pull/355): Change tpak/gb debug message level to verbose. * [352](https://github.com/mupen64plus/mupen64plus-core/pull/352): CountPerOp=1 for Factor5 games * [351](https://github.com/mupen64plus/mupen64plus-core/pull/351): Add SI_STATUS_DMA_BUSY. This fixes the error: ``` Core Warning: two events of type 0x8 in interrupt queue ``` in some games. * [343](https://github.com/mupen64plus/mupen64plus-core/pull/343): Send audio data to plugin as the DMA drains * [339](https://github.com/mupen64plus/mupen64plus-core/pull/339): Use count_per_op instead of 2 * [336](https://github.com/mupen64plus/mupen64plus-core/pull/336): Ignore TLB write if TLB entry is unmapping itself. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/221 * [334](https://github.com/mupen64plus/mupen64plus-core/pull/334): Fix write_cart_rom/read_cart_rom. This fixes https://github.com/mupen64plus/mupen64plus-core/issues/311 (International Track & Field 2000 and Midway's Greatest Arcade Hits Vol. 1) * [333](https://github.com/mupen64plus/mupen64plus-core/pull/333): Multiplayer timing fix for Mario Kart E and J * [330](https://github.com/mupen64plus/mupen64plus-core/pull/330): Add hack for Rat Attack! * [329](https://github.com/mupen64plus/mupen64plus-core/pull/329): Print accelerator when GB cart supports it. * [327](https://github.com/mupen64plus/mupen64plus-core/pull/327): Implement "Audio Signal" * [326](https://github.com/mupen64plus/mupen64plus-core/pull/326): Updates to DisableExtraMem * [324](https://github.com/mupen64plus/mupen64plus-core/pull/324): Add CP0_ERROREPC_REG to MTC0. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/323 * [322](https://github.com/mupen64plus/mupen64plus-core/pull/322): Fix asm_defines w/ mawk by setting LANG=C * [320](https://github.com/mupen64plus/mupen64plus-core/pull/320): Revert "Allow using compiler other than gcc" * [318](https://github.com/mupen64plus/mupen64plus-core/pull/318): Fix random resets in South Park 64. https://github.com/mupen64plus/mupen64plus-core/issues/316 * [317](https://github.com/mupen64plus/mupen64plus-core/pull/317): Allow using compiler other than gcc * [313](https://github.com/mupen64plus/mupen64plus-core/pull/313): Memory refactorings * [312](https://github.com/mupen64plus/mupen64plus-core/pull/312): Remove memd * [310](https://github.com/mupen64plus/mupen64plus-core/pull/310): Fix reading CP0_RANDOM_REG. Fixes https://github.com/mupen64plus/mupen64plus-core/issues/309 * [308](https://github.com/mupen64plus/mupen64plus-core/pull/308): Add note for NBA Showtime - NBA on NBC * [307](https://github.com/mupen64plus/mupen64plus-core/pull/307): Trust plugins to trigger SP interrupts * [306](https://github.com/mupen64plus/mupen64plus-core/pull/306): INI cheat cleanup * [301](https://github.com/mupen64plus/mupen64plus-core/pull/301): Avoid usage of global variable g_delay_si. (One less global variable used inside the emulation core.) * [300](https://github.com/mupen64plus/mupen64plus-core/pull/300): CountPerScanline=1600 for Twisted Edge * [298](https://github.com/mupen64plus/mupen64plus-core/pull/298): Various Mac-related build fixes * [297](https://github.com/mupen64plus/mupen64plus-core/pull/297): Fix M64P_GL_SWAP_CONTROL with SDL>=1.3 and no video extension * [296](https://github.com/mupen64plus/mupen64plus-core/pull/296): Fix undefined behavior in the interpreter * [295](https://github.com/mupen64plus/mupen64plus-core/pull/295): [WIP] Pass pointer to fcr31 around in fpu.h functions to avoid usage of g_dev. * [293](https://github.com/mupen64plus/mupen64plus-core/pull/293): Revert "Pass pointer to fcr31 around in fpu.h functions to avoid usage of g_dev." * [290](https://github.com/mupen64plus/mupen64plus-core/pull/290): Fix audio in RE2 * [289](https://github.com/mupen64plus/mupen64plus-core/pull/289): Fix Twisted Edge audio. Fixes #285 * [282](https://github.com/mupen64plus/mupen64plus-core/pull/282): No g dev in interrupt (Remove usage of g_dev in interrupt.) * [281](https://github.com/mupen64plus/mupen64plus-core/pull/281): Pass pointer to fcr31 around in fpu.h functions to avoid usage of g_dev. * [280](https://github.com/mupen64plus/mupen64plus-core/pull/280): Remove MK64 cheat for E and J * [278](https://github.com/mupen64plus/mupen64plus-core/pull/278): Avoid usage of g_dev in rdram_deteciton_hack. * [275](https://github.com/mupen64plus/mupen64plus-core/pull/275): README.md URL fix * [272](https://github.com/mupen64plus/mupen64plus-core/pull/272): Fix audio in Star Wars Episode I - Racer * [271](https://github.com/mupen64plus/mupen64plus-core/pull/271): DK64 Bone Displacement fix * [270](https://github.com/mupen64plus/mupen64plus-core/pull/270): Remove custom CountPerScanline values * [269](https://github.com/mupen64plus/mupen64plus-core/pull/269): Remove byte and hword accessors * [263](https://github.com/mupen64plus/mupen64plus-core/pull/263): Fix Indiana Jones * [258](https://github.com/mupen64plus/mupen64plus-core/pull/258): Reduce usage of g_dev * [257](https://github.com/mupen64plus/mupen64plus-core/pull/257): Get World Driver Championship booting * [256](https://github.com/mupen64plus/mupen64plus-core/pull/256): Mips instructions refactorings (This is just some internal reoganization of mips instructions functions.) * [255](https://github.com/mupen64plus/mupen64plus-core/pull/255): new_dynarec: Fix crash during shutdown * [253](https://github.com/mupen64plus/mupen64plus-core/pull/253): Restore old behavior when allocating memory for RDRAM * [250](https://github.com/mupen64plus/mupen64plus-core/pull/250): Don't reset the speed limiter when falling behind * [246](https://github.com/mupen64plus/mupen64plus-core/pull/246): CountPerOp=3 for CBFD * [243](https://github.com/mupen64plus/mupen64plus-core/pull/243): Fix compilation in msvc as per Gillou's comment. * [242](https://github.com/mupen64plus/mupen64plus-core/pull/242): Fix excessive warnings when compiling using clang. * [241](https://github.com/mupen64plus/mupen64plus-core/pull/241): Minor refac (Some minor refactorings to remove some magic constants and rework the si peripherals status command handling.) * [240](https://github.com/mupen64plus/mupen64plus-core/pull/240): Avoid g_dev in r4300 code (Small PR which avoids usage of the g_dev global variable inside TLB code.) * [239](https://github.com/mupen64plus/mupen64plus-core/pull/239): Don't use SDL directly * [238](https://github.com/mupen64plus/mupen64plus-core/pull/238): Dyna start * [237](https://github.com/mupen64plus/mupen64plus-core/pull/237): Add ConfigExternalGetParameter * [235](https://github.com/mupen64plus/mupen64plus-core/pull/235): new_dynarec: Code cleanup * [233](https://github.com/mupen64plus/mupen64plus-core/pull/233): fix include paths / fixes building on arm/neon * [232](https://github.com/mupen64plus/mupen64plus-core/pull/232): Disable OSD if OpenGL core context is in use * [227](https://github.com/mupen64plus/mupen64plus-core/pull/227): Device refactorings * [220](https://github.com/mupen64plus/mupen64plus-core/pull/220): Fix Kirby 64 save size * [216](https://github.com/mupen64plus/mupen64plus-core/pull/216): Fix new dynarec interrupt management (This also fixes soft reset.) * [215](https://github.com/mupen64plus/mupen64plus-core/pull/215): Fix assertion failure when starting Kuiki Uhabi Suigo * [213](https://github.com/mupen64plus/mupen64plus-core/pull/213): No globals * [212](https://github.com/mupen64plus/mupen64plus-core/pull/212): Allow CountPerScan and ViTiming in ROM database to be overridden * [211](https://github.com/mupen64plus/mupen64plus-core/pull/211): Avoid processing CIC response pif ram as commands * [208](https://github.com/mupen64plus/mupen64plus-core/pull/208): Various refactorings * [205](https://github.com/mupen64plus/mupen64plus-core/pull/205): Clean magic constants * [204](https://github.com/mupen64plus/mupen64plus-core/pull/204): Use custom ViRefresh for some games * [203](https://github.com/mupen64plus/mupen64plus-core/pull/203): Fix mario kart multiplayer timings * [202](https://github.com/mupen64plus/mupen64plus-core/pull/202): Make SDL usage optional in some files * [199](https://github.com/mupen64plus/mupen64plus-core/pull/199): Add using_tlb flag to savestates * [198](https://github.com/mupen64plus/mupen64plus-core/pull/198): Allow setting a loadstate job before emulator is running. * [196](https://github.com/mupen64plus/mupen64plus-core/pull/196): Fix Pokemon Puzzle League * [192](https://github.com/mupen64plus/mupen64plus-core/pull/192): new_dynarec: Allocate memory for original MIPS source code of a recompiled block before do_dirty_stub_ds is being called. * [182](https://github.com/mupen64plus/mupen64plus-core/pull/182): New dynarec fix * [180](https://github.com/mupen64plus/mupen64plus-core/pull/180): Use Ubuntu Trusty as base system for Travis CI * [168](https://github.com/mupen64plus/mupen64plus-core/pull/168): Documentation Update and Formatting * [155](https://github.com/mupen64plus/mupen64plus-core/pull/155): Fix speed limiter issue * [150](https://github.com/mupen64plus/mupen64plus-core/pull/150): Improve speed limiter accuracy * [144](https://github.com/mupen64plus/mupen64plus-core/pull/144): Framelimiter: Discard frames with excessive execution time * [143](https://github.com/mupen64plus/mupen64plus-core/pull/143): Fixed gfx moveScreen when SDL_VERSION > 1.2 * [140](https://github.com/mupen64plus/mupen64plus-core/pull/140): Call gfx moveScreen when SDL window moved (Windows only) * [138](https://github.com/mupen64plus/mupen64plus-core/pull/138): new_dynarec: Reverted printing method when warning about a block compiled at bogus memory address * [137](https://github.com/mupen64plus/mupen64plus-core/pull/137): Dynamic linker * [135](https://github.com/mupen64plus/mupen64plus-core/pull/135): new_dynarec: Fixed bomberman 64 * [133](https://github.com/mupen64plus/mupen64plus-core/pull/133): new_dynarec: Fixed verifier pointer when using trampoline jump * [132](https://github.com/mupen64plus/mupen64plus-core/pull/132): new_dynarec: Avoid replacing an allocated temporary register. Fixed crash in castlevania * [131](https://github.com/mupen64plus/mupen64plus-core/pull/131): Allow building the old dynarec on x64 with VisualStudio2013 * [128](https://github.com/mupen64plus/mupen64plus-core/pull/128): Rename new_dynarec.txt to new_dynarec.mediawiki * [125](https://github.com/mupen64plus/mupen64plus-core/pull/125): Remove Zelda OoT Subscreen Delay Fix from mupen64plus.ini * [124](https://github.com/mupen64plus/mupen64plus-core/pull/124): new_dynarec: Implemented recompiled DMULT instruction on x86 (This also fix DK going through wall issue on x86) * [123](https://github.com/mupen64plus/mupen64plus-core/pull/123): Merge back "Avoid .text relocations in PIC shared library" fix + cleanup linkage_arm.S * [122](https://github.com/mupen64plus/mupen64plus-core/pull/122): Remove unnecessary OpenBSD warning. * [120](https://github.com/mupen64plus/mupen64plus-core/pull/120): Avoid .text relocations in PIC shared library * [117](https://github.com/mupen64plus/mupen64plus-core/pull/117): Squelch sscanf warning in arm_cpu_features. * [98](https://github.com/mupen64plus/mupen64plus-core/pull/98): [WIP/RFC] Transfer Pak emulation support ## Closed Issues * [245](https://github.com/mupen64plus/mupen64plus-core/issues/245): Mario Kart 64 item not usable bug * [350](https://github.com/mupen64plus/mupen64plus-core/issues/350): RSP DMA double buffering not implemented * [438](https://github.com/mupen64plus/mupen64plus-core/issues/438): Mario 64 Star Revenge New dynarec game freezes * [616](https://github.com/mupen64plus/mupen64plus-core/issues/616): Please add 4K access to resolution in Android. * [552](https://github.com/mupen64plus/mupen64plus-core/issues/552): Tonic trouble (u) new dynarec crash * [338](https://github.com/mupen64plus/mupen64plus-core/issues/338): Turok 3 freezes after intro * [304](https://github.com/mupen64plus/mupen64plus-core/issues/304): Pokemon Puzzle League New Dynarec assert * [613](https://github.com/mupen64plus/mupen64plus-core/issues/613): Selecting a save state slot sends M64CORE_SAVESTATE_SLOT command twice * [558](https://github.com/mupen64plus/mupen64plus-core/issues/558): Donkey Kong 64 back to level beginning on vines * [587](https://github.com/mupen64plus/mupen64plus-core/issues/587): New dynarec CBFD is freezing * [504](https://github.com/mupen64plus/mupen64plus-core/issues/504): No 64 bit ARM library support with new dynarec * [603](https://github.com/mupen64plus/mupen64plus-core/issues/603): New dynarec not working on x64 * [540](https://github.com/mupen64plus/mupen64plus-core/issues/540): Translucent textures in Zelda OOT * [584](https://github.com/mupen64plus/mupen64plus-core/issues/584): Regression caused by #444 * [601](https://github.com/mupen64plus/mupen64plus-core/issues/601): Combined joystick actions not working on Windows 10 * [592](https://github.com/mupen64plus/mupen64plus-core/issues/592): Support for non-SDL mouse injection * [595](https://github.com/mupen64plus/mupen64plus-core/issues/595): Debugger is broken * [591](https://github.com/mupen64plus/mupen64plus-core/issues/591): Troubles extracting rom MD5 from save state * [580](https://github.com/mupen64plus/mupen64plus-core/issues/580): SM64 Last Impact: Game Crashes When jumping inside basket or entering warpipe in hub world * [539](https://github.com/mupen64plus/mupen64plus-core/issues/539): Is not longer possible to play using the keyboard * [568](https://github.com/mupen64plus/mupen64plus-core/issues/568): Is "frame advance" working? * [567](https://github.com/mupen64plus/mupen64plus-core/issues/567): Unable to enter and edit config * [555](https://github.com/mupen64plus/mupen64plus-core/issues/555): Audio is not working in Windows * [560](https://github.com/mupen64plus/mupen64plus-core/issues/560): D-pad on iOS * [536](https://github.com/mupen64plus/mupen64plus-core/issues/536): Bus error when loading savestate on odroid c2 (armhf) * [261](https://github.com/mupen64plus/mupen64plus-core/issues/261): ARM New dynarec crash * [522](https://github.com/mupen64plus/mupen64plus-core/issues/522): Building with LTO enabled makes loading save states crash * [543](https://github.com/mupen64plus/mupen64plus-core/issues/543): Speed limiter is slowing down way too much * [542](https://github.com/mupen64plus/mupen64plus-core/issues/542): Indiana Jones have bugs in dynarec * [531](https://github.com/mupen64plus/mupen64plus-core/issues/531): Unplugging controllers using CONTROL_INFO doesn't work * [528](https://github.com/mupen64plus/mupen64plus-core/issues/528): Log spam when loading save states: Unexpected command format 01 c4 01 * [222](https://github.com/mupen64plus/mupen64plus-core/issues/222): World Driver Championship | Video Error: Error: Unsupported uCode! crc: 844b55b5 * [530](https://github.com/mupen64plus/mupen64plus-core/issues/530): Major League Baseball with Ken Griffey Jr. (Messed Up Splash Screens and Start Screen) * [181](https://github.com/mupen64plus/mupen64plus-core/issues/181): Top Gear Really 2 freezes * [294](https://github.com/mupen64plus/mupen64plus-core/issues/294): Save states are locking up the emulator * [321](https://github.com/mupen64plus/mupen64plus-core/issues/321): Crash report * [527](https://github.com/mupen64plus/mupen64plus-core/issues/527): GLP license text has outdated address * [484](https://github.com/mupen64plus/mupen64plus-core/issues/484): mupen64plus save/screenshot/config folder change on macOS * [512](https://github.com/mupen64plus/mupen64plus-core/issues/512): Tetris 64 (J) freezes on boot. * [489](https://github.com/mupen64plus/mupen64plus-core/issues/489): Reported crashes * [497](https://github.com/mupen64plus/mupen64plus-core/issues/497): Crash when loading save state * [344](https://github.com/mupen64plus/mupen64plus-core/issues/344): Possibility of idle loop detection on cached interpreter. * [447](https://github.com/mupen64plus/mupen64plus-core/issues/447): Removing the GoldenEye TLB hack (Pure Interpreter) * [486](https://github.com/mupen64plus/mupen64plus-core/issues/486): International super star soccer 2000 keeps stalling * [482](https://github.com/mupen64plus/mupen64plus-core/issues/482): Compiler log seldomness * [479](https://github.com/mupen64plus/mupen64plus-core/issues/479): MacOS makefile changes * [463](https://github.com/mupen64plus/mupen64plus-core/issues/463): Audio cracks in Banjo Kazooie * [458](https://github.com/mupen64plus/mupen64plus-core/issues/458): FlashRam saving fails in Derby Stallion 64 * [467](https://github.com/mupen64plus/mupen64plus-core/issues/467): Some devices are failing CoreStartup with M64ERR_NO_MEMORY * [445](https://github.com/mupen64plus/mupen64plus-core/issues/445): Can't change pak type after game has started using CONTROL.plugin API * [469](https://github.com/mupen64plus/mupen64plus-core/issues/469): Hey You Pikachu corrupt graphics * [462](https://github.com/mupen64plus/mupen64plus-core/issues/462): Ide Yousuke no Mahjong Juku - black screen * [456](https://github.com/mupen64plus/mupen64plus-core/issues/456): Waialae Country Club won't save * [452](https://github.com/mupen64plus/mupen64plus-core/issues/452): Turok: Dinosaur Hunter not responding to inputs. * [385](https://github.com/mupen64plus/mupen64plus-core/issues/385): Bomberman 64: black screen using arm/x86 new dynarec * [283](https://github.com/mupen64plus/mupen64plus-core/issues/283): BattleTanx - Global Assault (U) - Game restarts * [442](https://github.com/mupen64plus/mupen64plus-core/issues/442): No longer supporting Raspberry Pi? * [434](https://github.com/mupen64plus/mupen64plus-core/issues/434): Should mupen64plus switch to big-endian format for raw saves? * [432](https://github.com/mupen64plus/mupen64plus-core/issues/432): Bomberman 64 is freezing as of latest * [426](https://github.com/mupen64plus/mupen64plus-core/issues/426): x86 new dynarec games are freezing * [429](https://github.com/mupen64plus/mupen64plus-core/issues/429): UI-Console Error: LoadLibrary('mupen64plus.dll') error: The specified module could not be found. * [418](https://github.com/mupen64plus/mupen64plus-core/issues/418): Castlevania gets stuck in the intro demo * [145](https://github.com/mupen64plus/mupen64plus-core/issues/145): Donkey Kong 64 - Bone Displacement * [288](https://github.com/mupen64plus/mupen64plus-core/issues/288): Indiana Jones x86 new dynarec crash * [274](https://github.com/mupen64plus/mupen64plus-core/issues/274): New Dynarec: WDC not working * [416](https://github.com/mupen64plus/mupen64plus-core/issues/416): Interpreter fails CP1ROUND test * [384](https://github.com/mupen64plus/mupen64plus-core/issues/384): Better COUNT emulation idea/enhancement * [405](https://github.com/mupen64plus/mupen64plus-core/issues/405): PIF rewrite broke loading save states at startup * [409](https://github.com/mupen64plus/mupen64plus-core/issues/409): Mischief Makers - Framerate halved * [402](https://github.com/mupen64plus/mupen64plus-core/issues/402): Custom Robo V2 freeze * [374](https://github.com/mupen64plus/mupen64plus-core/issues/374): Save paths not correct. * [398](https://github.com/mupen64plus/mupen64plus-core/issues/398): Vigilante 8: Second Offense Screenshots/Save States don't work. * [349](https://github.com/mupen64plus/mupen64plus-core/issues/349): Crash GLXBadFBConfig * [315](https://github.com/mupen64plus/mupen64plus-core/issues/315): SM64 won't launch (several issues I believe) * [392](https://github.com/mupen64plus/mupen64plus-core/issues/392): Yakouchuu II - Satsujin Kouro does not go to menu * [154](https://github.com/mupen64plus/mupen64plus-core/issues/154): Paper Mario (U) flash written incorrectly * [389](https://github.com/mupen64plus/mupen64plus-core/issues/389): OSD=0 causes game to hang after one has been played * [391](https://github.com/mupen64plus/mupen64plus-core/issues/391): Hydro thunder broke with recent commits * [127](https://github.com/mupen64plus/mupen64plus-core/issues/127): Several Rare games locking up while using LLE video plugins * [379](https://github.com/mupen64plus/mupen64plus-core/issues/379): Perfect Dark (Europe) is hanging/freezing at the Perfect Dark logo * [130](https://github.com/mupen64plus/mupen64plus-core/issues/130): Remove processDList() from code and API * [335](https://github.com/mupen64plus/mupen64plus-core/issues/335): Compressed ROM support * [303](https://github.com/mupen64plus/mupen64plus-core/issues/303): No RPS available in Mupen64 0.51 * [377](https://github.com/mupen64plus/mupen64plus-core/issues/377): Travis CI broken * [314](https://github.com/mupen64plus/mupen64plus-core/issues/314): New Dynarec: NFL Quarterback Club 2001 corrupt graphics * [186](https://github.com/mupen64plus/mupen64plus-core/issues/186): Perfect Dark freezes occasionally when attempting to start next level * [346](https://github.com/mupen64plus/mupen64plus-core/issues/346): Anisotropic Filtering Missing * [200](https://github.com/mupen64plus/mupen64plus-core/issues/200): Top Gear Rally bad audio * [316](https://github.com/mupen64plus/mupen64plus-core/issues/316): South park restarts (x86 fix not PIC complaint) * [366](https://github.com/mupen64plus/mupen64plus-core/issues/366): Doom 64 Mempak saving issue * [354](https://github.com/mupen64plus/mupen64plus-core/issues/354): [Website] HTTPS does not work * [345](https://github.com/mupen64plus/mupen64plus-core/issues/345): XbrZ is Broken * [221](https://github.com/mupen64plus/mupen64plus-core/issues/221): All Star Baseball 2001 not starting (TLB Exception) * [311](https://github.com/mupen64plus/mupen64plus-core/issues/311): International Track & Field 2000 won't start (TLB Exception) * [340](https://github.com/mupen64plus/mupen64plus-core/issues/340): Unable to map C buttons * [331](https://github.com/mupen64plus/mupen64plus-core/issues/331): Indiana Jones freeze at end of level * [319](https://github.com/mupen64plus/mupen64plus-core/issues/319): Issue with compile-time generation of asm defines * [328](https://github.com/mupen64plus/mupen64plus-core/issues/328): x86 new dynarec crashing * [325](https://github.com/mupen64plus/mupen64plus-core/issues/325): DisableExtraMem no longer working? * [323](https://github.com/mupen64plus/mupen64plus-core/issues/323): NHL Breakaway 98 won't start * [309](https://github.com/mupen64plus/mupen64plus-core/issues/309): Space Invaders won't start * [87](https://github.com/mupen64plus/mupen64plus-core/issues/87): Signed integer overflow in core interpreter * [217](https://github.com/mupen64plus/mupen64plus-core/issues/217): Add custom ini support * [284](https://github.com/mupen64plus/mupen64plus-core/issues/284): CBFD freezes when entering other stages using a saved state * [299](https://github.com/mupen64plus/mupen64plus-core/issues/299): RE2 video distorted on ARM dynarec and x64 Windows dynarec * [287](https://github.com/mupen64plus/mupen64plus-core/issues/287): Banjo tooie crash after latest refactors * [219](https://github.com/mupen64plus/mupen64plus-core/issues/219): RSP HLE Crash * [268](https://github.com/mupen64plus/mupen64plus-core/issues/268): new dynarec ARM crash * [291](https://github.com/mupen64plus/mupen64plus-core/issues/291): macho64 output format not recognized on El Capitan * [285](https://github.com/mupen64plus/mupen64plus-core/issues/285): Twisted Edge Extreme Snowboarding no audio * [266](https://github.com/mupen64plus/mupen64plus-core/issues/266): Constant audio buffer underflows and GFX flickering in Pokemon Puzzle League FMV's * [267](https://github.com/mupen64plus/mupen64plus-core/issues/267): Question: RSP specific instructions and their interpretation * [226](https://github.com/mupen64plus/mupen64plus-core/issues/226): Input Lag with GFX plugins that have framebuffer emulation (Mario 64) * [262](https://github.com/mupen64plus/mupen64plus-core/issues/262): Pilot Wings 64 Shadows Graphics Glitch * [254](https://github.com/mupen64plus/mupen64plus-core/issues/254): Mupen 0.5 Save States (Discussion) * [251](https://github.com/mupen64plus/mupen64plus-core/issues/251): Compilation fix for SDL2 from homebrew on Mac for plugins * [247](https://github.com/mupen64plus/mupen64plus-core/issues/247): How to run in Fedora? * [158](https://github.com/mupen64plus/mupen64plus-core/issues/158): Crash during Mario Party (Coin Block Bash) * [248](https://github.com/mupen64plus/mupen64plus-core/issues/248): Missing textures and incorrect placement in Star Wars: Shadows of the Empire * [244](https://github.com/mupen64plus/mupen64plus-core/issues/244): Saving sate cause retroarch to crash * [193](https://github.com/mupen64plus/mupen64plus-core/issues/193): OSD should support OpenGL core profile * [195](https://github.com/mupen64plus/mupen64plus-core/issues/195): arm new dynarec doesn't build with clang * [234](https://github.com/mupen64plus/mupen64plus-core/issues/234): Segfault when closing games * [225](https://github.com/mupen64plus/mupen64plus-core/issues/225): Ability to set custom RDRAM size * [230](https://github.com/mupen64plus/mupen64plus-core/issues/230): fails to build since 5aebce38204de4fe3671f78e3cee66838f9a1d87 * [139](https://github.com/mupen64plus/mupen64plus-core/issues/139): Configurable VI Refresh Rate * [187](https://github.com/mupen64plus/mupen64plus-core/issues/187): Gamepads are comfortable * [194](https://github.com/mupen64plus/mupen64plus-core/issues/194): Compiling to custom paths * [191](https://github.com/mupen64plus/mupen64plus-core/issues/191): Wonder Project J2: Cutoff / misaligned textures * [183](https://github.com/mupen64plus/mupen64plus-core/issues/183): Building on Windows * [179](https://github.com/mupen64plus/mupen64plus-core/issues/179): NBA live 2000 crash * [170](https://github.com/mupen64plus/mupen64plus-core/issues/170): Banjo-Tooie crash * [160](https://github.com/mupen64plus/mupen64plus-core/issues/160): Vidext SDL2 compatibility overrides context profile mask, making attribute useless * [119](https://github.com/mupen64plus/mupen64plus-core/issues/119): ARM build creates broken PIC with TEXTREL * [172](https://github.com/mupen64plus/mupen64plus-core/issues/172): Screenshots broken on raspberry pi * [166](https://github.com/mupen64plus/mupen64plus-core/issues/166): glide64mk2 requires libboost 1.46.1 * [173](https://github.com/mupen64plus/mupen64plus-core/issues/173): Core build fails in VS2013 * [169](https://github.com/mupen64plus/mupen64plus-core/issues/169): With mouse input disabled, mouse still gets captured and ctrl alt does nothing * [167](https://github.com/mupen64plus/mupen64plus-core/issues/167): N64 from open emu suddenly stopped working. * [163](https://github.com/mupen64plus/mupen64plus-core/issues/163): Does not work on Windows XP (but works if binaries are patched) * [161](https://github.com/mupen64plus/mupen64plus-core/issues/161): Disney's Tarzan freezes * [153](https://github.com/mupen64plus/mupen64plus-core/issues/153): Triggering [CoreEvents] using simultaneous button presses doesn't work * [152](https://github.com/mupen64plus/mupen64plus-core/issues/152): Matching code for input neglects spaces in controller names * [149](https://github.com/mupen64plus/mupen64plus-core/issues/149): Bomberman 64: transition and effets are not rightly emulated * [146](https://github.com/mupen64plus/mupen64plus-core/issues/146): RSP SETTINGS VANISHED * [141](https://github.com/mupen64plus/mupen64plus-core/issues/141): Fails to build on windows (mingw64) * [136](https://github.com/mupen64plus/mupen64plus-core/issues/136): si/eeprom.o (symbol from plugin): memset used with constant zero length parameter; * [102](https://github.com/mupen64plus/mupen64plus-core/issues/102): Google Code shutting down: More organization needed * [126](https://github.com/mupen64plus/mupen64plus-core/issues/126): Can map buttons with controller, game play doesnt work. Sixaxis * [107](https://github.com/mupen64plus/mupen64plus-core/issues/107): Next release discussion Mupen64Plus-core v2.5 - April 26, 2015 -------------------------------------- - Game-specific fixes (Banjo Tooie, Zelda Ocarina of Time, DK64, Hydro Thunder, others) - Game-specific override for # of clock cycles per cpu instruction - Many bug fixes for SDL 2.0 - Various instruction-specific optimizations in new dynarec - Cheat fixes for WWF No Mercy, Bomberman Hero, Super Mario 64, and Pokemon Stadium (E) - Major R4300 CPU core refactoring in many subsystems to improve code organization - Rewrite speed limiter code to improve performance and audio synchronization - Separate the logic of the Pure Interpreter from the Cached Interpreter - Regression test improvements: add speed tests, ignore border in video tests due to Rice scissor problems - New Dynarec: Speed improvements, accuracy fixes, build support for MSVC - Support for building against OpenGL ES - Build system improvements for ARM / Raspberry Pi - Video Extension: support OpenGL context version and profile selection (needed for GLideN64 under OSX) Mupen64Plus v2.0 - July 4th, 2013 --------------------------------- - Fixes for various games (DK64, Zelda, Blast Corps) - add Ari64's dynamic recompiler for x86 (32-bit) and ARM - improved PJ64 savestate loading - support video window resizing (with help from video plugin and front-end application) - Auto-detect savestate type (Mupen64Plus or PJ64) when loading from a slot - many various code cleanups in core from casualjames - support to build against SDL2 - debugger code cleanup - Project files for Visual Studio 2012 - Makefile changes - add support for PowerPC and MinGW32 builds - add cross-compiling support to build Win32 executables (MXE) under Linux Mupen64Plus v1.99.5 - March 10, 2012 ------------------------------------ - New feature: support for N64 internal real-time clock - use X-Scale's PIF-CIC algorithm instead of the hard-coded challenge-response pairs - New config parameter for path to save SRAM/EEPROM/MPK files, so they can be separated from emulator snapshots - updated core for new Mupen64plus 2.0 API versioning scheme - split core configuration data into 2 sections: Core and CoreEvents. Added version numbers and upgrade handling to both - Accurately emulate the RSP DMA operation (from Bobby Smiles) - bugfix: #290 - OnScreenDisplay text is sometimes captured in screenshots - bugfix: when the front-end specifies an override for the configuration directory, always use this path, so that we don't load the config from there and then save it back to the default user path - bugfix: #468 - On-screen-display problem under OSX - bugfix: Use option SaveStatePath from config file - bugfix: don't call SDL_Quit() until the core library is being unloaded. fixes some front-end use cases - bugfix: #410 - segfault in dma_pi_write()-->strlen() if /home/username/.local/share/mupen64plus/ owned by root - bugfix: for Interpreter cores, use proper math functions for ceil/floor/round/trunc instead of x87 rounding modes - many makefile fixes and improvements Mupen64Plus v1.99.4 - February 22, 2010 --------------------------------------- - Added some type checking to ConfigGetParameter() function, and a new error type - Bugfix: avoid segfault in the video extension code if SDL initialization fails (because video plugin fails) - Added new CoreGetRomSettings() function for front-ends - Allow to run dynarec in hardware DEP protected windows - Allow core .cfg parser to accept strings without quotes around them - API change: use new ReadScreen2() video plugin function - New re-entrant R4300 disassembler, from tty68k/zzt32, a man who loves MIPS processors - makefile fixes and improvements, code cleanups Mupen64Plus v1.99.3 - February 13, 2010 --------------------------------------- - New feature: configuration function ConfigGetParameterType() - New feature: up to 1000 screenshots per ROM are allowed - New feature: support for Gameshark 3.3 patch codes - Bugfix: Use Dynarec by default when core supports it. If dynarec is selected but unavailable, fall back to cached interpreter - Bugfix: screenshot directory handling code used unix-specific path separators; now is platform-independent - Bugfix: #313 - 64-bit inline assembly code in r4300/x86_64/rjump.c needs to have underscores before the symbols names in OSX - Bugfix: old bug in the core - hang if a ROM *without* a 16kb EEPROM type is loaded after a ROM *with* a 16kb EEPROM type - Bugfix: rumble feature caused memory corruption - Bugfix: Problem with zilmar API: the plugin RomOpen() functions had no way of returning errors to the core, causing crashes - Replaced api documentation .tar.gz file with the mediawiki text - Build script improvements: - new feature: m64p_update.sh script can take an input argument to update to a tag or revision - new feature: added bash script for building source packages of individual modules - Makefile improvements: - dont run ldconfig on make install unless user is root - added OS type GNU/kFreeBSD Mupen64Plus v1.99.2 - January 6, 2010 --------------------------------------- - doc: added tarball of emuwiki api documentation from 2010-01-06 for backup purposes - clean-up: removed almost all of the ifdef WIN32 statements - bugfix: stop spamming console with "Core: couldn't open memory pack file '...' for reading" messages - bugfix: stop spamming console with "Core: couldn't open eeprom file '...' for reading" messages - new feature: MSVC8 project file for mupen64plus-core, refactored code for VC8 compatibility - Makefile improvements: - throw error if OS/CPU not supported - use DESTDIR in install/uninstall paths - Allow user-specified CC/CXX/LD paths - makefile needs to install Core header files so that plugins can be built later Mupen64Plus v1.99.1 - December 14, 2009 --------------------------------------- New 2.0 architecture advantages: - Simplified emulator Core, making it much more portable - Removed all GUI code from plugins, making them simpler and more portable - User interface development is not tied to Core emulator releases - All messages from core/plugins can be filtered and shown in GUI instead of only on console - Video Extension allows Front-end to override some video functions, ie to support embedded render window - Startup in Fullscreen mode, instead of always starting in windowed mode and switching to FS after few seconds - video resolution can be given via command-line parameter - all configuration options for core and plugins are in a single config file, can be configured with a single GUI - dummy plugins are automatically used if plugin loading fails for any reason - core and plugins all use the same conventions for where to put data/config files Mupen64Plus core: - New feature: cheat code support - New feature: Keyboard shortcuts for Core commands are now user-configurable - New feature: can load/save PJ64 state files - Major code cleanup, refactored build system to separate source and object files - Removed many dependencies to simplify porting to other platforms - Moved all of the SDL event-related stuff into a new source file eventloop.c - Use XDG directory convention for file locations on Unix - bugfix: frame advance feature should advance every frame, instead of every vertical interrupt (every field) - bugfix: allow diagonal hat movements for core joystick commands - bugfix: modified SDL event loop joystick code so that gameshark button press is captured, and joystick commands that are level-triggered instead of edge-triggered (such as fast foward) can be accommodated - bugfix: fixed the outstanding SDL event issues by re-writing the code which handles the joystick-event-driven core commands. Now the axis-based commands use hysteresis and there is a single global event function for determining if the gameshark button is pressed - bugfix: OSD crash after pause-stop-start-pause of emulator - bugfix: Set video width and status, aiDacrate during savestate load - bugfix: in pure interpreter, Dont allow to override r0 register - bugfix #52: PJ64 load state patch from olejl77 - bugfix #268: use aligned malloc and mprotect to set executable status for dynarec emitted code - bugfix #51: Floating Point Register data was not correctly converted when switching between 32-bit (MIPS-I) mode and 64-bit (MIPS III). New code more closely emulates behavior of r4300 hardware. Fixes collision problems in Banjo-Tooie - bugfix #272: rounding mode for x86 FPU not being set correctly in interpreter and pure interpreter cores - bugfix: many games need different ScreenUpdateSetting to work properly with Rice Video Mupen64Plus v1.5 - January 4, 2009 ---------------------------------- Major New Features: - support for Macintosh OSX platform with Intel CPUs - Qt4 GUI by slougi, Tillin9, and others - Rom Cache System (r636, others), by Tillin9, Okaygo, and Hasone. Minor New Features: - r1235: Debugger: memory breakpoint speedup - r1170-1178,1181: QT GUI: translations for English, Norwegian, German, and Dutch - r1155: Use configurable key commands for special emulator functions - r1134: got our own custom test ROM, courtesy of Marshallh - r1046: debugger: new r4300 disassembler from ZZT32 - r829: jttl_audio: added GTK GUI configuration dialog - r793: soft reset (hit F9) - r782: jttl_audio: both SDL-based and OSS-based volume control methods are now supported - r765: added savestate conversion tool to be able to load pre-v1.5 savestate files - r711: 7-zip support - r692: Multi-file Zip support - r667: GTK GUI: user-configurable columns in ROM browser - r659: LZMA archive support - r638: BZip2 archive support - r629,634: LIRC - added support for speedup, slowdown, pause, and frame advance Updates: - r1007,1032: GTK GUI improvements - r970, 1019: use SDL threading support instead of pthreads - r935,938,940: Gtk GUI updates for core and Jttl - r642,655-657,663,664,747,759,761-763,768-770,774,775,780,781,783,786,787,825,828,931: mupen64plus.ini updates: Good Names, stars, EEPROM types, players, rumble support Bugfixes: - r1247: rsp_hle: memory overwrite bug with Zelda:OOT - r1234: out of bound array bug in memory access function handlers - r1222,1223,1228,1229: Debugger fixes - r1183: Blight Input: sometimes the axis direction would flip - r1133: Added stop rumble to load savestate, fixes issue 165 - r1077: GTK GUI bugfixes - r1063: rice video: crash in MMX/SSE checking functions - r800: logical error in strcpy loop in util.c - r798: small bugfixes in blight_input: 1. only save config file after running config dialog, not every time DLL is closed. 2. If rumble is not available on a controller, don't allow user to switch between rumble and mempack. 3. If rumble is selected in config file but not available on a controller, select mempack instead. - r789: 3 glN64 bugfixes (segfaults on a 64-bit system in Perfect Dark): prevent clamp values from being negative, handle TMEM wrap-arounds from wacky height/line values in texture cache load and texture CRC functions - r788: rice video: add checks for uint32 height/width parameters which can be negative, causing segfault on 64-bit systems - r784: 64-bit problem causing GUI crashes - gotta save/restore all the callee-saved registers around the dynarec - r758: fixed some savestate problems - r748: Fixed 64-bit dynarec crash in genj_idle() and genjal_idle() - r715: Bugfixes thanks to Valgrind. Two using strcpy with source and destination overlay, i.e. strcpy(p,p+1) - r700: set ScreenUpdateSetting=1 in rice video ini file for Conkers BFD - r694: require bash shell scripting for install.sh - r686: fixed OSD crash bug after running a game, disabling OSD, then running another game - r684: OGLFT measuring functions were taking a huge chunk of CPU time. Refactored code to measure only once and store the line size and the message sizes instead of re-measuring all the time. This eliminated nearly all of the OSD overhead on my PC - r681: Refactored OGLFT to do color setting outside of glyph compiling, so the OSD fading doesnt force bitmaps to be continually recreated with calls to renderGlyph. Seems to have cut the excessive cpu usage of the OSD about by half - r680: removed many unused classes from OGLFT font library code - r676: bugfix in my BYTESWAP macros - r674: Removed glide64/Tmem_nasm.asm source file and the project dependency on nasm/yasm assemblers - r673: removed inline assembly sections in rdp_loadblock and rdp_loadtile, including their dependency on functions in Tmem_nasm.asm. Replaced with new C code. This fixes a segfault on some 64-bit source builds - r669: string function causing crash on 64-bit linux - r667: issue #88 - added basic view menu in GTK GUI - r628,633: Small patch to get glide64.so to compile with O3 optimizations - r622: Fixed segfault in Glide64 as per issue 133 - r619: fix LIRC build to integrate w/ new screenshot mechanism - r608: another couple of memory leak fixes from Tub, in main/config.c - r605: fix from Tub for free() bug in main/util.c/list_delete() - r587: issue #111: close screenshot file after saving Mupen64Plus v1.4 - June 14, 2008 ----------------------------------- - New feature: Graphical debugger for R4300 core - New feature: On Screen Display - New feature: KDE4 GUI (experimental) - New feature: cheat system with Gameshark codes - New feature: search/filter box in GTK GUI - New feature: Single frame advance - New feature: adjust emulator playback speed up or down in 5% increments - New feature: Rumble Pak support with force feedback - New feature: Map emulator functions (fullscreen, stop emulation, etc) to joystick buttons or axis movements. - New feature: Volume up/down - Blight Input: Individually configure each direction of X and Y axis, which allows inverting the axis - JTTL_Audio: libsamplerate support for high quality audio resampling - GTK GUI: Removed second status bar which was not used - GTK GUI: Implemented accelerator keys - GTK GUI: Replaced custom directory browser with GTK file chooser - GTK GUI: numerous small changes and fixes - Added Mupen64Plus 'man' (manual) page - Removed mupen64_audio plugin, as it was unnecessary and mostly broken - Added NoMemoryExpansion parameter to emulate 4MB console; fixes some games - Overhaul of rom handling functions; numerous small fixes - Bugfix: Removed NoAudioDelay core option to resolve issue #48 - Bugfix: check for stopped state in dynarec jump function, to fix unresponsive emulator when game gets stuck in loop - Bugfix: GTK GUI: #6 - if a ROM is selected in the ROM browser and 'play' is pressed, emulation will start - Bugfix: GTK GUI: #62 - ROM browser column sorting works - Bugfix: Rice Video: Support hi-res textures with different scale factors for X and Y - Bugfix: Blight Input: don't use 100% CPU in configuration dialog Mupen64Plus v1.3 - March 29th, 2008 ----------------------------------- - New feature: Glide64 video plugin for 32-bit and 64-bit, renamed project Mupen64Plus - New feature: Combine mupen64 and mupen64_nogui into a single binary - New feature: ability to change icon size - New feature: support different directories for install (plugins, icons, etc) and config (save games, config files) - New feature: support for creating/using ~/.mupen64plus dir for storing user data - New feature: support for installation via "make install" or "./install.sh" - New feature: support for plugins given via command line option in GUI mode - New feature: config dialog checkbox to toggle "noask" setting - New feature: pause/continue functionality with LIRC - Removed messagebox utility and replaced it with cleaner alert_message/confirm_message calls - GTK GUI: Set parent window for all popups so WM will center popup windows over the main gui window - Added README file with information about usage of Mupen64Plus and plugins - Removed mupen64_soft_gfx, as it didn't work - Removed Win32 code from RSP HLE plugin, - Change fullscreen hotkey to Alt+Enter - Only plugin filenames (not paths) are stored in the mupen64plus.conf file - Modified pre.mk and glide64 makefile to auto-select yasm or nasm - Bugfix: Rice Video: Make configuration during gameplay possible again - Bugfix: many compiler warnings and errors in Glide64 - Bugfix: segfault in Goldeneye and Perfect Dark for 64-bit dynarec - Bugfix: 64-bit dynarec bug in genld() - Bugfix: buffer overflow allocating temp strings for basename/dirname - Bugfix: GTK GUI: Exiting via File -> Exit wasn't writing out config file to disk - Bugfix: GTK GUI: "About" menu does not pop up while emulation is running - Bugfix: Glide64: Refactored a bunch of inline asm code with potential bugs - Bugfix: Added plugin error checking before emulator is started - Bugfix: Logo not loading in "about" window - Bugfix: Segfault in plugin_scan_directory() - Bugfix: ROM pause/continue while playing - Bugfix: Too many dialog windows when loading a bad dump or hacked rom - Bugfix: Closing emulation window now stops emulator - Bugfix: Rice Video: config dialog bug, now it displays proper resolution - Bugfix: GTK GUI: "Toolbar Style" now works - Bugfix: Glide64: changed inline asm label syntax, for compatibility with gcc 4.3.0 - Bugfix: Many other minor bug fixes, GTK warnings fixes, translation corrections, etc Mupen64-amd64 v1.2 - February 10th, 2008 ---------------------------------------- - New feature: Dynamic Recompiler for 64-bit - New feature: New ROM Browser for Mupen64 GUI build - New feature: LIRC remote control integration for NOGUI build - Added R4300 instruction counting capability to 64-bit Dynarec - Added R4300 profile data output for 32-bit and 64-bit dynamic recompilers - TLB Optimization / bugfix - Revised makefiles to support PPC builds - Bugfix: memory leaks in mupenIniApi.c - Bugfix: corrupted filenames being saved to disk for mupen64.ini - Bugfix: crash in jttl_audio - Bugfix: crash when running game from gui after first time - Bugfix: spurious noise blip when running game from gui after first time RiceVideoLinux v1.2 - February 10th, 2008 ----------------------------------------- - Revised makefiles to support PPC builds - Added more logging to hi-res texture loading - Bugfix: Texture dumping now works Mupen64-amd64 v1.1 - December 9th, 2007 ---------------------------------------- - New icons for GTK GUI - Removed GTK 1.2 GUI build; GTK 2.0 is required now - Added file pointer checking for frwite() calls and error logging - Added scrolling to the the rom list widget - Added main/version.h file to store Mupen64-amd64 package version - Print joystick numbers along with names in blight input to tell multiple devices apart - Merged okaygo's TLB hack for Goldeneye from Mupen64++ - Rework GTK GUI config dialog; fixed bugs in ROM directory list - Bugfix: segfault from playing same game twice in a row from GUI - Bugfix: segfault from fwrite() failure in dma_pi_read in memory/dma.c - Bugfix: exit properly instead of segfault after dyna_stop is called - Bugfix: blight input: SDL_PumpEvents must be called from thread which initialized SDL video mode - Bugfix: blight_input: joystick handling caused glitch in config dialog - Bugfix: makefile: 32-bit CFLAGS must be used when doing 32-bit build on 64-bit machine - Bugfix: Added makefile to root folder for building releases RiceVideoLinux v1.1 - December 9th, 2007 ----------------------------------------- - Removed configure script and config.h; added SDL and GTK library checking and handling in main makefile - Added capability to load 24-bit PNG files into 32-bit texture buffer - Added more error logging to hi-res texture code - Added combiner type logging to DeviceBuilder class - Bugfix: added quotes around BUILD_NUMBER to prevent segfault on About box - Bugfix: SSE vertex lighting inline ASM code was incorrect - Bugfix: makefile: 32-bit CFLAGS must be used when doing 32-bit build on 64-bit machine - Bugfix: segfault with hi-res textures (incorrect scale factor used when creating memory buffer) - Bugfix: modified DrawSprite function in RenderExt.cpp to eliminate gaps between textures in Puyo Puyo 4 - Bugfix: opengl error in ApplyTextureFilter due to wrong enum type - Bugfix: Simplified fragment program and removed ATTRIB parameters to fix problems on Intel X3100 hardware Mupen64-amd64 v1.0 - November 12th, 2007 ---------------------------------------- - Forked from Mupen64 v0.5 - Ported to 64-bit architecture by NMN/SirRichard42 - Fixed texture cache problem in glN64 - Print more information during plugin loading process - Added blight input config file for logitech dual-action style controllers - Added SDL_GL_SWAP_CONTROL attribute in glN64 to prevent tearing - Changed glVoids to voids due to strange compilation bug that occurs on certain systems - Totally refactored makefiles; now plugins are built as sub-modules - Better logging for R4300 core selection, disallow Dynamic Recompilation for 64-bit builds at compile time - Set execstack attribute for all mupen64 binaries, to prevent segfault when Dynamic Recompilation is used - Lots of code cleanup - Removed 'multi-user' mode of operation - Removed 'configure' script and config.h file - Refactored plugin loading code in _nogui build, much more user-friendly now - Added comments and SDL shutdown code to main.c - Bugfix: fixed memory leaks in plugin.c - Bugfix: strcpy in main/gui_gtk/config.c should not copy overlapping strings - Bugfix: blight audio: only close down audio and timer sub-systems when exiting RiceVideoLinux v1.0 - November 12th, 2007 ----------------------------------------- - Forked from RiceVideo 6.1.1 beta 10 - Ported to Linux by Hacktarux - Ported to 64-bit architecture by SirRichard42 - Added rudimentary debug support for Linux - Merged all Non-Win32 changes from Mudlord's RiceVideo SVN 6.1.3.2 (mostly hi-res texture load/save) - Added more logging information - Tweaked Z-Buffer and Z-Bias (Decal Z-mode) handling to be like that of D3D renderer - Added screenshot capability for Linux build - Cleaned up Makefile, added 32-bit and debug build modes, help info - Removed all Win32 code, massive cleanup - Fixed uninitialized data members in several places - Bugfix: crash in Banjo Kazooie - dont delete cached texture if its currently loaded in the g_textures array - Bugfix: crash in Carmaggedon caused by illegal values in texture loading function - Bugfix: screen flashes in Mario Kart and Kirby64, tweaked .ini ScreenUpdateSetting what's new in 0.5: - Core + detection of invalid code cache for ambiguous region now use adler32 (faster than previous algorithm) + fixed a bug in ini file compression + added support for framebuffer effects functions : these functions are there to help the plugins that support framebuffer extension to zilmar's spec. These functions are based on rice's idea. I've worked closely with Gonetz to implement these and the only plugin that support this feature is Glide64 0.8 (when option is enabled). Many hard to emulate framebuffer effects are supported by this feature. Mariokart's monitor in first race running fullspeed and puzzle effect in banjo's intro are two examples that i can think about but there are many more. + detection of VI interrupt rate works on weird country codes + better detection of self modifying code in dma + warnings fixed on new gcc versions + rsp's dmem and imem are now contiguous in PC's memory (some windows plugins were requiring this) + slightly improved audio timing + better detection of self modifying code when accessing memory through TLB + fixed a bug in RSP memory write + reading from ai_current_delay register should work even when Count register is looping + in interpreter code : fixed a bug in jump opcodes (detection of exceptions in delay slot in some rare conditions) + the event scheduler has better support for Count register loops + better AI interrupt handling (for musyx games for example) + jump opcodes changed in pure interpreter core so that they are timed exactly like on the other cores (easier to debug this way) + fixed a bug when accessing memory through invalid TLB in LDL, LDR, LWL, LWR, SWL, SDL, SDR, SWR opcodes + added LL, SC opcodes + two consecutive jump opcodes doesn't crash in the dynarec (result is undefined according to the r4300 manual but some games are doing it). + basic implementation of fpu opcodes in dynarec + division by 0 in FPU opcodes is returning NaN + all jump opcodes implemented in the dynarec + faster inside function loop with dynarec (register cache) + various bug fixes in dynarec opcodes + memory access improvements in dynarec - Linux version + GUI and all plugins have been switched to GKT2 (all old plugins should be recompiled for GTK2) + detection of GTK 1.2 or GTK 2 in the configure script : if both are detected, the user can choose which one to use + configure script rewritten so that it's compatible with standard unix shells instead of bash + much improved multi-user install support : if multi-user is choosen in configure script, mupen64 should be compiled ("make") and installed ("make install"). Then, when a user launch mupen64, it will create automatically a .mupen64 folder in his home and put all required files there. + language saved and restored correctly when quitting mupen64 + the console version (mupen64_nogui) has command line support and can read settings from the gui version config file thanks to jogibear's patch + autoincrement save slot option when quick saving (thanks to jdratlif's patch) + speed limiter in the core + support for plugin configuration changes when a rom is running - Windows version + autoincrement save slot option when quick saving (thanks to jdratlif's patch) + stabilty improvements on the GUI (when closing a rom for example) + added support for readScreen function to support avi recording feature on plugins that don't use opengl or directx (ie: glide64...) - Sound plugin + thread synchronisation improvements what's new in 0.4: - A totally new core based on a dynamic recompiler with register caching, it doesn't compile the fpu yet but it's already much faster compared to older versions of mupen64 :) - Self mod code detection has been improved and emulation is faster now - A lot of little fixes that should improve compaibitlity quite a bit - A new video recording feature (record in own mupen64 movie format that can be converted later into a standard avi file) - The windows GUI has been redesigned by linker - A lot of other things i forgot... sorry :P what's new in 0.3: - All versions + General speed up, 10-20 in most games Save states long loading time fixed, now it should load in less than a second + sound sync is far more accurate now (thanks to Azimer) it makes some additionnal games booting + 64dd detection to fix F-zero + a little idle loops bug has been fixed - Windows port + Configuration and initialisation of plugins now can be done prior running a rom. It fixes numerous configuration issues with plugins as well + Recent roms menu with option to clear and freeze + Command line arguments support with option to run in GUIless mode, compatible with 1964 options, read more about it in pdf + Choosing and saving of plugins used per game, access it from Rom Properties + Reset rom menu added + Speed Modifier to allow game to run at any speed between 1-200% of original Use + and - to increase, decrease it, while in the game. And . to return to 100%. + Start game in fullscreen option + Pause emulation when idle fixes + Global plugin settings (should be unchecked if you want to use plugins per game option from rom properties) + Switch on/off ToolBar (ALT+T) and Status Bar (ALT+S), useful when plugin sets wrong resolution in windowed mode, and for those who hate toolbars :) + Selection of columns to show in rom browser + English language template updated + Support for debugview by linker Put dll in the main folder, if you want to see log output + Tonnes of little fixes... - RSP hle plugin + mario kart sound fixed what's new in 0.2: - Core + better sound plugin integration + optimizations in interrupt handling + a totally new interpreter core (half of a compiler => far much faster) it caches the opcodes when they're decoded + self modifying code detection code for the new interpreter and the compiler when it'll be implemented + RSP plugin integration + pif2 implemented for banjo tooie - RSP hle plugin + the first version of this plugin based on uhle sound code + 3 main audio ucode implemented (based on uhle) + mp3 ucode implemented (direct asm to c translation) + jpeg ucode (direct asm to c translation) + boot code for btooie and dk + on windows: ability to use the hle part of a sound plugin while using another to output the sound (example: using hle from Azimer's plugin and ouputing with Jabo's plugin) This option doesn't work with azimer's audio plugin 0.3 version Please see more info about RSP and this feature in readme.pdf in chapter "3.3.2 Configuration" - Sound Plugin for linux + a new lle sound plugin that's using the OSS api - Windows port + Major cleanup of gui code and bug fixes + Gui improvements in rombrowser + Gui changes in configuration sheets and about dialog + Updates in language support and template Dialog with proper credits to translators ,send us your translations now :) + Support for screenshots from menu (depends on video plugin) (F3 key) + Added some shortcuts for gui functions to accelerators + Option to choose directories of plugins,screenshots and save states in sheets + Auto limit VI/s according to game region (60 or 50) + Ini updated with latest N64 releases + ... what's new in 0.1: - Core + sram bug zelda oot fixed + flashram is working + a new interrupt system that'll enabled more accurate timing in the future but can cause some compatibility issues right now + bug in DMULT/DMULTU opcode fixed + some optimizations in jump instructions + sound plugins support implemented but not well supported use sound at your own risk :D + a clean tlb implementation + tlb exception handled correctly + compressed save states with slots + the whole memory map has been almost completes + newly emulated games include goldeneye, conker's bad fur day and perfect dark :) - Windows port + Zipped Cache to Rom Browser + Multy slot save states + Md5 based Ini + Rom properties dialog + Sound support + Config plugins dialog Allows you to chose and configure plugins + Multy directories in rom browser with recursion as an option + Audit roms dialog + Many bugs fixed and minor features added + ... - Linux port + A new gui made by Blight very similar to the windows one Everything in the gui is new so one line many new things ;) what's new in 0.0.90: - this is a huge update many games are playable now :) but only pure interpreter work on this release it will be fixed in the future but currently i am only working on compatibility - i have totally rewritten the pure interpreter core - nearly all missing opcodes have been added - interrupt code has been totally rewritten and should never crash now - tlb code rewritten, it's faster even if it's not perfect yet - some fpu opcodes have been debugged - fpu precision emulation improvements (only for x86 processors) - many bugs to allow port to big endian processors - fixed endianness when cpu write directly to pif ram - rewritten dma code for pure interpreter (with this core it always work now ) - update dp status register when a display list has been processed it fixed a lot of roms - implemented 8Mb RDRAM - implemented memory pack, eeprom, sram (thanks to Jabo and Zilmar for the pj64 source code on this part) - flashram is partially implemented (it's enough to get zelda2 starting) - a new debugger for linux was made by DavFR (it's for linux and it uses gtk library) - zip file support - a new gui for windows port has been made by ShadowPri, it features a rom browser with *classic* UHLE look,multy directories support , a toolbar (thx Schibo for help on it :), multy languages support, saving of configuration, .... - and much more ;) what's new in 0.0.4: - a new pure interpreter core (better compatibility but really slow, will help to debug in the future) - input plugins (a basic keyboard plugin is included and the obsidian joystick plugin ) - coprocessor unusable exception implemented - gui for windows - again many little bugs i can't remember fixed - automatic comparison between two cores via a pipe (for debugging) - .... what's new in 0.0.3: - unaligned dma exception fix - a little gui in gtk - new opcodes implemented - memory map fixes - better initial registers (this was find in the pj64 source code thanks Zilmar and Jabo) - implemented Zilmar spec Gfx plugins - included : a linux port of the tr64 plugin v0.5c what's new in 0.0.2: - MARIO64 works!!! - sound temporarly disabled (Just to not hurt your ears because hle audio doesn't work :) - various speed improvements - various stupid bugs removed what's new in 0.0.1: - everything it's the first public release :) mupen64plus-core-src-2.6.0/appveyor.yml000066400000000000000000000017131464506436200200400ustar00rootroot00000000000000version: 1.0.{build} image: Visual Studio 2022 skip_tags: true skip_commits: files: - '**/*.md' - .github/ - data/* - .gitattributes - .gitignore - .travis.yml - README configuration: - New_Dynarec_Release - Release platform: - Win32 - x64 before_build: - git tag --delete nightly-build - git clone --depth 1 https://github.com/mupen64plus/mupen64plus-win32-deps.git ..\mupen64plus-win32-deps build_script: - msbuild projects\msvc\mupen64plus-core.vcxproj /p:Configuration=%configuration%;Platform=%platform% after_build: - ps: $env:rev1 = git describe --tags - set rev2=%platform% - if "%rev2%"=="Win32" set rev2=x86 - set rev3=%configuration% - if "%rev3%" NEQ "Release" set rev3=NewDynarec - set filepkg=mupen64plus-core_v%rev1%_%rev2%-%rev3% - cd projects\msvc\%platform%\%configuration% - 7z a -t7z ..\..\..\..\build\%filepkg%.7z *.dll artifacts: - path: build\$(filepkg).7z name: $(filepkg) mupen64plus-core-src-2.6.0/data/000077500000000000000000000000001464506436200163575ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/data/font.ttf000066400000000000000000002006141464506436200200470ustar00rootroot00000000000000OS/2´_ôcëpVPCLTÑŠ^—ëÈ6cmap¤Ãè ±lXcvt ÿÓ9üüfpgmç´ñÄ&`‹gaspH glyf tAÏ&ìŠ~hdmx4ð!ìHheadÝ„¢ÐT6hheaEoëL$hmtx ÆŽ²´Ä0kernÜRÕ™½ -ŠlocaóËÒ=»„maxpG:ë, nameټȵßpost´Z/»¸ôŽprep;ñ øh::_:: dM0­l  ƒ p t › &   Y &  &   c . 5 ` õ s 0¡ & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5¸ËËÁªœ¦¸fqË ²…u¸Ãˉ-˦ðÓª‡ËªJ3ËÙôT´œ99N´R¸çÍ7sÍ`s3¢V¦V9Åɸßsºé3¼Dßͪåªˤ{¸o{RÇÍššoËÍžÓðºƒÕ˜HžÕÁËöƒT3fÓǤ͚sÕ þ+¤´œbœ-ÕÕÕð{T¤¸#Ӹ˦Ãì“ Ó\qÛ…#¨H99`Õš#fy```{œw`ªé`b{Å{´RÍf¼fwÍ;…‰{ÍJ/œœ}oo5jo{®²-–{öƒT7öœáföÍD)fîs¸€@ÿûþúù%ø2÷–öõþôþó%òñ–ð%ïŠAïþî–í–ìúëúêþé:èBçþæ2åäSå–äŠAäSãâ/ãúâ/áþàþß2ÞÝ–ÜþÛÚ}Ù»ØþÖŠAÖ}ÕÔGÕ}ÔGÓÒÓþÒÑþÐþÏþÎþÍ–ÌËÌþËÊ2ÉþÆ…ÆÅÄþÃþÂþÁþÀþ¿þ¾þ½þ¼þ»þº¹†%¹þ¸·»¸þ·¶]·»·€¶µ%¶]@ÿ¶@µ%´þ³–²þ±þ°þ¯þ®d­¬«%¬d«ª«%ª©ŠA©ú¨þ§þ¦þ¥¤þ£¢£2¢¡d ŠA –Ÿþž žþ œ›œd›š›š™ ˜þ—– —þ– •ŠA•–”“”(“’ú‘»‘þ]»€Ž%]@Ž%þŒ‹.Œþ‹.І%ŠA‰ˆ ‰ˆ ‡†%‡d†…†%…„þƒ‚ƒþ‚þ€þþ@ÿ~}}~þ}}|d{T{%zþyþxw v uþtúsúrúqúpþoþnþl!kþjBjSiþh}gBfþeþdþcþbþa:`ú^ ]þ[þZþYX YúX WW2VþUTUBTSSRQJQþP OþNMNþMLþKJKþJIJI IH GþF–E–DþC-CúB»AK@þ?þ>=>=<=<; <@ÿ; :þ9þ878ú76765 65 43 21 2þ1 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $þ#þ"!! dú d BþúBBþdþþþþBþ-B}dþ  þ   þ  þ-þdþ@-þ-þ¸d…++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++¶, °%Id°@QX ÈY!-,°%Id°@QX ÈY!-,  °P° y ¸ÿÿPXY°°%°%#á °P° y ¸ÿÿPXY°°%á-,KPX °ýEDY!-,°%E`D-,KSX°%°%EDY!!-,ED-fþ–f¤@ ûû/ÄÔì1ÔìÔì0!%!!füsüåþ–øòr)5Õ @@ƒ ü<ì2991/äüÌ0K° TX½ @ ÿÀ878Y¶ P ]%3#3#5ËËË¢þþÕýqþ›eŪéÕM@„üüÜì1ô<ì20K°TK°T[X½@ÿÀ878Y@0 @ P ` p   ¿ ]#!#oª$ªÕýÕ+ýÕ+ž¾`@1 ‡  ‡   üÌ91/<Ô<<ü<<Ô<<Ä2ì220@   ]!! !3!!!!#!#!5!!5!þÝT%Dh$i g8þ¡R>þ›h gþÛg¡hþÅ`Tþ¾if…þ²‡þaŸþašþ²™þbžþbž™NšŸªþÓm!(/Õ@U" '&( /)/))/B" ) *!††#Љ*Љ- ) " & 0ü<ìô<ü<ôäì1/äìÄÔäì2Äîî99990KSXíí9í9íY"K° TX½0@00ÿÀ878YK° TK°T[K°T[X½0ÿÀ00@878Y#.'5.546753.'>54&´diÒjfÑoÝÉÚÌd]®SS¯\ãÖãÖdtzqá{þÓ---´@AÈ$¬–£¼ëè¯*.þU#´œ©Ãš jXV`ÕþOnZXhqÿã)ð #'3•@6$%&%&'$'B’ ’.’$’ &Œ($‘4'!%   ! + 1 4üÄìôìîöî991ä2ô<äìîöîî0KSXííY"K° TK° T[K° T[K°T[K°T[K° T[X½4@44ÿÀ878Y"32654&'2#"&546"32654&%3#2#"&546ÑWccWUccUžº» º»ü—VcbWWcd1 üZ ž¼»ŸŸ¹º‘”„‚••‚ƒ•Ü»»ÛÛ»¼Ûa•‚„””„–ùó Û»½ÚÛ¼ºÜÿãþð 0Í@–  † †  † †††  !         B  (('•+•'”$‘Œ .  .'.'!!1üìÄÔÔìÆî99999991/ÆäöæîîÆ9990KSXíí9í9í9í9í9íí9í9ííí9Y"²2]@² " ) **&:4D ^YZ UZZY0g{›š™—• “••"™-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z““—•œœŸš › š 2 2°29]]3267 >73#'#"5467.54632.#"ò[UÔ _¦Iþ{ü;Bº h]ühäƒñþΆ†02Þ¸S¥UWžDiƒ;#Q¡X’Â?@ýøYËr„þþ~þã“YW×€ác?}<¢Å$$¶/1oX3gŪoÕB@ „üì1ôì0K°TK°T[X½@ÿÀ878Y@ @P`p ]#oªÕýÕ+°þò{ O@˜—  Üä2ì991üì0K°TX½@ÿÀ878YK°TX½ÿÀ@878Y#&547{†‚ƒ… –•”—æþ>ççþ;åëÆàßÄì¤þòo @˜— Ü<ôì991üì03#654¤ –••– …ƒƒìþ<ßàþ:ëåÅççÂ=JÃðN@,  ™ ™ ‘    Ô<ä2Ü<ä2991ôÔ<ì2Äì2990%#'%%73%Ãþ™g:þ°rþ°:gþ™:PrPßÂÃbËþ‡yËbÃÂcËyþ‡ËÙÛ #@ œ  Üü<ü<ì1/Ô<ü<Ä0!!#!5!®-ýÓ¨ýÓ-ýÓªýÓ-ª-žÿÃþ@ žƒüìÔÌ1üì073#ðÓ¤Rþ¬þÀ@d߃¶œÜÌ1Ôì0!!dý僤ۮþ·ƒüì1/ì073#ÛÓÓþþÿB²Õ-@BŸ/Ä991ôì0KSXííY"3#ªýøªÕùm‡ÿãð #@   ‘Œ üìôì1äôìî0"32'2#"‹œœû þ÷ûûþ÷ PþÍþÌþÍþÍ3343 þsþ†þ‡þsyzáZÕ K@B     ÔìÄüì1/ì2ôìÔì0KSXY"K°TX½ ÿÀ @878Y´]7!5%3!!þJþ™eÊJü¤ªsH¸HúÕª–Jð¥@'B¡”  ‘   üÄÔìÀÀ91/ì2ôìôì0KSXíí9Y"K°TK°T[K°T[X½@ÿÀ878Y@2UVVzzv‡tvust‚†‚‚‚¨¨]]%!!567>54&#"5>32‰ÁüLs3aM§†_ÓxzÔXèE[þôªªªw‘:m—Iw–BCÌ12èÂ\¥pþëœÿãsð({@. † †     “  “#‘Œ£)&  )üÄÄÔìôì991ìäôäìæîîîî90K°TK°T[X½)@))ÿÀ878Y@ daa d!]!"&'532654&+532654&#"5>32?‘£þÐþè^ÇjTÈm¾Ç¹¥®¶•ž£˜S¾rsÉYæ Ž%ÄÝò%%Ã12–„•¦wps{$&´ Ѳ|«d¤Õ Œ@   B     ÜÔ<Äì291/äÔ<ì290KSXÉÉY"K° TK° T[X½@ÿÀ878Y@* *HYiwŠ+&+6NO O Vfuz… ]] !33##!5þþ5þÕÕÉý^%üãÍü3¨þ `ÞÿãdÕu@#†  ‰   Œ¤  üÄÔìÄî1ääôìæîþÄî90K°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y!!>32!"&'532654&#"Ýý ,X,ú$þÔþï^ÃhZÀk­ÊÊ­Q¡TÕªþ’þîêñþõ Ë10¶œœ¶$&ÿã–ð $X@$ †   ¥  ‰"‘Œ% " !%üììôìä1äôäüäîîî90@ËËÍÍÍËˤ²]]"32654&.#">32# !2¤ˆŸŸˆˆŸŸ L›LÈÓ;²káþðâþýþîPL›;º¢¡»»¡¢ºy¸$&þòþïW]þïëæþêyb¥¨hÕc@B üÌÄ991/ôì0KSXííY"K°TX½@ÿÀ878Y@X9Hg°°]]!#!¨ÀýâÓþý3ÕVú+‹ÿã‹ð #/C@%  ' - ‘Œ'£0 $*$ !0üÄìôÄìîî991ìäôìîî990"32654&%&&54632#"$54632654&#"‹¥¥¦¥þ¥‚‘ÿÞßþ‘’£þ÷÷÷þ÷¤H‘ƒ‚““‚ƒ‘Åš‡‡š›†‡šV ²€³Ðг€² "ÆÙèèÙÆat‚‚tt‚‚ÿã‡ð$X@#†  ¥ ‰ ‘Œ%!"" %üìäôìì1äôìæþõîî90@ÄÂÀÀÀÂμé]]7532#"543 !"&2654&#"áLœKÈÓ:²làþûâþ±þåLœ>ˆŸŸˆˆŸŸ¸$& V\ëæþsþ†þŸþ[—º¢¡»»¡¢ºðÃ#@ƒ¦ƒü<ì21/ìôì073#3#ðÓÓÓÓþþ#þžÿÃ# %@ƒžƒ¦  ü<ì2ÔÌ1äüìî03#3#ðÓÓÓ¤R#þýÙ¬þÀ@Ù^Û¦M@*œœœœB¨§$#üì291ôì90KSXííííY" 5Ûûøúþðþ‘þ“¶ѦÑÙ`Û¢@ œœ#ü<Ä21ÔìÔì0!!!!Ùúþúþ¢¨ðªÙ^Û¦O@+œœœœB¨§$#ü<ì91ôì90KSXííííY"55Ùúþð¶þ/¦þ/¶m“°ð$p@+$  †ˆ•‘ƒ   &%ÜÄüìÔìî99991/îöþôîÍ9990K° TX½%@%%ÿÀ878Y¶y z z ]%3##546?>54&#"5>32‡ËËÅ¿8ZZ93ƒlO³a^Ág¸ßHZX/'þþ‘še‚VY5^1YnFC¼98ŸL‰VV/5<4‡þœq¢ L•@2  ©©L43¬0©7¬$©7CM34( (+(I+*(I,=MÜìüìþýþ<Æî991ÔÄüìþíÔÆÅî2Äî990K° TK° T[K°T[K°T[K°T[X½MÿÀMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32úŽ|{zy!<›g¬×Ø«gœ;’¥?@hþÕ°{â`±smiùhZ}þÙ˜¹þ¸€€†ˆ~R½Ôk{KOþÂþè£¤ŽŒ¥¤þHMIùÈÈúKLƒý ß±k¼Pƒ‹A@fþµÁŸþêjhmWQoagƒ}}I½¶J}‡® bæ{þùþÐhÕ º@A       B•    ÔÄ91/<äÔì90KSXííííííííY"² ]@:XvpŒ VXP ghxv|rwx‡ˆ€ ˜™–]] !3#!#¼þî%þ{å9Òˆý_ˆÕý®ú+þÉìÕ C@#• •• ­ . !üì2üìÔì9991/ììôìî90²"]!2654&#!2654&#%!2#!“D££þ¼+”‘‘”þ çú€|•¥þðûýèÉý݇‹Œ…fþ>orqp¦À±‰¢ ˘ÈÚsÿã'ð6@ ¡® •¡®•‘Œ 0üì2ì1äôìôìîöî0´].# !267# !2'fç‚ÿþð‚çfjí„þ­þz†S†íbÕ_^þÇþØþÙþÇ^_ÓHHŸghŸGɰÕ.@• •  2 üìôì99991/ìôì0²`]3 !%! )“ô5þáþËþBŸ²–þhþPþa/ûw.,¦þ—þ€þ~þ–É‹Õ .@•••­   üì2ÔÄÄ1/ììôìî0² ]!!!!!!ɰýÇý9øü>ÕªþFªýãªÉ#Õ )@••­ üì2ÔÄ1/ìôìî0² ]!!!!#ÉZýpPý°ÊÕªþHªý7sÿã‹ð9@ ••¡®•‘Œ43 üìüäüÄ1äôìôìþÔî990%!5!# !2&&# !26Ãþ¶uþæ þ¢þu‹^’opü‹þîþík¨Õ‘¦ýSU™mn™HF×_`þÎþÑþÒþÎ%É;Õ ,@•­ 8  üì2üì21/<ä2üì0²P ]3!3#!#ÉÊÞÊÊý"ÊÕýœdú+Çý9É“Õ9·¯üì1/ì0K°TX½ÿÀ@878Y@ 0@P`Ÿ]3#ÉÊÊÕú+ÿ–þf“Õ M@ •° 9 üìä991äüì990K°TX½ ÿÀ @878Y@ 0 @ P ` Ÿ ]3+53265ÉÊÍãM?†nÕú“þòôª–ÂÉjÕ ï@(B¯  üì2ÔÄ91/<ì290KSXííííY"²]@’ ((764GFCUgvwƒˆ”›ç    (+*66650 A@E@@@ b`hgwp ‹‹Ž š¶µÅÅ×Öèéèê÷øù,]q]q3! !#ÉÊžýþöý3ÊÕý‰wýHüãÏý1ÉjÕ%@ •:üìì1/äì0@ 0P€€]3!!ÉÊ×ü_ÕúÕªÉÕ ¿@4  B ¯   >  üìüì91/<Äì290KSXííííY"²p]@V   && & 45 i|{y €‚‚  #,'( 4<VY ej vy •›]]! !###É-}-ÅþËþÄÕüøú+üúáÉ3Õ y@B¯6 üìüì991/<ì2990KSXííY"² ]@068HGif€ FIWXeiy…Š•šŸ ]]!3!#É–ÄþðýjÄÕûáú+áûsÿãÙð #@•• ‘Œ 3üìüì1äôìî0"32' ! 'ÜþýÜÜþÿÜ:xþˆþÆþÅþ‡yLþ¸þåþæþ¸HH¤þ[þžþŸþ[¤bb¥ÉÕ:@••   ? üì2üì91/ôìÔì0@ ?_¯]32654&#%!2+#“þššþ8ÈûþÿûþÊ/ýÏ’‡†’¦ãÛÝâý¨sþøÙð R@*  B ••‘Œ    3üìüì9991Ääôìî990KSXíí9Y""32#'# ! 'ÜþýÜÜþÿ? ôÝ!#þÅþ‡y;:xÑLþ¸þåþæþ¸HHúÏþÝï¥ab¥þ[þžþüþŽÉTÕ±@5  B• •   ?  üì2üÄì99991/<ôìÔì9990KSXíí9Y"²@]@Bz%%%&'&&& 66FFhuuwˆˆ˜˜]]#.+#! 32654&#A{>ÍÙ¿J‹xÜÊÈüƒý‰þ’••’¼~þh–bý‰ÕÖØºOýƒ…‡ÿã¢ð'~@<    B ¡”••”%‘Œ( "-"(ÜÄìüìä99991äôäìîöîÆ90KSXí9í9Y"²)]¶)/)O)].#"!"&'532654&/.54$32HsÌ_¥³w¦zâ×þÝþçjï€{ìr­¼‡š{âÊõiÚ¤Å76€vce+Ù¶Ùà0/ÐEFˆ~n|-À«Æä&ÿúéÕJ@•@@Ôäüä1/ôì20K° TX½@ÿÀ878Y@  @ p Ÿ ]!!#!ïýîËýîÕªúÕ+²ÿã)ÕK@ •Œ  8Aüìüì1ä2ôì99990K°TX½@ÿÀ878Y¶Ÿ]332653! ²Ë®Ã®ËþßþæþåþßÕüuðÓÓð‹ü\þÜþÖ*$hÕ·@'B¯ÔÄ91/ì290KSXííííY"²P]@b*GGZ}ƒ *&&))% 833<<7HEEIIGYVfiizvvyyu€˜—)]]!3 3JýÆÓÙÚÒýÇÕûéú+D¦Õ {@I      B ¯    ÔÌ91/<ì2290KSXííííííííY"²]@ò  ($ >>4 0 LMB @ Yjkg ` {|€ –•     !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx  †‡ˆ‰… Š —Ÿ¯[]]3 3 3# #DÌ:9ã:9Íþ‰þþÅþÂþÕûîûîú+úð=;Õ ]@F      B ¯   ÔÄÜÄ91/<ì290KSXííííííííY"K° TK° T[K°T[X½ ÿÀ @878Y@¸ '' 486 KX[fkww †€‡‹… ”—–     &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x €€ƒˆ…„ƒ ”——•“ Ÿ ¯ @]]3 3 # #ÙsuÙþ Ùþ\þYÚÕýÕ+ý3üø{ý…ÿüçÕ”@(B¯@@ Ôäüä91/ì290KSXííííY"² ]@<5000F@@@QQQe„“ &)78@ ghxp Ÿ ]]3 3#Ùž›ÙýðËÕýšfüòý9Ç\Õ ›@B••B ÜÄÔä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878Y@@ )&8HGH    / 59? GJO UYfio wx Ÿ ]]!!!5!s•üPÇû=°ügÕšûoªš‘°þòXS@©²©±CÜüÌ21üìôì0K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y!#3!°¨ððþXùüÿB²Õ-@BŸ/Ä991ôì0KSXííY"#ªªýøÕùm“Çþòo<@©²©±Cü<Üì1üìôì0K°TK°T[X½ÿÀ@878Y!53#5oþXïïøÞÙ¨ÛÕ@ ÜÌ91ôÌ290##¼ÉþHþHÉÕýÓ‹þu-ÿìþþ¬µ©ÄÄ1Ôì0!5ûØþ¬ªð‰f1@ ´³DÜì1ôì0K° TK°T[X½ÿÀ@878Y #o™þºfþŠv{ÿã-{ %¼@'  ©¹ †º¹#¸Œ   E&üìÌÔì22991/ÄäôüôìÆîî9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p'…‡‡‡ ‡!…"' 'ð'000 0!@@@ @!PPP P!``` `!ppp p!€€€ €!]]"326=7#5#"&5463!54&#"5>32¾ß¬o™¹¸¸?¼ˆ¬Ëýû§—`¶Te¾Zóð3f{bsÙ´)LýªfaÁ¢½À‹..ª''üºÿ㤠8@¹  ¹Œ¸—G Füì22ôì1/ìäôÄìÆî0¶`€ ]4&#"326>32#"&'#3å§’’§§’’§ýŽ:±{ÌÿÿÌ{±:¹¹/ËççËËççRdaþ¼þøþøþ¼ad¨qÿãç{?@†ˆ† ˆ ¹¹¸Œ HEüä2ì1äôìþôîõî0@ € ].#"3267#"!2çNP³ÆÆ³PNM¥]ýþÖ-U¢5¬++ãÍÍã++ª$$>:#qÿãZ8@¹¹Œ¸—G Eüìôì221/ìäôÄìÄî0¶`€ ]3#5#"3232654&#"¢¸¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶^ùì¨daDDaþËççËËççqÿã{p@$ †ˆ©¹ »¹¸ ŒKEüìôìÄ91äôìäîîôî90@)?p Ðð?????,// , ooooo ]q]!3267# 32.#"ü² Í·jÇbcÐkþôþÇ)ü⸥ˆš¹^Z¾Ç44®*,8 CþÝÄ—´®ž/øp@ ©‡—¼    Lü<Äü<ÄÄ991/ä2üìî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y¶@P ]#"!!##535463ø°cM/þѹ°°®½™Phcü/ÑN»«qþVZ{ (J@#  †¹¹&#¸'¼ ¹½& G E)üÄìôì221/ÄäìäôÄìþÕî990¶`*€* *]4&#"326!"&'5326=#"3253¢¥•”¥¥”•¥¸þþúa¬QQžRµ´9²|ÎüüÎ|²9¸=ÈÜÜÈÇÜÜëþâþé³,*½¿[cb::bcªºd4@ ‡¸ — N  Füì2ôì1/<ìôÄì90²`]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡ýžedïÁy+@¾±¼Fü<ì21/äüì0@  @ P ` p ]3#3#Á¸¸¸¸`û éÿÛþVy D@ ¾ ‡½¼ ±O  Fü<ì2ä991ìäôìî990@ @P`p]3+532653#Á¸£µF1iL¸¸`ûŒÖÀœa™(麜 ¼@)B¼— F üì2ÔÄ91/<ìä90KSXííííY"² ]@_ ')+Vfgsw‚‰Ž“–—£    ('(++@ h` ‰…‰š—ª§¶ÅÖ÷ð÷ð]q]33 ##º¹%ëý®kðýǹüiãýôý¬#ýÝÁy"·—Füì1/ì0@ @P`pð]3#Á¸¸ùìº{"Z@&  ‡ ¸¼PPF#üì2üüüì91/<<äô<Äì290@0$P$p$$ $ $¿$ß$ÿ$ ]>32#4&#"#4&#"#3>32)EÀ‚¯¾¹ru¦¹rw¦¹¹?°yz«‰|võâý\ž¡œ¾¤ý‡ž¢›¿£ý‡`®gb|ºd{6@ ‡¸ ¼ N  Füì2ôì1/<äôÄì90´`Ï]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡`®edïqÿãu{ J@¹¹ ¸Œ QEüìôì1äôìî0@#?{{   {  { ð]"32654&'2#"s”¬«•“¬¬“ðþîðñþïßçÉÉçèÈÇéœþÈþìþíþÇ98ºþV¤{>@¹¹¸Œ½¼ GFüì22ôì1äääôÄìÄî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý® ªdaþ¼þøþøþ¼aëËççËËççqþVZ{ >@¹  ¹¸Œ½¼ GEüìôì221äääôÄìÆî0@ `€ à]32654&#"#"3253#/§’’¨¨’’§s:±|ËÿÿË|±:¸¸/ËççËËççý®daDDadªùöºJ{0@  ‡¸ ¼ FüÄì21/äôìÄÔÌ90´PŸ].#"#3>32JI,œ§¹¹:º….´˾ý²`®fcoÿãÇ{'ç@<  S  SB †‰†‰¹¹%¸Œ( R"E(üÄìÔìä99991äôìþõîõî90KSXí9í9Y"²']@m   . , , , ; ; ; ; $( ( *//*(() )!$'† † † †      '/)?)_))€)) )ð)]]q.#"#"&'532654&/.54632‹N¨Z‰‰b”?Ä¥÷ØZÃlfÆa‚Œe«@«˜àÎf´?®((TT@I!*™‰œ¶##¾55YQKP%$•‚ž¬7òž8@©¼‡  Fü<Äü<Ä2991/ìô<Äì2990²¯]!!;#"&5#53w{þ…Ks½½Õ¢‡‡žþÂý ‰NšŸÒ`>®ÿãX`6@ ‡Œ ¼  NFüìôì21/ä2ôÄì90´`Ï]332653#5#"&®¸||•­¸¸C±uÁȺ¦ýaŸŸ¾¤{û ¬fcð=`@'B¿ÔÄ91/ì290KSXííííY"K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@ŽHj{†€‘¤  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz……‰‰‰†––—š˜˜—¨§°Àßÿ>]]3 3#=Ã^^Ãþ\ú`üT¬û V5` @IU U U U   B ¿    ÔÌ91/<ì2290KSXííííííííY"K° TK°T[K°T[K°T[K° T[X½ ÿÀ @878YK° TK° T[K°T[X½ @ ÿÀ878Y@ÿ" 5 IIF @ [[U P nnf yy‡™˜” ¼¼ÎÇÏ         %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } ‡ˆ——”“œ›˜˜™@/– Ÿ¦¦¤¤««©©«¤ ¯µ±½»¸ ¿ÄÃÌÊy]]333# #V¸æåÙæå¸þÛÙñòÙ`ü–jü–jû –üj;y` Z@F      B ¿  ÔÄÔÄ91/<ì290KSXííííííííY"K° TK°T[K°T[K°T[X½ ÿÀ @878YK°TX½ @ ÿÀ878Y@˜   & =1 UWX f vzvt ‚ ™Ÿ—’ ¦©¯¥£       )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x ›”«¤° Ï ß ÿ /]] # # 3 dþkªÙþºþºÙ³þrÙ))`ýßýÁ¸þHJþq=þV`¢@C        B  ‡½ ¼  ÔÄÄ91ä2ôì9990KSXíííííí2Y"K° TK°T[X½ÿÀ@878YK°TX½@ÿÀ878Y@ð     # 5 I O N Z Z j ‡ € “        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx‰Š … … ‰ ‰‰™ • • šš¤ ¤ ««°Ïßÿe]]+5326?3 3“N”|“lLT3!þ;Ã^^ÃhÈzšH†TNü”lXÛ` ´@B©¼© ÜÄ2Ä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878YK°TX½ ÿÀ @878Y@B&GI  + 690 @@E@@CWY_ ``f``b € ¯ ]]!!!5!qjýL´ü}´ýe`¨üÛ“¨%þ²$‚@4 %   ! © ©À ©±% $  C %Ô<Äü<Ä299999991üìÄôìî99999990K° TX½%ÿÀ%%@878Y²&]#"&=4&+5326=46;#"3>ù©lŽ==k©ù>DV[noZV¾”Ýï—ts•ðÝ“XøŽŽœøXþ®·±Ôì1üÌ0#®ªøþ²$ž@6%   ©©#À©±%#C %Ô<Ä2ü<Ä99999991üìÄôìî99999990K° TX½%@%%ÿÀ878YK°TX½%ÿÀ%%@878Y²&]326=467.=4&+532;#"+FŒUZooZUŒF?ù§lŽ>>Žl§ù?¾VøœŽŽøŽW“Ýð•st—ïÝ”ÙÓÛ1#@ œœ ÔÄ1ÔüÔìÀ990#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©1²OD;>MS²OE<>LÿÿhN'$¼uhm !Ë@T   !!  ! !!!B  Á • Ž  !  VV!"ÔÄÔì2Ôî299999991/<æÖîÔî9990KSXííííííííY"² #]@  s › P#f iu {yyv v!€# ]]4&#"326!.54632#!#TY?@WX??Y˜þð!þX=>Ÿsr¡?<Òˆý_ˆÕZ?YWA?XXþóýN)sIs ¡rFv)ú‹þÿÿsþu'ð'&Ý-ÿÿÉ‹k'(žuÿÿÉ3^'1þuÿÿsÿãÙN'2'uÿÿ²ÿã)N'8îuÿÿ{ÿã-f'DRÿÿ{ÿã-f'DCRÿÿ{ÿã-f'D×Rÿÿ{ÿã-'DŽRÿÿ{ÿã-7'DØRÿÿ{ÿã-'DÜRÿÿqþuç{'FÝÿÿqÿãf'H‹ÿÿqÿãf'HC‹ÿÿqÿãf'H׋ÿÿqÿã'HŽ‹ÿÿof'ÖÿÿÿÿǦf'ÖCÿÿÿÿÞ\f'Ö×ÿÿÿÿôF'ÖŽÿÿÿºd7'Qؘÿÿqÿãuf'Rsÿÿqÿãuf'RCsÿÿqÿãuf'R×sÿÿqÿãu'RŽsÿÿqÿãu7'RØsÿÿ®ÿãXf'X{ÿÿ®ÿãXf'XC{ÿÿ®ÿãXf'X×{ÿÿ®ÿãX'XŽ{9ÿ;ÇÕ '@¹  YW Y Ô<ìü<ì1äôÔ<ì203!!#!5!¨°oþ‘°þ‘oÕþ\™û£]™Ãu=ð  @ÃÄà ‘ Z[ZÜìüì1ôìüì0"32654&'2#"&546PnnPPnoO@v+..¹†‡´¸ooPOmmOOp1.-rB„·´‡†º¬þÇ#˜!Q@+  †ˆ †ˆ ¹ ¹¸Œ"  "ÜìÔ<Ô<<ì221äô<ÄìÄþôîõî9990%&&'667#&73¦“¤¤JˆDF‰HA‰Mfñþ÷ ñfI‰ƒX⸹⡬)*ü *'ª#þä 32þá!bð`@!† ©  ”‘   Ü<ÌÌü<ÄÔÄ1/ì2ôäìÔ<î2î990K° TX½ÿÀ@878Y´66].#"!!!!53#535632NLˆ=”t‡þy-üìÇÇÖè=—´¶))›Ô×þ/ªªÑîó\ÿ=¢ð >‘@54&.#"#"&'532654/.5467.54632{?>‹ú?>ÌS8alÎÓƒ\]>9Ì­IšXW”:fqÝÖ€][;;ȦI™¨.Z.L…‡-[.Kˆ“¤''PGZswšeZŒ54m@ލ¤''TLf{x™f[1,pE‚Ÿ3Ñ…! · Ç \ Ôì1Ôì04632#"&3­~|«¬}}¬ú|««|}¬¬žÿ;9Õ %@Á]] ÔÔüÜì91Ä2ôì90!###&&54$yÀ¾Ž×ëÕùfùáNݸ¾èºÿã¬/š@0-'!  *†¹*¹—Œ.  !' $'$-F0üÄüÌÆîÔîî99991/äþîþÕî990@@'(Š Š     ! "&  : :!MM I!I"jj ¥¥¦ ]]4632#"&'532654&/.5467.#"#ºïÚÐÛ—¨:A9¦`áÓ@ˆIPŒAtx;e\`W§—ƒq‚ˆ»qÈÛèàs`/Q*%jŽd¬·¤_[?T>7;‡[¬gp‹ƒû“åÍ/8L`@6EBC?2ÉH0É9JCÊ 9ÊÉÈ É$HE301BKL?gwyVpMIßÑ`3þœDåÍ/IC@&=Ë>:ÌAÊ$1Ë04ÌGÊÉÈ$É 7aD=0^* D^ JÜÌüìþí2î1/îöþýîÖîýîÖî02#"$'&5476$"32676654&'&&&&#"3267#"&54632˜mmllmmþù˜˜þùmmllmm˜ƒâ^^``^^⃄ã^]]^\^ã§B‚B•§«›@zBC‰FØûûØIˆÍnmmþúš˜þûmmnnmm˜šmmng^^^å‚ã^^__^]⃅ã]^^õ! ¯Ÿ®"ôÐÑò'“FÕ >@!  É  b b cbcÔäüäÔìÔì91ô<<ì2Ô<<Ä903#######5J®¤ªqÃ7ËrqËrÉÕÿý¾äþÑ/þB^þä^sîRf1@ ´³DÔì1ôì0K° TK°T[X½ÿÀ@878Y3#‹Çþº™fþˆ×F)’@ÎÍddÜüÔì1ü<ì20K° TK° T[X½@ÿÀ878YK° TK° T[K°T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@````pppp]3#%3#^ËËþyËËÊÊÊÙ'ÛÝ>@" Ïœ Ï œ  Ü<Ä291Ô<Ì2ü<ìþ<ì990!!!!!'7!5!7!Ù}®/þHÃ{üúþþ}®þÕ¶Ãý‡¢;fÕ¨ðªþÇfÓªðHÕ‡@9  B• ••••­    ÔÔ<ì2ÔÄÄ91/<ììÄôììîî0KSXííííY"²€]@gww† …– ¿ ]!!!!!!#!5ýÇý9øü=ýð Íq‹þ¶ËÕªþFªýãªþÕžüðfÿºå +ž@< +,  )&  *&•& •‘&Œ,+,* # )#3,üìüìÀ999999991äôìîÀÀ99999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''¶ý3>¡_Ü'y=¡_Üþý''†NOy;‚ÝW¢fªNPþˆþÆ€Ý[¢gXü²@CHp¸¸@Cþ¸þåp¼Džf b¥MK¿YÆgþöžþŸþ[KK¿XÝÝÏî /ÿ@- !$'!!0 $*0ÔÄÔÄ99991ÔÄÔÄÀ9990@¾     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV´° °!°"°&°'°(´)]]32654&#".#"326#"&54632>32#"&“1†Te€vYR…Ä1…UfvYR†F^ˆº§†_™HDža†¼§†^•/XZ‡ie†‡7XX„je†ˆ‡ߦ¯Ø~ŠŠƒá§¯ÖwÙÛ .@МР œ   Ô<ì2ü<ì21/ìÔ<ìü<ì0!!#!5!!!®-ýÓ¨ýÓ-ýÓúþþ}ªþ}ƒªƒû¦ªÙÛ¨ T@.œœœœBѧœ $# ü<ì2291/ìôì90KSXííííY" 5!!Ûü@Àúþúþúþøþëþî²pªoüªÙÛ¨ V@/œœœœBѧœ$ # ü<<ì291/ìôì90KSXííííY"55!5ÙúþÁAúþø°þ‘ªþ²ýǪªRÃÕÆ@F  B Ó Ó   fe f eÔ<ì2ìüì2ì99991/ä2Ô<ì2Ô<ì290KSXííííY"K° TX½ÿÀ@878Y@(†¦ µ' ' ')((79‡ ˆ¦ ¥ª©]]!#!5!5'!5!3 3!!!þcÉþ` Tþ´þþ{y¿þÂþµTŸÇþ9Ç{3›{JýD¼ý¶{›3®þVå` M@% ‡Œ ¼½!   NF!üì2ôìÄ91ää2ô<ìÜÄ990¶"`"Ï"]3326533267#"&'#"&'®¸Š‡”•¸#% )I#ER2‘bf*þV ýH‘”¨¨ü¢<9 ”NPOONNý×hÿçÁ-)b@'! '!Õ* $$*ÔÌÜÌ9991äÌÜÌÎÎ990K° TK° T[K°T[K°T[K°T[X½*@**ÿÀ878Y>54&#"#"&54632#"&54324&#"32ôIH7$$0e´ÖþßÕ˜ËÝ¢e‚ WOmVPmmW£Kƒt,>bþÊþùþ±þFØ£Æ[àt}þþÏt{þw;Á ]@    ÔÄ91ÄÔÌÎ990@0QVPZ spvupz €€ Z pp{ t €€ ]]!! !!5 7êüA ýJïúÞÕýIÁÁý3ýÀ•!ãœþwqÁ@×Ö¯ggÔìÔì1üìì20!#!#œÕðý ïÁø¶}ùƒÿáÿðª/#Ë@1 ÚÙ"ØÕ $ #" #h#$ÔÔÔì9999991/<äôì22î9990K° TX½$ÿÀ$$@878Y@V             ##(]]#3267#"&5467!##"#>3!‡¶i/7.%7vy"PþºÂµÃ)6<  ¥y‘þJ\:1fd.¡xüo‘@E¦}/þú%&@ Û Ûܱ& iji&Üìüì1üìÜäÞä026732#"&'&&#"#"&546327j ¾ÊPd@7*8  k½ÄOeD=!0 þú°l9¼TA6?&#Hý•Ánþ!þbSA8?SsÕ;ð)_@3(%ãÝá%Ý ßÞÝ à‘* "(kl"k *ÜìÌüì22ÀÀ9991ôäüôìÄîíÖîî99990!!#5#"&5463354&#"56632"32655‹°ýP®•,]€˜¿¼¶uu>ˆDI‘E·³þì¡~bRh‚P{¸þ@p?D‡q‡Š[[""°ðCO@Mr`Õdð.@ãáÝ àÝ‘ klk Üìüì991ôìôìüì0!!2#"&546"32654&‹°ýPX³Îγ³Ðгi~hi}|P{Ý¿¿Ûܾ¿Ýs¡ˆ…  …‰ NÏç@@" å‘å  mm  ÔììÔììÀÀ9991/<ì2ôì0%!5654#"!5!&5! Ïý¨±ÆþøØØþ÷Dzý¨?ž‘1/Ž¡²²²aLÊð"þÝïÊþ´a²²‹*¸>ŠþwþËÂþØ{ÿão{3>@C'-%= 4©%†ˆ©:¹.†-º*¹»1 ¸Œ%?47&%7& =&-7"E?üìÌÔü<ÔìÄ999991Ää2ô<Ääü<ôìÄî2îôîî9990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0…+…0€@@ @°@À@Ð@à@à@ð@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/€,€-€.€/]q].#">32!3267#"&'#"&5463!54&#"5>32"326=¶¥‰™¹DJÔ„âü² Ì·hÈddÐj§øMIؽÒýû§—`¶Te¾ZŽÕï߬o™¹”—´®ž0Z^þÝúZ¿È55®*,ywxx»¨½À‹..ª''`þf{bsÙ´)Hÿ¢œ¼ +ä@<+,&  )&  *&¹& ¹¸&Œ,+,* # #Q)E,üì2ôì2À9999991äôìîÀÀ99999990@p(?-YVUV jf!{    { z{ {!"#$%{&›•%¨ -ð-&YVUZ(ifej(ztvz(‰•š$¢­$]] 32654&'.#".5327#"&''‰þ)gA“¬\*g>—©}66ñ]ŸC‹_’56þîð`¡?‹`!ý°*(èÈOuš))ëÓHn.—MÅw834¨O³MÆxþíþÇ43¨Nÿã¬Õ $†@/ †ˆ !ƒ# •Œ#%" " "!& %ÜìÔüìÔì99991äôìþÍôî9990K°TK°T[K°T[X½%ÿÀ%%@878Y@ ttttv]33267#"&546?>7>5#53ô¾7ZZ:3ƒmN´`^Àg¸àIYX0&ÄÊÊDœe‚WX5^1YnFC¼98ŸL‰VV/5<6þ5Õ b@ƒ ü<ì2991/ôüÌ0K° TX½ @ ÿÀ878YK°TK°T[K°T[X½ ÿÀ @878Y¶ P ]#53#3ËËË¢×þú+eþ›ÙÛ^@ œÜÔì1ÔÄì0!#!Ù¨û¦^ýÁ•=ÿ×} *@    ÔÌ91ÔÌÄ903##'%\½sý®BþÁ}}`ùºs-Pbý;þV#Š@@   B   ©Šæ©Šæ©!—$  $ÔÌ91Ä2Äüìôìîöîî299990KSXí2í9Y"K° TX½$ÿÀ$$@878Y.#"!!#"&'53267#5!>32&P,`r<þÃ:¼º:d/4a/am"‰ø?$Æ—5dð¤z„þÉý…þãÓ¦!!‰¦­J·ÃÙÛô;?@.9*-" *œ19œ"œ œ<-<Ô<Ä21ÔìÔìÜüÔìÀ9999990#"'&'&'&#"56632326#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©gi³an’ ›^X¬bi³an“ ›^V©o³NE;=LT³NE;=KÚ²OE;=LS²NE;=Kÿú`Á8@ÔÌ91/ÄÌ90@cmpxyvn]] !3!¬þ^DýïàCúšîûÄú?ž%# †@Ièèèè è è è  è B  ç¦ o o nüü<Ôì2991ô<ì2990KSXííííííííY"55%þÓ-þ+#þÓ-þ+#¿þôþô¿¢R¢¿þôþô¿¢RÁH# †@I è è è è èèèèB  ç¦ o opü<üÔ<ì991ô<ì2990KSXííííííííY"5%5ÁÕþ+-þÓ²Õþ+-þÓ#þ^Rþ^¿  ¿þ^Rþ^¿  ìþ #@ƒ   ÔüÔìÔì1/<<ì220%3#%3#%3#–ÔÔ©ÕÕú­ÕÕþþþþþþÿÿhk'$¼uÿÿh^'$¼uÿÿsÿãÙ^'2'us Õ;@•••­   üìÔÄÄÔì299991/ìì2ôì2î0!!!!! !# !3úýÇý9øû×þOþA¿±gþ¿þÀ@AÕªþFªýãª|pm|ªþáþàþßþßqÿãÃ{'3„@1†ˆ ©. ¹(¹»"%¸Œ4"1 K1 Q+E4üìôüôìÄ9991ä2ô<Ääì2Äî2îôî90@%?5_5p5Ÿ5Ï5Ð5ð5????? ooooo ]q].#"!3267#"&'#"32>32%"32654& ¤‰™¹Hü² Ì·jÈbdÐj òQGÑŒñþïñŒÓBNèâú°”¬«•“¬¬”˜³®ž5Z¾Ç44®*,nmnm98olkpþ݇çÉÉçèÈÇééy¶©é/Æ1üì0!!üyéyµ©/Ì1Ôì0!!øy®émÕ '@ž   ÜüÌÔÌþÔÎ1ô<ì20#53#53Ó¤RšÓ¤Ré­?þÁ­­?þÁ®émÕ '@ ž  ÜìÔÌÜîÔÎ1ô<ì203#%3#Ó¤RšÓ¤RÕ¬þÀ@¬¬þÀ@®éÓÕ@ žÜüÔÌ1ôì0#53Ó¤Ré­?þÁ²þ×Õ@ žqÜìÔÌ1ôì03#Ó¤RÕ˜þÁ?Ù–Ûo )@êêœ r ÜÔ<ü<Ä1ÔÄüÄîî03#3#!!ßööööýúúþoöþõAªþ#îu"@ÔÌ91ÔÌ990 úþþôþ þ üÏüÇ9%ûÛûÓ-ÿÿ=þV'\Ž^ÿÿÿüçN'<suþ‰ÿãÍð+@BŒ‘ÔÌ1ää0KSXííY"3#- ü\ ðùó^R¼²#/ƒ@I -'! - -¹ëì'¹ë!0 *$0* $ $(st*(s0Üäìôäì9999999991ÔäìôäìÀ9999999907'#"&''7&&5467'766324&#"326{ÏrÎ%$&(ÑrÏ;t=:x=ÏqÏ%%&&ÏsÏ7t@?s9ÏqÏ(&%%ÏsÎ>v:@t8ÎsÏ'%$þ|pššprœžs#G@%èèèèBç¦onüì291ôì90KSXííííY"5sþÓ-þ+#¿þôþô¿¢RÁ–#I@&èèèèBç¦opü<ì91ôì90KSXííííY"5ÁÕþ+-þÓ#þ^Rþ^¿  /J›@( ©‡¾±— ¼ Lü<Ä2Äü<Äî2991/<æ2îþîîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€€€ Ðï]]#!##53546;#"3#J¹þ¹°°­³¹°cMù¹¹`û Ñü/ÑN·¯™Phc²é/J„@! © ‡— ¼   Lü<ÄÄü<Äî991/<æ2þîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€ € € Ðï]!#!"!!##53546J¹þ·cM/þѹ°°®ùì{Phcü/ÑN»«9ÿ;ÇÕ>@ ¹¹  ÂY W Y Ô<<ì2ü<<ì21äôÄ2Ä2î2î20%!#!5!!5!3!!!Çþ‘°þ‘oþ‘o°oþ‘oßþ\¤š™¤þ\™ýáÛH®F·ƒÔì1Ôì03#ÛÓÓFþ®ÿÓþ@ žƒÔìÔÌ1üì0%3#Ó¤Rþ¬þÀ@®ÿmþ '@ žƒ   ÜìÔÌÜîÔÎ1ü<ì20%3#%3#šÓ¤RþfÓ¤Rþ¬þÀ@¬¬þÀ@qÿã Lð #'3?K®@D$%&%&'$'B@’ .’(’F’4 :&Œ$‘L%IC'1+C =  1 =I 7+ ! LüäìÔÄìäîîöîî991ä2ô<<ä2ì2îöîî20KSXííY"K°TK° T[K° T[K° T[K° T[K°T[X½L@LLÿÀ878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&ôWddWUccUžº» º»ùtž¼»ŸŸ¹º% üZ VcbWWcd²žº» º»ŸWccWUcc‘”„‚••‚ƒ•Ü»»ÛÛ»¼ÛàÛ»½ÚÛ¼ºÜùóŽ•‚„””„–ýŸÜ»»ÛÛ»¼Û”„‚••‚ƒ•ÿÿhm'$¼uÿÿÉ‹m'(žuÿÿhk'$¼uÿÿÉ‹N'(žuÿÿÉ‹k'(žuÿÿ¢k',ÿ/uÿÿÿþ`m',ÿ/uÿÿXN',ÿ/uÿÿ;ºk',ÿ/uÿÿsÿãÙk'2'uÿÿsÿãÙm'2'uÿÿsÿãÙk'2'uÿÿ²ÿã)k'8îuÿÿ²ÿã)m'8îuÿÿ²ÿã)k'8îuÁy` ·¿Füì1/ì0@ @P`p]3#Á¸¸`û Áî?f7@ ´³uÜì91ôì290K° TK°T[X½ÿÀ@878Y3#'#¶”õ‹´´‹fþˆõõ¶J7c@$  Ãà íVwVvôìüì99991ü<üÔ<ì99990K° TK° T[X½ÿÀ@878Y'.#"#>3232673#"&ü9! &$}f[&@%9! &$}f[&@Z7IR‡“!7IR‡“Õb+ö/·ïîÔÌ1üì0K° TK°T[X½ÿÀ@878Y!!ÕVýªö”Ç)9H W@ ð³VVÜìÔì1ô<Ôì0K° TX½ÿÀ@878YK°TK°T[K°T[X½@ÿÀ878Y332673#"&Çv aWV` v ž‘‘žHKKJLšDf,@ ÎÍdÔì1üì0K° TX½ÿÀ@878Y3#šÌÌÌîá _@Áò ÁñV xVÔìôì1ôìôì0K° TK° T[X½ÿÀ@878YK° TK° T[K° T[X½ÿÀ@878Y4&#"3267#"&54632˜X@AWWA@XzŸssŸŸssŸô?XW@AWX@s  ssŸŸ#þuÁ@  ó' ÜÔìÔÌ1/ÔüÄ90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ ƒ0.W=ðî®fB@´³ÔÜÔÌ991ô<ì20K° TK°T[X½ÿÀ@878Y3#3#ü²ø‡ªß‰fþˆxþˆLþuÁ @  óô 'ÔìÄÔÌ1/üüÄ90!33267#"&546¸w-+76 >&Dzs5=X..… W]0iÁî?f7@ ´³uÜì91ô<ì90K° TK°T[X½ÿÀ@878Y373¶õ‹´´‹õîxõõþˆÿòuÕ ?@ •  : yô<ìÄü<Ä991/äì90´0P]3%!!'7ÓË9Pþw×ü^”MáÕý˜Ûoþîýãª;jnžH ^@ — z z Ô<äü<ä991/ì90K°TX½ @ ÿÀ878Y@ @ P ` sz p à ð ]37#'7Ǹ}Lɸ{JÅý¦ZjüãšXjÿÿ‡ÿã¢m'6‹uÿÿoÿãÇf'Vàÿÿ\m'=¾uÿÿXÛf']àþ¢®˜@ õõÜ<ì21ÔìÔì0##®ªªª˜ý öý ö ºÕ g@  © ••  2  yô<ì2ÄôìÄ91/Æ2îöîî20@( °Ÿ Ÿ Ÿ Ÿ ŸŸŸŸ¿ ¿ ¿ ¿ ¿¿¿¿]]! )#53!!3 !Ó ±–þiþPþ`ÉÉËPþ°ó5þáþËÕþ—þ€þ~þ–¼ãþýê.,qÿãu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ##¹ ¹Œ#±)&' ! (%#" QE)üìôì99999991ìÄôìî9990KSXÉÉÉÉííííY"²?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x" *ð*']].#"32654&#"5432''%'3%F2X)§¹®’‘®6 ~rþäæçþåÝ4*ŸþÁ!µäM!þÙ“ØÃ¼ÞÞ¼z¼&þà­ÿþÉ7ÿú7´kc\Ì‘oabÿÿÿüçk'<suÿÿ=þVf'\^ÉÕ =@• •ö  ? üì22üì91/ôüìÔì0@ ?_]332+#32654&#ÉÊþûþÿûþÊÊþš™ŽÕþøáÜÜâþ®'ýÑ’††‘ºþV¤>@¹¹Œ¸½— GFüì22ôì1ìääôÄìÆî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý®¾ý¢daþ¼þøþøþ¼aëËççËËççÙ-Û×¶œÔÄ1Ôì0!!Ùúþת?œÅ …@M œ  œœœœœ œ œ B   Ô<Ì291Ô<Ì290KSXííííííííY" '7œþ7Éwþ5þ5vÈþ8vËËLþ5þ7yËþ5yÉËyþ5ˉœÅß ,@Ý ÝÝ ÷‘ |]|| Üôäüä1ôììÔìî2035733!œÌßæ‰Íý× c)t'ý+n^œ´ðJ@$}}BÝÝ÷ Ý‘~ÜÄÔÄì91ôÄìüìî90KSXí2íY"!!56754&#"56632 ¨ýª"?XhU4zHM…9‘®þµ8rn81^BQ##{„l‹þä0bÍð(H@' Ý Ý Ý Ý ø÷Ý ø#‘)~&~ )ÜÄÄÔìÔì9991ôäìüäìÔìîî90#"&'532654&##532654&#"56632 \e¾±9}F4wCmxolV^^ad_(fQI€7©Z`mR|†yOFJLl?<:=svcE`ÿÿ‰ÿãð'ð'¼5 ‹ýdÿÿ‰ÿã?ð'ð'¼5ñ‹ýdÿÿbÿãð'ò'¼5 ‹ýdÿÿsÿã‹m'* uÿÿqþVZH'JÚ‹ÿÿÉ•P', ÿ/uÿÿ‡þu¢ð'6Ý‹ÿÿoþuÇ{'VÝÿÿsÿã'k'&-uÿÿqÿãçf'F‰ÿÿsÿã'm'&-uÿÿqÿãçf'Fà‰qÿãô$J@$Ó ù"¹¹ Œ¸—   GE%üìô<Äü<Ä1/ìäôÄìÄîý<î20¶`&€& &]!5!533##5#"3232654&#"¢þºF¸šš¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶N}““}úü¨daDDaþËççËËççd߃¶œÜÌ1Ôì0!!dý僤ÛH®F·ƒÔì1Ôì03#ÛÓÓFþÿãð1@: Ó"+Ó ¡®•¡®•/‘Œ) 2+"!)#&  , & &*!/<ÔÄ2üÄÄ99999999991Ä2äôìôìîöîî2Ý<î20K° TK° T[K° T[K°T[K°T[K°T[X½2ÿÀ22@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-ŸŸŸ Ÿ Ÿ Ÿ Ÿ ŸŸŸŸŸŸ–Ÿ Ÿ!Ÿ"Ÿ#Ÿ$Ÿ%Ÿ&Ÿ'Ÿ(Ÿ)Ÿ*Ÿ+Ÿ,-2   USjg ]].#"!!!!3267#"#734&5465#7332[©fÊ A7ýæ¾8þŠ Êf©[Y¹`íþË(Ó7‹Â7œ(6ìb¹bÕiZÈ»{.# .{»ÊZiÓHH"{/ #/{"G×)Ù¥@ ÎddÔüÜì1Ô<ì20K°TK°T[X½@ÿÀ878YK°TK° T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y@````pppp]3#%3#^ËËþyËËÙËËËsîðö@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@ %%6FVjg //]]3#7¹ä™öþø¶Jéu@!  ÃÃúVV ÔìÔì99991ô<ìÔì2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y´ ]'.#"#4632326=3#"&ü9 $(}gV$=09" (}gT";9! 2-ev 3)dw î‹ö‰@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@*$$5CUUŸŸ¯¯//]]#ÇÄ™æöþøÏî1øw@ úÔÄ91ô<Ä90K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ //- ]3#'#¢¼Ó‹¦¦‹øþö²²Ïî1ø†@ úÔÄ91ôÄ290K° TK° T[K° T[K° T[X½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ "  ]373¢Ó‹¦¦‹Óî ²²þö?œôß Ô@ Ý ÷‘ ] ÜÔ<Äì291ôüÔ<ì290K°TK°T[K°T[K°T[K° T[K° T[X½@ÿÀ878YK°TK°T[X½ÿÀ@878Y@T /9IFYi‹«»       "5GK S[ e„¥µ]] !33##5!5ÝþË5¦‡‡þbfþ]ýämººyÇ9ø j@à úVVÔìÔì1ôüÄ20K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TK°T[X½ÿÀ@878Y332673#"&Çv cSRav  Ÿø6978w{zšfÛ¶úÔÌ1ôÌ03#šÌÌÛÍ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßà>: ~ÿ1BSax~’ÇÝ©À & 0 : ¬!""""+"H"e%Êûÿÿ   0AR^x}’ÆØ©À  0 9 ¬!""""+"H"`%ÊûÿÿÿãÿõÿØÿ ÿ^ÿCÿhÿüöüÛà–à…àVßjÞqÞ_Úï¿8ôüúúü (B¬£„…½–熎‹©¤ŠÙƒ“ñò—ˆÃÝðžªóôõ¢­ÉÇ®bcdËeÈÊÏÌÍÎèfÒÐѯgï‘ÕÓÔhêì‰jikmln oqprsutvwéxzy{}|¸¡~€ëíºýþÿøÖùúãä×àÚÛÜßØÞ²³¶·Ä´µÅ‚‡«˜¨š™î¼¥’”•Íf‹‹55®Å´žªšq=3ۤ=´Ù‹žãd‹Û²‡á–œdž¨‹²ð²ž´Ù´Ù´Ù?“‡y}É–s)ÉÉšÉ3sÉ\É\ÿ–?ÉuÉçÉüÉLsÓÉLsɇãÿúÛ²yéD{=ãÿü{\°²Ç´Ùÿìªç{ºfqqìqÑ/qº9Á9ÿÛ¢º9Á˺ºåqºqJº+o#7®¼=‹V¼;¼=3X²´Ùyy–sÉüÉLsÛ²ç{ç{ç{ç{ç{ç{fqìqìqìqìq99ÿÇ9ÿÞ9ÿôºåqåqåqåqåq®®®®9ì\¸3ž º's×´ÙËLfªÝ´Ù´Ù´ÙR®#hdœ¶ÿá+/ÅsÅ`NÛ{åH?55´Ù=´ÙZÿúåžåÁìyyLss/q%®%®‹®‹²´Ùô¼=ãÿüVþ‰^3ž3Á / /9‹Û‹®%® ¼qyÉyÉÉ\¢\ÿþ\\;LsLsLsÛ²Û²Û²9ÁÁ¶ÕÇšî#ðLÁÿòF‡+o{\3X²3 åqãÿü¼=×ɺ´Ù´5‰5^5bÁ‰Á‰Áb3sq\ɇ+o–sfq–sfqqãd‹Û×s¶ ÏÏ5?Çšÿ+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóõôöøùúûüýþÿ     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""X“ÿ¶Oƒ²ö!n˜´ÊÞE‚~áL·üeÏî  R s ®  ß X ° û : i “ æ  = z /¬E…ëuñ)pཊëP‹±á@Ö"m¹#{ßC€øw³R¡Ø‡Äº‡wè [ r ó!5!B!â!ï!ü" ""#"0"="J"W"d"q"~"‹"˜"¥"²"¿"Ì"Ù"æ"ó## ##'#4#A#N#[#h#”#Ï$4$%3%S%&&º'K''·((X(Ã)_*%*\*£*é+z+Ó,D,,±-P- ..R.ª/‡0A0½11!1P1Ï2H2z2ß3F3p3p3}3Š3—3æ4z44£4Ñ4ÿ5595g5‘5ž5«5Ï6[6“6Í7C7©7ë888J999)969C9P9]9j9w9„9‘9ž9«9¸9Å9Ò9ï::{: :å;;^;Ž;Ä;ô<"<_<§<´<Á<Î<Û<þ=c>;>H>U>˜>ç>ý?a??Ü@:@K@\@m@z@‡@”@¡@®@»@È@Õ@âA@AVAkBEBªB÷C_C²CÿDUDÛE*E?-†” x$ÿÓ%ÿ·&')*K+-r./2934K57ÿD9ÿˆ:ÿ­;ÿš<ÿ =IQR&UYÿÉZ\ÿÜbÿÓdg9xy&z&{&|&}&‰­ÿÓ®ÿÓ¯9ºÿÜ»ÿ ÇÿÓÉÿÓÐ9Ñ9Ò9åéêÿ ëÿÜìöKûý$ÿÓ$ÿÜ$ÿÜ$$9$&ÿÜ$*ÿÜ$2ÿÜ$4ÿÜ$6$7ÿa$8$9ÿ}$:ÿ$;$<ÿa$FÿÜ$GÿÜ$HÿÜ$Iÿ·$RÿÜ$TÿÜ$WÿÜ$X$Yÿˆ$Zÿ­$\ÿu$b9$dÿÜ$gÿÜ$h$oÿÜ$pÿÜ$qÿÜ$rÿÜ$sÿÜ$yÿÜ$zÿÜ${ÿÜ$|ÿÜ$}ÿÜ$~$$€$$©ÿ·$ª$­9$®9$¯ÿÜ$´þø$µÿ$ºÿu$»ÿa$Å/$Ç9$É9$ÐÿÜ$ÑÿÜ$ÒÿÜ$Ó$Ô$Õ$ã$êÿa$ëÿu$öÿÜ$ù$ûÿÜ$üÿÜ$ýÿÜ$þÿÜ%%&ÿÜ%*ÿÜ%2ÿÜ%6ÿÜ%9ÿÁ%:ÿ·%<ÿ%dÿÜ%gÿÜ%©ÿÁ%ªÿÜ%¯ÿÜ%´ÿ%µÿ%»ÿ%Åÿ­%ÐÿÜ%ÑÿÜ%ÒÿÜ%ãÿÜ%êÿ%öÿÜ%ùÿÜ%ûÿÜ%ýÿÜ&&$&6&<ÿÜ&b&©ÿÜ&ªÿÜ&­&®&´&µ&&»ÿÜ&Å&Ç&É&ã&êÿÜ&ù''$ÿÜ'9ÿÜ':'<ÿ'bÿÜ'©ÿÜ'ªÿÜ'­ÿÜ'®ÿÜ'´ÿÓ'µÿÉ'»ÿ'ÅÿD'ÇÿÜ'ÉÿÜ'êÿ))þ·)ÿa)$ÿD)6ÿÜ)7ÿÜ)DÿD)Hÿ)Lÿk)Rÿ·)Uÿk)Xÿ)\ÿD)bÿD)iÿD)jÿD)kÿD)lÿD)mÿD)nÿD)pÿ)qÿ)rÿ)sÿ)yÿ·)zÿ·){ÿ·)|ÿ·)}ÿ·)~ÿ)ÿ)€ÿ)ÿ)©)ª)­ÿD)®ÿD)´ÿÓ)µ)ºÿD)Åþˆ)ÇÿD)ÉÿD)ãÿÜ)ëÿD)ùÿÜ**$*7ÿ·*:*<ÿš*b*©ÿÜ*ªÿÜ*­*®*´ÿÓ*µÿÓ*»ÿš*ÅÿÉ*Ç*É*êÿš++ÿÜ++©+ª+´ÿ·+µÿÁ+Åÿ·-ÿ·-$ÿÜ-bÿÜ-©ÿÜ-ªÿÜ-­ÿÜ-®ÿÜ-´ÿ·-µÿÁ-Åÿ-ÇÿÜ-ÉÿÜ.ÿ).$ÿÜ.&ÿ.2ÿ.7ÿa.8ÿÉ.:ÿ·.<ÿ·.DÿÜ.Hÿš.Rÿš.Xÿš.\ÿk.bÿÜ.dÿ.gÿ.hÿÉ.iÿÜ.jÿÜ.kÿÜ.lÿÜ.mÿÜ.nÿÜ.pÿš.qÿš.rÿš.sÿš.yÿš.zÿš.{ÿš.|ÿš.}ÿš.~ÿš.ÿš.€ÿš.ÿš.©ÿ}.ª.­ÿÜ.®ÿÜ.¯ÿ.´ÿÁ.µÿÁ.ºÿk.»ÿ·.Å.ÇÿÜ.ÉÿÜ.Ðÿ.Ñÿ.Òÿ.ÓÿÉ.ÔÿÉ.ÕÿÉ.êÿ·.ëÿk.ûÿ.ýÿ/ÿÜ/$//2ÿ·/7þæ/8ÿš/9ÿ/:ÿD/<þð/D/HÿÜ/RÿÜ/XÿÜ/\ÿD/b//gÿ·/hÿš/i/j/k/l/m/n/pÿÜ/qÿÜ/rÿÜ/sÿÜ/yÿÜ/zÿÜ/{ÿÜ/|ÿÜ/}ÿÜ/~ÿÜ/ÿÜ/€ÿÜ/ÿÜ/©/ª/­//®//¯ÿ·/´þa/µýæ/ºÿD/»þð/Å/Ç//É//Ðÿ·/Ñÿ·/Òÿ·/Óÿš/Ôÿš/Õÿš/êþð/ëÿD292ÿ­2ÿÜ2$ÿÜ29ÿÜ2;ÿ}2<ÿ2bÿÜ2©ÿÜ2ª2­ÿÜ2®ÿÜ2´ÿÓ2µÿÜ2»ÿ2ÅÿD2ÇÿÜ2ÉÿÜ2êÿ3ÿÓ3þÁ33$ÿ}383:3<ÿÓ3Dÿ¤3Hÿ·3LÿÓ3QÿÜ3Rÿ·3UÿÜ3VÿÜ3XÿÜ3\3bÿ}3h3iÿ¤3jÿ¤3kÿ¤3lÿ¤3mÿ¤3nÿ¤3pÿ·3qÿ·3rÿ·3sÿ·3xÿÜ3yÿ·3zÿ·3{ÿ·3|ÿ·3}ÿ·3~ÿÜ3ÿÜ3€ÿÜ3ÿÜ3©ÿÜ3ª3­ÿ}3®ÿ}3´&3µ&3º3»ÿÓ3Åþ·3Çÿ}3Éÿ}3Ó3Ô3Õ3äÿÜ3êÿÓ3ë3úÿÜ494©4ª4´ÿÓ4µÿÜ4Åÿ}5ÿ­5ÿ·5ÿÁ5$ÿ­5&ÿš57ÿk59ÿ5:ÿ­5<ÿ}5DÿÓ5Hÿ¤5Rÿ¤5Xÿ¤5\ÿ5bÿ­5dÿš5iÿÓ5jÿÓ5kÿÓ5lÿÓ5mÿÓ5nÿÓ5pÿ¤5qÿ¤5rÿ¤5sÿ¤5yÿ¤5zÿ¤5{ÿ¤5|ÿ¤5}ÿ¤5~ÿ¤5ÿ¤5€ÿ¤5ÿ¤5©ÿ5ªÿÜ5­ÿ­5®ÿ­5´ÿk5µÿ}5ºÿ5»ÿ}5ÅÿÜ5Çÿ­5Éÿ­5êÿ}5ëÿ5ûÿš5ýÿš6$&6&6*6264666b&6d6g6­&6®&6¯6Ç&6É&6Ð6Ñ6Ò6ã6ö6ù6û6ý7ÿD7ÿ 7ÿ7$ÿa7&ÿˆ77ÿÜ7Dþ­7Fþ¤7Hþ¤7LÿÁ7Rþ¤7UþÓ7Vþ­7XþÉ7Zþ­7\þÁ7bÿa7dÿˆ7iþ­7jþ­7kþ­7lþ­7mþ­7nþ­7oþ¤7pþ¤7qþ¤7rþ¤7sþ¤7yþ¤7zþ¤7{þ¤7|þ¤7}þ¤7~þÉ7þÉ7€þÉ7þÉ7©ÿD7ªÿ7­ÿa7®ÿa7´7µÿÓ7ºþÁ7Åþø7Çÿa7Éÿa7äþ­7ëþÁ7úþ­7ûÿˆ7üþ¤7ýÿˆ7þþ¤8$8-8=ÿÜ8b8­8®8Ç8É8åÿÜ9ÿˆ9þø9ÿY9$ÿ}92ÿÜ9Dÿa9Hÿa9LÿÓ9Rÿa9Xÿu9\ÿÉ9bÿ}9gÿÜ9iÿa9jÿa9kÿa9lÿa9mÿa9nÿa9pÿa9qÿa9rÿa9sÿa9yÿa9zÿa9{ÿa9|ÿa9}ÿa9~ÿu9ÿu9€ÿu9ÿu9©ÿN9ªÿ9­ÿ}9®ÿ}9¯ÿÜ9´9µ9ºÿÉ9Åþæ9Çÿ}9Éÿ}9ÐÿÜ9ÑÿÜ9ÒÿÜ9ëÿÉ:ÿ­:ÿ:ÿˆ:$ÿ:Dÿ}:Hÿˆ:LÿÓ:Rÿˆ:Uÿ¤:Xÿ·:\ÿÜ:bÿ:iÿ}:jÿ}:kÿ}:lÿ}:mÿ}:nÿ}:pÿˆ:qÿˆ:rÿˆ:sÿˆ:yÿˆ:zÿˆ:{ÿˆ:|ÿˆ:}ÿˆ:~ÿ·:ÿ·:€ÿ·:ÿ·:©ÿ:ªÿÜ:­ÿ:®ÿ:´ÿÜ:µ:ºÿÜ:Åþø:Çÿ:Éÿ:ëÿÜ;ÿš;$;&ÿk;2ÿ};7ÿÜ;Hÿ¤;b;dÿk;gÿ};pÿ¤;qÿ¤;rÿ¤;sÿ¤;©ÿ;ª;­;®;¯ÿ};´ÿa;µÿ­;ÅÿÓ;Ç;É;Ðÿ};Ñÿ};Òÿ};ûÿk;ýÿk<ÿ <þa<þð<$ÿa<&ÿ<2ÿ<Dþæ<Hþð<Lÿ·<Rþð<Xÿ<bÿa<dÿ<gÿ<iþæ<jþæ<kþæ<lþæ<mþæ<nþæ<pþð<qþð<rþð<sþð<yþð<zþð<{þð<|þð<}þð<~ÿ<ÿ<€ÿ<ÿ<©ÿ<ªÿk<­ÿa<®ÿa<¯ÿ<´ÿ<µÿÜ<Åþø<Çÿa<Éÿa<Ðÿ<Ñÿ<Òÿ<ûÿ<ýÿ=ÿÜ=©=ª=´ÿÜ=µÿÜ=ÅÿÜH[ÿÜIÿIÿkIÿ·IWÿÜIZÿÜI\ÿÜI©ÿ·IªÿÜI´AIµIºÿÜIÅÿIëÿÜNDÿÜNHÿ·NRÿ·NXÿÁN\ÿ·NiÿÜNjÿÜNkÿÜNlÿÜNmÿÜNnÿÜNpÿ·Nqÿ·Nrÿ·Nsÿ·Nyÿ·Nzÿ·N{ÿ·N|ÿ·N}ÿ·N~ÿÁNÿÁN€ÿÁNÿÁNºÿ·Nëÿ·QQQQ©QªQ´ÿkQµÿQÅÿ¤R&RÿÜRR[ÿÁR©RªR´ÿkRµÿ·RÅÿ}Uÿ}UÿDUÿÜUFÿÓUGÿÜUHÿÓUIUJÿÜUKÿÜUPÿÜUQÿÜURÿÓUTÿÜUUÿÜUXUYUZU[ÿÉU\U]UoÿÓUpÿÓUqÿÓUrÿÓUsÿÓUxÿÜUyÿÓUzÿÓU{ÿÓU|ÿÓU}ÿÓU~UU€UU©ÿ·UªU´UµVUºUÅþÉUæUëU÷ÿÜUüÿÓUþÿÓYÿÉYÿaYÿY©ÿÜYªÿÜY´YµÿÜYÅþðZZÿDZÿZ©ÿÜZªÿÜZ´ZµZÅÿ)[FÿÜ[HÿÁ[RÿÁ[oÿÜ[pÿÁ[qÿÁ[rÿÁ[sÿÁ[yÿÁ[zÿÁ[{ÿÁ[|ÿÁ[}ÿÁ[üÿÜ[þÿÜ\ÿÜ\þÜ\ÿk\©ÿÜ\ªÿÜ\´\µ\ÅþÓbÿÓbÿÜbÿÜb$9b&ÿÜb*ÿÜb2ÿÜb4ÿÜb6b7ÿab8b9ÿ}b:ÿb;b<ÿabFÿÜbGÿÜbHÿÜbIÿ·bRÿÜbTÿÜbWÿÜbXbYÿˆbZÿ­b\ÿubb9bdÿÜbgÿÜbhboÿÜbpÿÜbqÿÜbrÿÜbsÿÜbyÿÜbzÿÜb{ÿÜb|ÿÜb}ÿÜb~bb€bb©ÿ·bªb­9b®9b¯ÿÜb´þøbµÿbºÿub»ÿabÅ/bÇ9bÉ9bÐÿÜbÑÿÜbÒÿÜbÓbÔbÕbãbêÿabëÿuböÿÜbùbûÿÜbüÿÜbýÿÜbþÿÜdd$d6d<ÿÜdbd©ÿÜdªÿÜd­d®d´dµ&d»ÿÜdÅdÇdÉdãdêÿÜdùg9gÿ­gÿÜg$ÿÜg9ÿÜg;ÿ}g<ÿgbÿÜg©ÿÜgªg­ÿÜg®ÿÜg´ÿÓgµÿÜg»ÿgÅÿDgÇÿÜgÉÿÜgêÿh$h-h=ÿÜhbh­h®hÇhÉhåÿÜp[ÿÜq[ÿÜr[ÿÜs[ÿÜxxxx©xªx´ÿkxµÿxÅÿ¤y&yÿÜyy[ÿÁy©yªy´ÿkyµÿ·yÅÿ}z&zÿÜzz[ÿÁz©zªz´ÿkzµÿ·zÅÿ}{&{ÿÜ{{[ÿÁ{©{ª{´ÿk{µÿ·{Åÿ}|&|ÿÜ||[ÿÁ|©|ª|´ÿk|µÿ·|Åÿ}}&}ÿÜ}}[ÿÁ}©}ª}´ÿk}µÿ·}Åÿ}‰&‰©‰ª‰´ÿ‰µÿ‰Åÿ­©ª´ÿ­µÿ¤Åÿ©$©%ÿÜ©&ÿÜ©'ÿÜ©)©*ÿÜ©+©-ÿÜ©.©/©2©3©4©5©7ÿ©9ÿ©:ÿÜ©;©<ÿk©=©I©Q©R©U©YÿÜ©ZÿÜ©\ÿÜ©b©dÿÜ©g©x©y©z©{©|©}©‰©—©­©®©¯©ºÿÜ©»ÿk©Ç©É©Ð©Ñ©Ò©å©é©êÿk©ëÿÜ©ì©öÿÜ©ûÿÜ©ýÿܪ$ÿ·ª%ÿ·ª&ÿܪ'ÿܪ)ª*ª+ª-ÿܪ.ª/ª2ÿܪ3ª4ª5ª7ÿDª9ÿNª:ÿª;ÿª<ÿª=ªIªQªRªUªYÿܪZÿܪ\ÿܪbÿ·ªdÿܪgÿܪxªyªzª{ª|ª}ª‰ªª­ÿ·ª®ÿ·ª¯ÿܪºÿܪ»ÿªÇÿ·ªÉÿ·ªÐÿܪÑÿܪÒÿܪåªéªêÿªëÿܪìªöªûÿܪýÿÜ­ÿÓ­ÿÜ­ÿÜ­$9­&ÿÜ­*ÿÜ­2ÿÜ­4ÿÜ­6­7ÿa­8­9ÿ}­:ÿ­;­<ÿa­FÿÜ­GÿÜ­HÿÜ­Iÿ·­RÿÜ­TÿÜ­WÿÜ­X­Yÿˆ­Zÿ­­\ÿu­b9­dÿÜ­gÿÜ­h­oÿÜ­pÿÜ­qÿÜ­rÿÜ­sÿÜ­yÿÜ­zÿÜ­{ÿÜ­|ÿÜ­}ÿÜ­~­­€­­©ÿ·­ª­­9­®9­¯ÿÜ­´þø­µÿ­ºÿu­»ÿa­Å/­Ç9­É9­ÐÿÜ­ÑÿÜ­ÒÿÜ­Ó­Ô­Õ­ã­êÿa­ëÿu­öÿÜ­ù­ûÿÜ­üÿÜ­ýÿÜ­þÿÜ®ÿÓ®ÿÜ®ÿÜ®$9®&ÿÜ®*ÿÜ®2ÿÜ®4ÿÜ®6®7ÿa®8®9ÿ}®:ÿ®;®<ÿa®FÿÜ®GÿÜ®HÿÜ®Iÿ·®RÿÜ®TÿÜ®WÿÜ®X®Yÿˆ®Zÿ­®\ÿu®b9®dÿÜ®gÿÜ®h®oÿÜ®pÿÜ®qÿÜ®rÿÜ®sÿÜ®yÿÜ®zÿÜ®{ÿÜ®|ÿÜ®}ÿÜ®~®®€®®©ÿ·®ª®­9®®9®¯ÿÜ®´þø®µÿ®ºÿu®»ÿa®Å/®Ç9®É9®ÐÿÜ®ÑÿÜ®ÒÿܮӮԮծã®êÿa®ëÿu®öÿÜ®ù®ûÿÜ®üÿÜ®ýÿÜ®þÿܯ9¯ÿ­¯ÿܯ$ÿܯ9ÿܯ;ÿ}¯<ÿ¯bÿܯ©ÿܯª¯­ÿܯ®ÿܯ´ÿÓ¯µÿܯ»ÿ¯ÅÿD¯ÇÿܯÉÿܯêÿ´$þø´%ÿÁ´&ÿ·´'ÿÁ´)ÿÁ´*ÿ·´+ÿÁ´-ÿÁ´.ÿÁ´/ÿÁ´2ÿ·´3ÿÁ´4ÿ·´5ÿÁ´7´9´:´;ÿˆ´<´=ÿÜ´Iÿ·´Qÿ´Rÿk´Uÿ´Yÿ·´Zÿ·´\ÿ·´bþø´dÿ·´gÿ·´xÿ´yÿk´zÿk´{ÿk´|ÿk´}ÿk´‰ÿÁ´þ}´­þø´®þø´¯ÿ·´ºÿ·´»´Çþø´Éþø´Ðÿ·´Ñÿ·´Òÿ·´åÿÜ´éÿ·´ê´ëÿ·´ìÿÁ´öÿ·´ûÿ·´ýÿ·ºÿܺþܺÿkº©ÿܺªÿܺ´ºµºÅþÓ»ÿ »þa»þð»$ÿa»&ÿ»2ÿ»Dþæ»Hþð»Lÿ·»Rþð»Xÿ»bÿa»dÿ»gÿ»iþæ»jþæ»kþæ»lþæ»mþæ»nþæ»pþð»qþð»rþð»sþð»yþð»zþð»{þð»|þð»}þð»~ÿ»ÿ»€ÿ»ÿ»©ÿ»ªÿk»­ÿa»®ÿa»¯ÿ»´ÿ»µÿÜ»Åþø»Çÿa»Éÿa»Ðÿ»Ñÿ»Òÿ»ûÿ»ýÿÅ$&Å%ÿ·Å&ÿÅ'ÿ·Å)ÿ·Å*ÿ·Å+ÿ·Å-/Å.ÿ·Å/ÿ·Å2ÿÅ3ÿ·Å4ÿÅ5ÿ·Å7þæÅ9þˆÅ:ÿÅ;ÿ·Å<þˆÅ=ÅIÿÜÅQÿ·ÅRÿ·ÅUÿ·ÅYÿÅZÿ<Å\ÿÅb&ÅdÿÅgÿÅxÿ·Åyÿ·Åzÿ·Å{ÿ·Å|ÿ·Å}ÿ·Å‰ÿ·Å&Å­&Å®&ůÿźÿÅ»þˆÅÇ&ÅÉ&ÅÐÿÅÑÿÅÒÿÅåÅéÿ·ÅêþˆÅëÿÅìÿ·Åöÿ·ÅûÿÅýÿÇÿÓÇÿÜÇÿÜÇ$9Ç&ÿÜÇ*ÿÜÇ2ÿÜÇ4ÿÜÇ6Ç7ÿaÇ8Ç9ÿ}Ç:ÿÇ;Ç<ÿaÇFÿÜÇGÿÜÇHÿÜÇIÿ·ÇRÿÜÇTÿÜÇWÿÜÇXÇYÿˆÇZÿ­Ç\ÿuÇb9ÇdÿÜÇgÿÜÇhÇoÿÜÇpÿÜÇqÿÜÇrÿÜÇsÿÜÇyÿÜÇzÿÜÇ{ÿÜÇ|ÿÜÇ}ÿÜÇ~ÇÇ€ÇÇ©ÿ·ÇªÇ­9Ç®9ǯÿÜÇ´þøÇµÿǺÿuÇ»ÿaÇÅ/ÇÇ9ÇÉ9ÇÐÿÜÇÑÿÜÇÒÿÜÇÓÇÔÇÕÇãÇêÿaÇëÿuÇöÿÜÇùÇûÿÜÇüÿÜÇýÿÜÇþÿÜÉÿÓÉÿÜÉÿÜÉ$9É&ÿÜÉ*ÿÜÉ2ÿÜÉ4ÿÜÉ6É7ÿaÉ8É9ÿ}É:ÿÉ;É<ÿaÉFÿÜÉGÿÜÉHÿÜÉIÿ·ÉRÿÜÉTÿÜÉWÿÜÉXÉYÿˆÉZÿ­É\ÿuÉb9ÉdÿÜÉgÿÜÉhÉoÿÜÉpÿÜÉqÿÜÉrÿÜÉsÿÜÉyÿÜÉzÿÜÉ{ÿÜÉ|ÿÜÉ}ÿÜÉ~ÉÉ€ÉÉ©ÿ·ÉªÉ­9É®9ɯÿÜÉ´þøÉµÿɺÿuÉ»ÿaÉÅ/ÉÇ9ÉÉ9ÉÐÿÜÉÑÿÜÉÒÿÜÉÓÉÔÉÕÉãÉêÿaÉëÿuÉöÿÜÉùÉûÿÜÉüÿÜÉýÿÜÉþÿÜÐ9Ðÿ­ÐÿÜÐ$ÿÜÐ9ÿÜÐ;ÿ}Ð<ÿÐbÿÜЩÿÜЪЭÿÜЮÿÜдÿÓеÿÜлÿÐÅÿDÐÇÿÜÐÉÿÜÐêÿÑ9Ñÿ­ÑÿÜÑ$ÿÜÑ9ÿÜÑ;ÿ}Ñ<ÿÑbÿÜÑ©ÿÜѪѭÿÜÑ®ÿÜÑ´ÿÓѵÿÜÑ»ÿÑÅÿDÑÇÿÜÑÉÿÜÑêÿÒ9Òÿ­ÒÿÜÒ$ÿÜÒ9ÿÜÒ;ÿ}Ò<ÿÒbÿÜÒ©ÿÜÒªÒ­ÿÜÒ®ÿÜÒ´ÿÓÒµÿÜÒ»ÿÒÅÿDÒÇÿÜÒÉÿÜÒêÿÓ$Ó-Ó=ÿÜÓbÓ­Ó®ÓÇÓÉÓåÿÜÔ$Ô-Ô=ÿÜÔbÔ­Ô®ÔÇÔÉÔåÿÜÕ$Õ-Õ=ÿÜÕbÕ­Õ®ÕÇÕÉÕåÿÜã$&ã&ã*ã2ã4ã6ãb&ãdãgã­&ã®&ã¯ãÇ&ãÉ&ãÐãÑãÒãããöãùãûãýåÿÜå©åªå´ÿÜåµÿÜåÅÿÜéé©éªé´ÿ¤éµÿéÅÿ·êÿ êþaêþðê$ÿaê&ÿê2ÿêDþæêHþðêLÿ·êRþðêXÿêbÿaêdÿêgÿêiþæêjþæêkþæêlþæêmþæênþæêpþðêqþðêrþðêsþðêyþðêzþðê{þðê|þðê}þðê~ÿêÿê€ÿêÿê©ÿêªÿkê­ÿaê®ÿaê¯ÿê´ÿêµÿÜêÅþøêÇÿaêÉÿaêÐÿêÑÿêÒÿêûÿêýÿëÿÜëþÜëÿkë©ÿÜëªÿÜë´ëµëÅþÓììÿkìÿ·ì©ìªì´ÿÜìµìÅÿDöö$ö7ÿ·ö:ö<ÿšöbö©ÿÜöªÿÜö­ö®ö´ÿÓöµÿÓö»ÿšöÅÿÉöÇöÉöêÿšù$&ù&ù*ù2ù4ù6ùb&ùdùgù­&ù®&ù¯ùÇ&ùÉ&ùÐùÑùÒùãùöùùùûùýûû$û6û<ÿÜûbû©ÿÜûªÿÜû­û®û´ûµ&û»ÿÜûÅûÇûÉûãûêÿÜûùýý$ý6ý<ÿÜýbý©ÿÜýªÿÜý­ý®ý´ýµ&ý»ÿÜýÅýÇýÉýãýêÿÜýù MB@hmþ ¼þ‰þ‰ L GÌþBGÌSf €¯ JBits@ ûþšmãB±‹`#cÕVeraSansÿÿÿÿ6ÿÿþ628R00@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "                      "       #                       #     $               $    &              &    ÿÿ P ì_<õº¹ð¸ºÂg‘þ‰þ Lmmupen64plus-core-src-2.6.0/data/mupen64plus.ini000066400000000000000000015510651464506436200212770ustar00rootroot00000000000000; Mupen64Plus Rom Catalog ; Generated by M64P_INICreater.php ; Script coded by: okaygo ; ; Total Rom Count: 3048 ; Fri, 06 Jun 08 23:13:38 -0400 [A56B15FAF24389DD375E7AFB03A7D3C1] GoodName=007 - Goldfinger CRC=B2242748 FFBD61DA Status=1 Rumble=Yes Players=4 CountPerOp=1 [34AB1DEA3111A233A8B5C5679DE22E83] GoodName=007 - The World is Not Enough (E) (M3) [!] CRC=3B941695 F90A5EEB SaveType=None Mempak=Yes Status=1 Rumble=Yes Players=4 [551324F5FD0A2B0BC2B1BFBB0FE29C08] GoodName=007 - The World is Not Enough (E) [T+Spa1.0.1_IlDucci] CRC=D8C74049 29CDD8C4 RefMD5=34AB1DEA3111A233A8B5C5679DE22E83 [9D58996A8AA91263B5CD45C385F45FE4] GoodName=007 - The World is Not Enough (U) [!] CRC=033F4C13 319EE7A7 SaveType=None Mempak=Yes Status=1 Rumble=Yes Players=4 [12BD3FAFB4E064B6B0C07B7EE156243B] GoodName=007 - The World is Not Enough (U) (Beta) [!] CRC=A92E0966 341C3912 SaveType=None Mempak=Yes Status=1 Rumble=Yes Players=4 [0846FFFDA3081821EA0DCBB7D4DEAAA3] GoodName=007 - The World is Not Enough (U) [t1] CRC=5B6AC01B 8D1A562A RefMD5=9D58996A8AA91263B5CD45C385F45FE4 [1D86AE43FF88E4583C8161815577F1CD] GoodName=007 - The World is Not Enough (U) [t1][f1] (PAL-NTSC) CRC=5B6AC01B 8D1A562A RefMD5=9D58996A8AA91263B5CD45C385F45FE4 [632C98CF281CDA776E66685B278A4FA6] GoodName=1080 Snowboarding (E) (M4) [!] CRC=58FD3F25 D92EAA8D SaveType=SRAM Status=2 Players=2 Rumble=Yes [4E08D29B094C13C030AC73A1DA2F8CD2] GoodName=1080 Snowboarding (E) (M4) [b1] CRC=6BB11645 2C6F637E RefMD5=632C98CF281CDA776E66685B278A4FA6 [4FCA132D6C96130371F4186A3DF85077] GoodName=1080 Snowboarding (E) (M4) [b1][f2] (NTSC) CRC=58FD3F25 D92EAA8D RefMD5=632C98CF281CDA776E66685B278A4FA6 [EC9DB32624B6C16376429D0660F0710B] GoodName=1080 Snowboarding (E) (M4) [f1] CRC=AF61F386 29F1112C RefMD5=632C98CF281CDA776E66685B278A4FA6 [5CA3A45C21E16EDAFBAFE1BD0491DC8D] GoodName=1080 Snowboarding (E) (M4) [f2] (NTSC) CRC=93C5ED78 F67E8528 RefMD5=632C98CF281CDA776E66685B278A4FA6 [FA27089C425DBAB99F19245C5C997613] GoodName=1080 Snowboarding (JU) (M2) [!] CRC=1FBAF161 2C1C54F1 SaveType=SRAM Status=2 Players=2 Rumble=Yes [E428181D573E25DCC0DC7F9F3BF4D1E1] GoodName=1080 Snowboarding (JU) (M2) [b1] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [A3D30FBDFD84B5E7298568BBD5CED7FD] GoodName=1080 Snowboarding (JU) (M2) [b2] CRC=1FBAF161 2C1C54F1 RefMD5=FA27089C425DBAB99F19245C5C997613 [FE15A6E7AF4E37487252369D6F0AB35B] GoodName=1080 Snowboarding (JU) (M2) [b3] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [7657C4BB92E3F6F126D94F5942FDB445] GoodName=1080 Snowboarding (JU) (M2) [b4] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [C7AC7460AF3897BB38D6745BC4557C8E] GoodName=1080 Snowboarding (JU) (M2) [b5] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [FE320327CF6EDC64D06BFA56D8E7A085] GoodName=1080 Snowboarding (JU) (M2) [b6] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [C36AC032E36C61723698344C33DC1F7E] GoodName=1080 Snowboarding (JU) (M2) [b7] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [DAFE880CEF56AF0231EBA2390259A2AC] GoodName=1080 Snowboarding (JU) (M2) [b8] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [A0B2E39FD3FE3802C369A6937416B38E] GoodName=1080 Snowboarding (JU) (M2) [b9] CRC=1FBAF161 2C1C54F1 RefMD5=FA27089C425DBAB99F19245C5C997613 [2C6A75570997BA7A1244950AC8FE6CBF] GoodName=1080 Snowboarding (JU) (M2) [ba] CRC=35F53383 0C8D0AE4 RefMD5=FA27089C425DBAB99F19245C5C997613 [3B5691B895B415056E4EA69695DC26B4] GoodName=1080 Snowboarding (JU) (M2) [f1] (DS-1) CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [6CEACF73F03BA3DE740BDB00D7CC18A1] GoodName=1080 Snowboarding (JU) (M2) [f2] (PAL) CRC=9207357A E85D4001 RefMD5=FA27089C425DBAB99F19245C5C997613 [765DC057507AA32DAAEC194E32FF26B1] GoodName=1080 Snowboarding (JU) (M2) [f2][b1] CRC=1FBAF161 2C1C54F1 RefMD5=FA27089C425DBAB99F19245C5C997613 [1ED9C697BD2F2AEBE6B3B8BF0D24A8CA] GoodName=1080 Snowboarding (JU) (M2) [f3][t1] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [C70578054AA00D7F95AE1D64E3AA9995] GoodName=1080 Snowboarding (JU) (M2) [f3][t2] (All Levels) CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [00CE20766866883063AF3A6C3368039F] GoodName=1080 Snowboarding (JU) (M2) [f4] (PAL-Z64) CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [AEE3FA928B2C1B73D841B47074D91C71] GoodName=1080 Snowboarding (JU) (M2) [f5] (SRAM) CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [B5AC31D584BB2EF93C2A229E19B6D9A1] GoodName=1080 Snowboarding (JU) (M2) [h1C] CRC=35F53383 0C8D0AE4 RefMD5=FA27089C425DBAB99F19245C5C997613 [136245692E02003ED1A972F424CD9323] GoodName=1080 Snowboarding (JU) (M2) [h2C] CRC=92072A84 275952F8 RefMD5=FA27089C425DBAB99F19245C5C997613 [EC4458443FBA0F09B8593AC5ED114C26] GoodName=1964 Demo by Steb (PD) CRC=5C450380 4B5CB6E6 [E76EA30A71F9DC19C6502591FA7CB8E2] GoodName=2 Blokes & An Armchair - Nintendo 64 Remix Remix by Tesko (PD) [f1] CRC=04815914 87141455 [B05E10857A76AB70A83017ADDE8A8ACC] GoodName=2 Blokes & An Armchair - Nintendo 64 Remix Remix by Tesko (PD) CRC=04815914 87141455 [8BEC4EDFA1446859DA896E4EBAE8F925] GoodName=3DS Model Conversion by Snake (PD) CRC=4C304819 2CBE7573 Players=0 Rumble=No Status=4 SaveType=None [DF6BC38C3D0C722DADD4EEDB5DFCE305] GoodName=3DS Model Conversion by Snake (PD) [h1C] CRC=4C304819 2CBE7573 RefMD5=8BEC4EDFA1446859DA896E4EBAE8F925 [0A5ACFEA0C7CF68AE25202040D5AD1EB] GoodName=40 Winks (E) (M3) (Prototype) CRC=ABA51D09 C668BAD9 Players=2 Mempak=Yes Rumble=Yes [8C3E4FE5F6B2D37C66A71097E8B1C72A] GoodName=40 Winks (U) (Prototype) CRC=AA94493C 3736CC22 RefMD5=0A5ACFEA0C7CF68AE25202040D5AD1EB [B88C172ED14F4ACB43C4A352D71CC640] GoodName=40 Winks (U) (Unl) CRC=5EF44642 44D05A25 RefMD5=0A5ACFEA0C7CF68AE25202040D5AD1EB [66335F4DC6AB27034398BC26F263B897] GoodName=64 Hanafuda - Tenshi no Yakusoku (J) [!] CRC=36F22FBF 318912F2 Players=1 SaveType=Eeprom 4KB Status=5 [2CF9EDB51ADA9DE2AE7AD9FD5ACC5580] GoodName=64 Oozumou (J) [!] CRC=9C961069 F5EA488D Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes Status=5 CountPerOp=1 [88763C3FD50E036BBB9CF504F77C0741] GoodName=64 Oozumou (J) [b1] CRC=9C961069 F5EA488D RefMD5=2CF9EDB51ADA9DE2AE7AD9FD5ACC5580 [9A737609D5A7565589DA44381C476FD3] GoodName=64 Oozumou (J) [b2] CRC=9C961069 F5EA488D RefMD5=2CF9EDB51ADA9DE2AE7AD9FD5ACC5580 [CD4F6C55A7567A25954908DF613B236F] GoodName=64 Oozumou (J) [b3] CRC=9C961069 F5EA488D RefMD5=2CF9EDB51ADA9DE2AE7AD9FD5ACC5580 [F7C796371E77E0A6FBD02EB866341952] GoodName=64 Oozumou 2 (J) [!] CRC=85C18B16 DF9622AF Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=5 [6B947F654775CF5DACD1E5D53D577DA7] GoodName=64 Trump Collection - Alice no Wakuwaku Trump World (J) [!] CRC=7A6081FC FF8F7A78 Players=4 SaveType=Eeprom 4KB Rumble=Yes Status=5 [2C6FDCF4A6A6614D09224EFAA55FB531] GoodName=64 Trump Collection - Alice no Wakuwaku Trump World (J) [h1C] CRC=7A6081FC FF8F7A78 RefMD5=6B947F654775CF5DACD1E5D53D577DA7 [EA6A92DE5A221A00814F7448BF6F1B31] GoodName=64 de Hakken!! Tamagotchi Minna de Tamagotchi World (J) [!] CRC=B98BA456 5B2B76AF Players=4 Status=2 SaveType=Eeprom 4KB Mempak=Yes CountPerOp=1 [11B20CFE8E3ECCC680AA8157A7906D6D] GoodName=64 de Hakken!! Tamagotchi Minna de Tamagotchi World (J) [b1] CRC=B98BA456 5B2B76AF RefMD5=EA6A92DE5A221A00814F7448BF6F1B31 [D8F6D887B94BA913EF60A0B03F781AE6] GoodName=64 de Hakken!! Tamagotchi Minna de Tamagotchi World (J) [h1C] CRC=B98BA456 5B2B76AF RefMD5=EA6A92DE5A221A00814F7448BF6F1B31 [326BF85C5EF158205364710454EE1AF1] GoodName=64 de Hakken!! Tamagotchi Minna de Tamagotchi World (J) [h2C] CRC=B98BA456 5B2B76AF RefMD5=EA6A92DE5A221A00814F7448BF6F1B31 [11B891B7551BFBDB79732BFB94B45603] GoodName=64 de Hakken!! Tamagotchi Minna de Tamagotchi World (J) [o1] CRC=B98BA456 5B2B76AF RefMD5=EA6A92DE5A221A00814F7448BF6F1B31 [14E8E1761B8994C54B304418CEA49773] GoodName=77a Special Edition by Count0 (PD) CRC=975B7845 A2505C18 Players=2 Status=1 Rumble=No SaveType=Eeprom 16KB [45C610FC443D0DF07ED9F07AC8B7C54A] GoodName=77a Special Edition by Count0 (PD) [b1] CRC=975B7845 A2505C18 RefMD5=14E8E1761B8994C54B304418CEA49773 [7D6AC6295EF6A0ABB3D4594AF407B7A6] GoodName=77a by Count0 (POM '98) (PD) CRC=D6D29529 D4EADEE4 Players=2 Status=1 Rumble=No SaveType=None [A8426180C65A4C9DD1DF9FD033DDCBB6] GoodName=77a by Count0 (POM '98) (PD) [b1] CRC=D6D29529 D4EADEE4 RefMD5=7D6AC6295EF6A0ABB3D4594AF407B7A6 [4A5C509A20DB7A429DC1DD4E219AD4A2] GoodName=AI Shougi 3 (J) [!] CRC=8CC182A6 C2D0CAB0 Players=4 Status=1 SaveType=Eeprom 4KB Mempak=Yes [D9FE93EBA610E60F8F5D9880E52DB056] GoodName=Absolute Crap #2 by Lem (PD) CRC=2E7E893C 4E68B642 Status=3 Players=0 SaveType=None Rumble=No [9E59882163EA99A45629B9B8B491D86B] GoodName=Absolute Crap #2 by Lem (PD) [b1] CRC=2E7E893C 4E68B642 RefMD5=D9FE93EBA610E60F8F5D9880E52DB056 [D5F73BB1FC46328440C3BD9812A49284] GoodName=Absolute Crap #2 by Lem (PD) [b2] CRC=2E7E893C 4E68B642 RefMD5=D9FE93EBA610E60F8F5D9880E52DB056 [2F02D478FC89E46FA143B128E29B434C] GoodName=Absolute Crap Intro #1 by Kid Stardust (PD) [b1] CRC=B0667DED BB39A4B8 RefMD5=FF4D4FEFF0AF8A0F9B9AE509DA7D9071 [E06A7190B2DF9CCCCA30C1724DDFE95B] GoodName=Absolute Crap Intro #1 by Kid Stardust (PD) [h1C] CRC=B0667DED BB39A4B8 RefMD5=FF4D4FEFF0AF8A0F9B9AE509DA7D9071 [FF4D4FEFF0AF8A0F9B9AE509DA7D9071] GoodName=Absolute Crap Intro #1 by Kid Stardust (PD) CRC=B0667DED BB39A4B8 Players=0 Status=5 Rumble=No SaveType=None [35BA407EA9E4EF7C0ACE8B4F58BEEC41] GoodName=Action Replay Pro 64 V3.0 (Unl) CRC=F1297BC9 42CDAE9D Status=0 [0D77918E6C989261EEF81FE244E48EEF] GoodName=Action Replay Pro 64 V3.0 (Unl) [b1] CRC=158A155D C1538CDB RefMD5=35BA407EA9E4EF7C0ACE8B4F58BEEC41 [FD8681CBF1A599FF2EA55DBF40EA7D27] GoodName=Action Replay Pro 64 V3.0 (Unl) [f1] CRC=8A155D15 53C1DB8C RefMD5=35BA407EA9E4EF7C0ACE8B4F58BEEC41 [67AFA5DF80A5CFC91FCE1DC918EA0A4F] GoodName=Action Replay Pro 64 V3.3 (Unl) CRC=A8D1DAF2 31206B53 Status=0 [7558E3DA7225712936D3BA3DCE210C36] GoodName=AeroFighters Assault (E) (M3) [!] CRC=62F6BE95 F102D6D6 Players=2 SaveType=Eeprom 4KB Rumble=Yes Status=3 [915E7762364C2449AAEBC4CA5278D1E8] GoodName=AeroFighters Assault (E) (M3) [f1] (NTSC) CRC=0BBCDFCF 2DD952CC RefMD5=7558E3DA7225712936D3BA3DCE210C36 [6C25C8D7CE393C0214917A211A199F0C] GoodName=AeroFighters Assault (E) (M3) [o1] CRC=62F6BE95 F102D6D6 RefMD5=7558E3DA7225712936D3BA3DCE210C36 [79FB6E2452AF077C5EF1DDE5FC810F04] GoodName=AeroFighters Assault (U) [!] CRC=1B598BF1 ECA29B45 Players=2 SaveType=Eeprom 4KB Rumble=Yes Status=3 [CF5FF92EED5FD3C714BC3C4D15C47AE3] GoodName=AeroFighters Assault (U) [b1] CRC=1B598BF1 ECA29B45 RefMD5=79FB6E2452AF077C5EF1DDE5FC810F04 [7E3E9BC4188B37A4FC283E22BEDB5D49] GoodName=AeroFighters Assault (U) [b2] CRC=1B598BF1 ECA29B45 RefMD5=79FB6E2452AF077C5EF1DDE5FC810F04 [48522CCF3D059DDF2DCF5D6AEE2D1FD7] GoodName=AeroFighters Assault (U) [b3] CRC=1B598BF1 ECA29B45 RefMD5=79FB6E2452AF077C5EF1DDE5FC810F04 [24CA46D2C8E2D68978AEAE46C3862F1E] GoodName=AeroFighters Assault (U) [f1] (PAL) CRC=5C4EB1C9 12A49603 RefMD5=79FB6E2452AF077C5EF1DDE5FC810F04 [0635FE16018BB216E5CD29C300CADC74] GoodName=AeroFighters Assault (U) [h1C] CRC=1B598BF1 ECA29B45 RefMD5=79FB6E2452AF077C5EF1DDE5FC810F04 [6A56589EC8FADD1139EC4B6EED9D19AE] GoodName=AeroFighters Assault (U) [h2C] CRC=1B598BF1 ECA29B45 RefMD5=79FB6E2452AF077C5EF1DDE5FC810F04 [63657276E7256DCA562F024FC71F4A47] GoodName=AeroFighters Assault (U) [h3C] CRC=1B598BF1 ECA29B45 RefMD5=79FB6E2452AF077C5EF1DDE5FC810F04 [05056045447BF1FBA8F9878A7F6009F3] GoodName=AeroGauge (E) (M3) [!] CRC=D83045C8 F29D3A36 Players=2 SaveType=Eeprom 4KB Mempak=Yes Status=4 [FD979768AC0EC6CBBCA8C5339D62BB05] GoodName=AeroGauge (E) (M3) [f1] (NTSC) CRC=440355A4 869CE5F9 RefMD5=05056045447BF1FBA8F9878A7F6009F3 [E0256E4270887B99DA7E91A620FFEFF3] GoodName=AeroGauge (E) (M3) [h1C] CRC=D83045C8 F29D3A36 RefMD5=05056045447BF1FBA8F9878A7F6009F3 [25D19487CB80DB724DB9D735F2C28E8B] GoodName=AeroGauge (E) (M3) [h2C] CRC=D83045C8 F29D3A36 RefMD5=05056045447BF1FBA8F9878A7F6009F3 [E970AF3DE25BB5AE1154010E26AF776F] GoodName=AeroGauge (J) (V1.0) (Kiosk Demo) [!] CRC=B00903C9 3916C146 Players=2 SaveType=Eeprom 4KB Mempak=Yes Status=4 [6A52188E8A7D008F1921AA8A6D40A74C] GoodName=AeroGauge (J) (V1.0) (Kiosk Demo) [b1] CRC=3F47EEA0 5DDF7A3C RefMD5=E970AF3DE25BB5AE1154010E26AF776F [5AB4773BB270BE3A72BB79EF68DEA414] GoodName=AeroGauge (J) (V1.0) (Kiosk Demo) [b2] CRC=B00903C9 3916C146 RefMD5=E970AF3DE25BB5AE1154010E26AF776F [13CCAA36D309B78D20C9C0C89A8CE650] GoodName=AeroGauge (J) (V1.0) (Kiosk Demo) [b3] CRC=B00903C9 3916C146 RefMD5=E970AF3DE25BB5AE1154010E26AF776F [AC5828BA750A4DCDC840050DE66305E2] GoodName=AeroGauge (J) (V1.0) (Kiosk Demo) [b4] CRC=3F47EEA0 5DDF7A3C RefMD5=E970AF3DE25BB5AE1154010E26AF776F [0620C2D134A0430F4AFA208FFEDA67B8] GoodName=AeroGauge (J) (V1.1) [!] CRC=80F41131 384645F6 Players=2 SaveType=Eeprom 4KB Mempak=Yes Status=4 [CC8C56B4E37BC5A501087E7CE8C12CC5] GoodName=AeroGauge (J) (V1.1) [b1] CRC=80F41131 384645F6 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [426725BFE1A505D4C3B12862188A2526] GoodName=AeroGauge (J) (V1.1) [b2] CRC=80F41131 384645F6 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [A74429738648C96FAB23944CCB06AA6C] GoodName=AeroGauge (J) (V1.1) [b3] CRC=80F41131 384645F6 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [E38C4D24254BB3CB6C9EC75CD29A6566] GoodName=AeroGauge (J) (V1.1) [b4] CRC=80F41131 384645F6 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [E80AD38B3139CBA5A367CB9B0B21AAFA] GoodName=AeroGauge (J) (V1.1) [b5] CRC=80F41131 384645F6 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [CDCB7101471DD1129DF63D6076834337] GoodName=AeroGauge (J) (V1.1) [b6] CRC=80F41131 384645F6 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [AB36ED30033F4101D3F660951A568413] GoodName=AeroGauge (J) (V1.1) [b7] CRC=80F41131 384645F6 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [9D7DAD00EAAC504D459608AB30CB0C1E] GoodName=AeroGauge (J) (V1.1) [f1] (PAL) CRC=4795217F 63D42538 RefMD5=0620C2D134A0430F4AFA208FFEDA67B8 [72C7FFCEA6C1430616867616F5E9D51A] GoodName=AeroGauge (U) [!] CRC=AEBE463E CC71464B Players=2 SaveType=Eeprom 4KB Mempak=Yes Status=4 [B8BA26F0C27253B80E5C7D96B0FB66AB] GoodName=AeroGauge (U) [T+Ita0.01_Cattivik66] CRC=AEBE463E CC71464B RefMD5=72C7FFCEA6C1430616867616F5E9D51A [3D6C792ED4FA3CE5C92013F15BCCD327] GoodName=AeroGauge (U) [b1] CRC=AEBE463E CC71464B RefMD5=72C7FFCEA6C1430616867616F5E9D51A [B7DB0D2CDCAB307D744B6370F1BBA9C1] GoodName=AeroGauge (U) [f1] (PAL) CRC=FDAA963C FDCCD971 RefMD5=72C7FFCEA6C1430616867616F5E9D51A [11BE82186C64EF407B28403D49B199DB] GoodName=AeroGauge (U) [h1C] CRC=AEBE463E CC71464B RefMD5=72C7FFCEA6C1430616867616F5E9D51A [31E739E6420DA88ABF4980AD0C76439A] GoodName=AeroGauge (U) [h2C] CRC=AEBE463E CC71464B RefMD5=72C7FFCEA6C1430616867616F5E9D51A [54D0A39123C15F74AABB1ECC24D4D6A0] GoodName=Aidyn Chronicles - The First Mage (E) [!] CRC=2DC4FFCC C8FF5A21 Players=1 SaveType=None Mempak=Yes Status=3 [AF149336B3DDB899598E7BE8740D7DC6] GoodName=Aidyn Chronicles - The First Mage (U) (V1.0) [!] CRC=E6A95A4F BAD2EA23 Players=1 SaveType=None Mempak=Yes Status=3 [31448B07CBC932018870F71D1254E317] GoodName=Aidyn Chronicles - The First Mage (U) (V1.0) [o1] CRC=E6A95A4F BAD2EA23 RefMD5=AF149336B3DDB899598E7BE8740D7DC6 [E8CDDF0C52B72453D52DA385322DFE15] GoodName=Aidyn Chronicles - The First Mage (U) (V1.1) [!] CRC=112051D2 68BEF8AC RefMD5=AF149336B3DDB899598E7BE8740D7DC6 [CD24763BECFA1D0053E5438B0EF5E75E] GoodName=Aidyn Chronicles - The First Mage (U) (Beta) (2000-02-10) CRC=40066883 9375D98F RefMD5=AF149336B3DDB899598E7BE8740D7DC6 [CC6EAE9ED582044CC27945684FD396CD] GoodName=Aidyn Chronicles - The First Mage (U) (Beta) (2000-05-09) CRC=FC8BED44 D640D904 RefMD5=AF149336B3DDB899598E7BE8740D7DC6 [E8891F8F498A615A6CBAF75B7DDC9FA6] GoodName=Airboarder 64 (E) [!] CRC=27C425D0 8C2D99C1 Players=2 SaveType=Eeprom 4KB Mempak=Yes Status=4 Rumble=Yes CountPerOp=1 [DCFB92A4B106FE61E54579B1D3B7336E] GoodName=Airboarder 64 (E) [f1] (NTSC) CRC=89A498AE DE3CD49A RefMD5=E8891F8F498A615A6CBAF75B7DDC9FA6 [A0EE7484500178BAB44FDE0AF6D5748F] GoodName=Airboarder 64 (E) [h1C] CRC=27C425D0 8C2D99C1 RefMD5=E8891F8F498A615A6CBAF75B7DDC9FA6 [CCEE2FCF38DC2200128D75D15DB53283] GoodName=Airboarder 64 (J) [!] CRC=6C45B60C DCE50E30 Players=2 Status=4 Rumble=Yes SaveType=Eeprom 4KB Mempak=Yes CountPerOp=1 [F558165311C9CDCA73FB089E298F2056] GoodName=Airboarder 64 (J) [b1] CRC=6C45B60C DCE50E30 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [62B005D0E9DAE96526443498D6420EC3] GoodName=Airboarder 64 (J) [b1][t1] CRC=F255D6F1 B65D6728 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [C429FE5C86F14764923F08D44884C823] GoodName=Airboarder 64 (J) [b2] CRC=F255D6F1 B65D6728 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [16CB66DD44F7A46EEAC5FFCB38FBE26B] GoodName=Airboarder 64 (J) [b3] CRC=6C45B60C DCE50E30 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [278EF4B79B3544DE327CF7DBCDD60081] GoodName=Airboarder 64 (J) [f1] (PAL) CRC=26809B20 39A516A4 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [C02C32351BD69CB2D3FAC355BE074DC0] GoodName=Airboarder 64 (J) [h1C] CRC=6C45B60C DCE50E30 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [78CABB696CA4847BFAD09B01257C6FDA] GoodName=Airboarder 64 (J) [h2C] CRC=6C45B60C DCE50E30 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [B6894826F5386019B19F0A775D11B042] GoodName=Airboarder 64 (J) [h3C] CRC=6C45B60C DCE50E30 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [F9027DF3909C849CBADDAB1C1468BACC] GoodName=Airboarder 64 (J) [h4C] CRC=6C45B60C DCE50E30 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [41BE85236052A2E8EED144989B0A3E0A] GoodName=Airboarder 64 (J) [h5C] CRC=F255D6F1 B65D6728 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [037B58EE5FB4F3BFF408EE406E3539C0] GoodName=Airboarder 64 (J) [h6C] CRC=6C45B60C DCE50E30 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [63F850D7CC829B287FF1DC61CA3F7CCA] GoodName=Airboarder 64 (J) [t1] CRC=F255D6F1 B65D6728 RefMD5=CCEE2FCF38DC2200128D75D15DB53283 [256A1CB23F9E1A2762A7A171417B5D68] GoodName=Akumajou Dracula Mokushiroku - Real Action Adventure (J) [!] CRC=B6951A94 63C849AF Players=1 SaveType=Eeprom 16KB Rumble=Yes [47EA239717C4D225C9D0E9FD37B9FCB3] GoodName=Akumajou Dracula Mokushiroku Gaiden - Legend of Cornell (J) [!] CRC=A5533106 B9F25E5B Players=1 SaveType=Eeprom 16KB Rumble=Yes [ECD127A57E25CE8514307BB47ECC1E95] GoodName=Alienstyle Intro by Renderman (PD) [a1] CRC=43EFB5BB D8C62E2B Players=0 Status=5 SaveType=None Rumble=No [232A5DC2E98C6CAB1D9F73C1D1C1C73A] GoodName=Alienstyle Intro by Renderman (PD) CRC=888EEC7A 42361983 Players=0 Status=5 SaveType=None Rumble=No [E3F4C868917A12BD5E84D94D1C260C7D] GoodName=All Star Tennis '99 (E) (M5) [!] CRC=DFD784AD AE426603 Players=4 SaveType=Eeprom 4KB Status=4 [4DC614B1022252F41E4E182249FA7BAA] GoodName=All Star Tennis '99 (E) (M5) [f1] (NTSC) CRC=3015A8AD 8CEAF5F8 RefMD5=E3F4C868917A12BD5E84D94D1C260C7D [37962CB6D58C2D6B044EAECDCF70EC09] GoodName=All Star Tennis '99 (E) (M5) [f2] (NTSC) CRC=6FD0035D 371B785D RefMD5=E3F4C868917A12BD5E84D94D1C260C7D [E034C969BCDC2E8DBE2C8A73BED57B53] GoodName=All Star Tennis '99 (E) (M5) [f3] (NTSC) CRC=2E341C3D 5AC8DEA3 RefMD5=E3F4C868917A12BD5E84D94D1C260C7D [7FB6422E5BBF60FEE39651EFF3F79BAB] GoodName=All Star Tennis '99 (E) (M5) [f4] (NTSC) CRC=F3700A53 4795C23D RefMD5=E3F4C868917A12BD5E84D94D1C260C7D [AFC3DC9BB737D81903F6CE4875B63AE9] GoodName=All Star Tennis '99 (U) [!] CRC=E185E291 4E50766D Players=4 SaveType=Eeprom 4KB Status=4 [A90FE01FDAFFB70DD123C0BA04589FAA] GoodName=All Star Tennis '99 (U) [T+Bra1.0_Guto] CRC=E185E291 4E50766D RefMD5=AFC3DC9BB737D81903F6CE4875B63AE9 [A2FA12A1DEFCB152DFD04E82968C7D3A] GoodName=All Star Tennis '99 (U) [f1] (PAL) CRC=2D56F77B CBE813FC RefMD5=AFC3DC9BB737D81903F6CE4875B63AE9 [D341A40EA9FBE95B6F0F99DFC5901FB7] GoodName=All Star Tennis '99 (U) [f2] (PAL) CRC=35D13E0D E8652252 RefMD5=AFC3DC9BB737D81903F6CE4875B63AE9 [953B00882A99D650E1F2817674595F0B] GoodName=All Star Tennis '99 (U) [h1C] CRC=E185E291 4E50766D RefMD5=AFC3DC9BB737D81903F6CE4875B63AE9 [ED5F1E12DA36DBEC8A0A24ED98D4AED5] GoodName=All-Star Baseball '99 (E) [!] CRC=D9EDD54D 6BB8E274 Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=3 [78551D23F230B58B9F449CDB4A285761] GoodName=All-Star Baseball '99 (U) [!] CRC=C43E23A7 40B1681A Players=4 SaveType=None Mempak=Yes Status=3 Rumble=Yes [045E0B801F70ADE69981FCBB2EDE5376] GoodName=All-Star Baseball '99 (U) [f1] (PAL) CRC=A6421764 ED1A13E9 RefMD5=78551D23F230B58B9F449CDB4A285761 [13B5AE646CC09876D64366BB07796C78] GoodName=All-Star Baseball '99 (U) [o1] CRC=C43E23A7 40B1681A RefMD5=78551D23F230B58B9F449CDB4A285761 [90448C4175EE9D0247674474DCABDFED] GoodName=All-Star Baseball 2000 (E) [!] CRC=A19F8089 77884B51 Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=0 [E4076E07DBDA9CEAB5EDCEF4D4648EAB] GoodName=All-Star Baseball 2000 (E) [f1] (NTSC) CRC=581900E5 8E662FC8 RefMD5=90448C4175EE9D0247674474DCABDFED [AADA358CE97F06C4DF5BF55987268844] GoodName=All-Star Baseball 2000 (U) [!] CRC=5E547A4D 90E60795 Players=4 SaveType=None Mempak=Yes Rumble=Yes [5D29C01B96A738C3EB68254EF40552F3] GoodName=All-Star Baseball 2000 (U) [f1] (PAL) CRC=44127A31 6D341229 RefMD5=AADA358CE97F06C4DF5BF55987268844 [93B98D93275F803EF4C925BAE5FB711F] GoodName=All-Star Baseball 2000 (U) [h1C] CRC=5E547A4D 90E60795 RefMD5=AADA358CE97F06C4DF5BF55987268844 [07AB7C19DBE85C8CC0961BAAF3B5CA79] GoodName=All-Star Baseball 2000 (U) [h2C] CRC=5E547A4D 90E60795 RefMD5=AADA358CE97F06C4DF5BF55987268844 [6E01B8D425AE74EF5A0F875C700A3B18] GoodName=All-Star Baseball 2001 (U) [!] CRC=5446C6EF E18E47BB Players=4 SaveType=None Mempak=Yes Rumble=Yes [CD04ABC5979F22EF5D6FDC4DCFAA4D50] GoodName=All-Star Baseball 2001 (U) [f1] (PAL) CRC=993CC742 EE65D7A4 RefMD5=6E01B8D425AE74EF5A0F875C700A3B18 [9BC0E3361385713BDF50F0EEBF59FFE0] GoodName=Alleycat 64 by Dosin (POM '99) (PD) CRC=306B3375 05F4E698 Players=1 Status=3 Rumble=No SaveType=None [2DCE0F6556C00B44367586FD1EEB40E5] GoodName=Alleycat 64 by Dosin (POM '99) (PD) [b1] CRC=306B3375 05F4E698 RefMD5=9BC0E3361385713BDF50F0EEBF59FFE0 [58B27AE9B41B755E4F9C503656B93A97] GoodName=Analogue Test Utility by WT_Riker (POM '99) (PD) [b1] CRC=E4C44FDA 98532F4A [25099EEB13E4FB47E390087EF6A20CBC] GoodName=Analogue Test Utility by WT_Riker (POM '99) (PD) CRC=E4C44FDA 98532F4A Players=1 SaveType=None Status=5 Rumble=No [0C2CBAFEC6F184AD39EF29B2B5E0F44A] GoodName=Armorines - Project S.W.A.R.M. (E) [!] CRC=3CC77150 21CDB987 Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=5 [0B5F909546DE5A414F2281AD0C83D9F9] GoodName=Armorines - Project S.W.A.R.M. (E) [f1] (NTSC) CRC=CCDEAF02 8AFC4B28 RefMD5=0C2CBAFEC6F184AD39EF29B2B5E0F44A [2BC48B3E6F61896B9BC7BEF5205CC49C] GoodName=Armorines - Project S.W.A.R.M. (G) [!] CRC=C0F6DB17 80E0D532 Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=5 [43C23D76E4B6B1CBFCE446DFADFB0396] GoodName=Armorines - Project S.W.A.R.M. (G) [f1] (NTSC) CRC=2CEEE754 31B69DBE RefMD5=2BC48B3E6F61896B9BC7BEF5205CC49C [6E6E7A703C131ADADDF4175E9037A2EB] GoodName=Armorines - Project S.W.A.R.M. (U) [!] CRC=1FB5D932 3BA9481B Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=5 [4C15C85280DFB003C3BE6506B217B775] GoodName=Armorines - Project S.W.A.R.M. (U) [f1] (PAL) CRC=EA090572 192F9673 RefMD5=6E6E7A703C131ADADDF4175E9037A2EB [0FDC4ACAB1B531CBB4DFB142CD630B7A] GoodName=Armorines - Project S.W.A.R.M. (U) [t1] CRC=E820670A A99ED0EF RefMD5=6E6E7A703C131ADADDF4175E9037A2EB [755DF7F57EDF87706D4C80FF15883312] GoodName=Army Men - Air Combat (U) [!] CRC=4C52BBB2 CEAB0F6B Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=3 [53E2872612760133AB7B2CC2E22B847C] GoodName=Army Men - Sarge's Heroes (E) (M3) [!] CRC=B210DF19 98B58D1A CountPerOp=1 Players=4 SaveType=None Mempak=Yes Rumble=Yes [B8085C2EDB1C6D23E52ED8C06D92B4F8] GoodName=Army Men - Sarge's Heroes (U) [!] CRC=862C0657 8DFD896D CountPerOp=1 SaveType=None Mempak=Yes Players=4 Rumble=Yes Status=4 [906D5A77188A0DC90EBF294EF8A3915E] GoodName=Army Men - Sarge's Heroes (U) [b1] CRC=D51CF20D 5534AF93 RefMD5=B8085C2EDB1C6D23E52ED8C06D92B4F8 [F1116FAEBBA932A0159B882AF9946BE6] GoodName=Army Men - Sarge's Heroes (U) [f1] (PAL) CRC=94123517 300EEA90 RefMD5=B8085C2EDB1C6D23E52ED8C06D92B4F8 [3D1C87BCF3F8AE8E55FC87A25BE4173C] GoodName=Army Men - Sarge's Heroes (U) [t1] CRC=A7507855 0D454C66 RefMD5=B8085C2EDB1C6D23E52ED8C06D92B4F8 [4E39474136C94CE25061FB6C0B473E29] GoodName=Army Men - Sarge's Heroes (U) [t2] CRC=5E23985B E3CF7CDA RefMD5=B8085C2EDB1C6D23E52ED8C06D92B4F8 [A952E495077D13C8D9587B7B8BBDE2DB] GoodName=Army Men - Sarge's Heroes (U) [t3] CRC=5E23985B E3CF7CDA RefMD5=B8085C2EDB1C6D23E52ED8C06D92B4F8 [6EEA5C4A6256092ED8F9BA8861C689C6] GoodName=Army Men - Sarge's Heroes 2 (U) [!] CRC=B20F73B6 2975FC34 CountPerOp=1 Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=3 [F818FB61331122D455692C00EDB2A2FF] GoodName=Army Men - Sarge's Heroes 2 (U) [t1] CRC=B24303F4 9F7D2445 RefMD5=6EEA5C4A6256092ED8F9BA8861C689C6 [874C7B7B365D2C20AAA1A0C90C93F9B8] GoodName=Asteroids Hyper 64 (U) [!] CRC=D1F7D8AB 293B0446 Players=4 SaveType=None Mempak=Yes Status=3 Rumble=Yes [94751FE93510EBA2D42D82269B224CF8] GoodName=Asteroids Hyper 64 (U) [o1] CRC=D1F7D8AB 293B0446 RefMD5=874C7B7B365D2C20AAA1A0C90C93F9B8 [48E6A629101B200A70873589B5D2F524] GoodName=Asteroids Hyper 64 (U) [o1][f1] (PAL) CRC=39CE39C1 04271200 RefMD5=874C7B7B365D2C20AAA1A0C90C93F9B8 [00396D6B4E66D323D4AD29833A53DF74] GoodName=Asteroids Hyper 64 (U) [o1][t1] CRC=5638C715 5EA6181D RefMD5=874C7B7B365D2C20AAA1A0C90C93F9B8 [CF63AB6AF5FBD5DBFE500DD9A658E069] GoodName=Attax64 by Pookae (POM '99) (PD) CRC=26E43C40 E11F283C Players=4 Status=3 Rumble=No SaveType=None [553037C41F9029F544353B8446BE77D9] GoodName=Attax64 by Pookae (POM '99) (PD) [b1] CRC=26E43C40 E11F283C RefMD5=CF63AB6AF5FBD5DBFE500DD9A658E069 [7853F02DC66A35BC8C2BC33D03B8F0CA] GoodName=Automobili Lamborghini (E) [!] CRC=FC7797BF 4A95E83C Players=4 SaveType=None Mempak=Yes Rumble=Yes Status=4 [DE4631D6419B7361DE9C4A5472964D21] GoodName=Automobili Lamborghini (E) [o1] CRC=FC7797BF 4A95E83C RefMD5=7853F02DC66A35BC8C2BC33D03B8F0CA [EC39579F066A9714FF030D07DEC3C9D3] GoodName=Automobili Lamborghini (U) [!] CRC=41B25DC4 1B726786 Players=5 SaveType=None Mempak=Yes Rumble=Yes Status=4 [E86A022815D0B7E65FD5557F0B3451D4] GoodName=Automobili Lamborghini (U) [T+Ita_cattivik66][b3] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [B293E449967B246451564B25A4A36BEC] GoodName=Automobili Lamborghini (U) [T+Ita_cattivik66][b4] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [1F324E92AF23CDC5499BBC35F3840205] GoodName=Automobili Lamborghini (U) [b1] CRC=4DB05DC4 28DBF801 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [4086114FFB03B156DBCAA0364EB0F81B] GoodName=Automobili Lamborghini (U) [b2] CRC=4DB05DC4 28DBF801 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [D861B752F59774A5597E66E8C58E52D9] GoodName=Automobili Lamborghini (U) [b3] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [B708601A36054FCA51D849D6D26CEC5C] GoodName=Automobili Lamborghini (U) [b4] CRC=DB833E34 63548286 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [0D0D6A170871ED3433A52D110B01357E] GoodName=Automobili Lamborghini (U) [b5] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [69431C0E9152A9C5B62131C034250A25] GoodName=Automobili Lamborghini (U) [b6] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [D441BB80EFD86B8FD65CE855FEC21631] GoodName=Automobili Lamborghini (U) [f1] CRC=4DB05DC4 28DBF801 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [4CEF5CDD83360127B0445E7A9EA0BC8F] GoodName=Automobili Lamborghini (U) [h1C] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [DAC77D638FF03E77F569119116D4B668] GoodName=Automobili Lamborghini (U) [h2C] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [17951444830696AAFC07F311AB128099] GoodName=Automobili Lamborghini (U) [o1] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [8FF8B861A0D095B910DD97EB1ECC02FF] GoodName=Automobili Lamborghini (U) [o1][T+Ita_cattivik66] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [87D7EEBD0E6B403A2022BBD84BC12868] GoodName=Automobili Lamborghini (U) [o2] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [805F74AEF610BA2C1F6FCEF723CD1970] GoodName=Automobili Lamborghini (U) [o3] CRC=4DB05DC4 28DBF801 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [EC9B393B3F52B76C02E3BF2AA20145A5] GoodName=Automobili Lamborghini (U) [o4] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [4E730D045AC33A64BA97D5672589C6C7] GoodName=Automobili Lamborghini (U) [o5] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [8E2F186FC1B86ABC1CC04FFE1845C6AC] GoodName=Automobili Lamborghini (U) [o6] CRC=DB833E34 63548286 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [835E98C0B8A16401BDC6653E8855F0D6] GoodName=Automobili Lamborghini (U) [o7] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [0AD7111C5DB3CA075DCD5AC9838C3B24] GoodName=Automobili Lamborghini (U) [o7][T+Ita_cattivik66] CRC=41B25DC4 1B726786 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [A6836524B4E71E5AD14DD8C3651665AD] GoodName=Automobili Lamborghini (U) [t1] CRC=DB833E34 63548286 RefMD5=EC39579F066A9714FF030D07DEC3C9D3 [3B4330445D9AAE1EF9C56B1393E281E3] GoodName=BB SRAM Manager (PD) CRC=4E5507F2 E7D3B413 [8222D1129394AB4F382476D8231EF9F6] GoodName=BMP View by Count0 (PD) CRC=273433C0 02B1F61B [8183688A4B7D0A390496B5655BCD252E] GoodName=Baku Bomberman (J) [!] CRC=E340A49C 74318D41 SaveType=Eeprom 4KB Players=4 Mempak=Yes [70415D917D5B7BEEFEDAFDB65CD64D43] GoodName=Baku Bomberman (J) [b1] CRC=E340A49C 74318D41 RefMD5=8183688A4B7D0A390496B5655BCD252E [5259F6331389F6AF55B867F60AA373C8] GoodName=Baku Bomberman (J) [h1C] CRC=E340A49C 74318D41 RefMD5=8183688A4B7D0A390496B5655BCD252E [70632EE119E54F76A344A7B04340A6F9] GoodName=Baku Bomberman (J) [t1] CRC=3A595B0E F8788AA6 RefMD5=8183688A4B7D0A390496B5655BCD252E [CA956015B6820DCFF1C814F3532E18B1] GoodName=Baku Bomberman 2 (J) [!] CRC=E73C7C4F AF93B838 SaveType=Eeprom 4KB Players=4 Mempak=Yes Rumble=Yes [8107825AC2A522057422463ED81E276B] GoodName=Bakuretsu Muteki Bangai-O (J) [!] CRC=DF98B95D 58840978 Players=1 Rumble=Yes [A78517540876AE94C2027FE260633CA8] GoodName=Bakuretsu Muteki Bangai-O (J) [f1] (PAL) CRC=0866BEDD AE31C2EE RefMD5=8107825AC2A522057422463ED81E276B [040538EA3C225D1E7F2497ACEFDE8CD0] GoodName=Bakuretsu Muteki Bangai-O (J) [h1C] CRC=DF98B95D 58840978 RefMD5=8107825AC2A522057422463ED81E276B [09FD63AFA1156405E618752FC583DF93] GoodName=Bakushou Jinsei 64 - Mezase! Resort Ou (J) [!] CRC=88CF980A 8ED52EB5 Players=4 Mempak=Yes [E16CFE9268E472A7814C58783AE7D3A2] GoodName=Bakushou Jinsei 64 - Mezase! Resort Ou (J) [h1C] CRC=88CF980A 8ED52EB5 RefMD5=09FD63AFA1156405E618752FC583DF93 [3D3855A86FD5A1B4D30BEB0F5A4A85AF] GoodName=Banjo to Kazooie no Daibouken (J) [!] CRC=5168D520 CA5FCD0D Players=1 SaveType=Eeprom 4KB Rumble=Yes [7FDAFD3252C0F59FFBA59CD42729D959] GoodName=Banjo to Kazooie no Daibouken (J) [f1] CRC=18439105 60424C9E RefMD5=3D3855A86FD5A1B4D30BEB0F5A4A85AF [89BBBB739E54721F77F1A6441C00C093] GoodName=Banjo to Kazooie no Daibouken (J) [f2] CRC=18439105 60424C9E RefMD5=3D3855A86FD5A1B4D30BEB0F5A4A85AF [B49EC888940FAB43651E48F760BF7BBD] GoodName=Banjo to Kazooie no Daibouken (J) [f3] CRC=18439105 60424C9E RefMD5=3D3855A86FD5A1B4D30BEB0F5A4A85AF [715A8816F30FA24B8D174DC5CB6F25A9] GoodName=Banjo to Kazooie no Daibouken 2 (J) [!] CRC=514B6900 B4B19881 SaveType=Eeprom 16KB Players=4 Rumble=Yes [06A43BACF5C0687F596DF9B018CA6D7F] GoodName=Banjo-Kazooie (E) (M3) [!] CRC=733FCCB1 444892F9 Players=1 SaveType=Eeprom 4KB Rumble=Yes [D0410D2C399CBF216BB756F35E5AC4EC] GoodName=Banjo-Kazooie (E) [T+Spa1.1_PacoChan] CRC=8B2FCAD3 361B412C RefMD5=06A43BACF5C0687F596DF9B018CA6D7F [5FC8116DAFDEC73DE9C5CCC2D8E14B4F] GoodName=Banjo-Kazooie (E) (M3) [f1] CRC=192C1422 5B8CFF48 RefMD5=06A43BACF5C0687F596DF9B018CA6D7F [F81C314B04CEE9DC92FD4D50811F6FBB] GoodName=Banjo-Kazooie (E) (M3) [f2] CRC=192C15DA 74BD6300 RefMD5=06A43BACF5C0687F596DF9B018CA6D7F [B29599651A13F681C9923D69354BF4A3] GoodName=Banjo-Kazooie (U) (V1.0) [!] CRC=A4BF9306 BF0CDFD1 SaveType=Eeprom 4KB Players=1 Rumble=Yes [8E870036E7A40BA42803C333A412EFE7] GoodName=Banjo-Kazooie (U) (V1.0) [b1] CRC=A4BF9306 BF0CDFD1 RefMD5=B29599651A13F681C9923D69354BF4A3 [63609225DA40E2BAEC425F4AEB365330] GoodName=Banjo-Kazooie (U) (V1.0) [b2] CRC=A4BF9306 BF0CDFD1 RefMD5=B29599651A13F681C9923D69354BF4A3 [880BB39F8B31C087D66F7193D3528EFE] GoodName=Banjo-Kazooie (U) (V1.0) [b3] CRC=A4BF9306 BF0CDFD1 RefMD5=B29599651A13F681C9923D69354BF4A3 [6E3FBAF95C79A3668B6A9211F1372216] GoodName=Banjo-Kazooie (U) (V1.0) [b4] CRC=16EDC447 B291F183 RefMD5=B29599651A13F681C9923D69354BF4A3 [508B2D76887E3FE169B60B6CF70E6DBA] GoodName=Banjo-Kazooie (U) (V1.0) [b5] CRC=A4BF9306 BF0CDFD1 RefMD5=B29599651A13F681C9923D69354BF4A3 [4782CA6F893AA03F701D6EDA7552711B] GoodName=Banjo-Kazooie (U) (V1.0) [b6] CRC=FEF9D364 FBD6D06E RefMD5=B29599651A13F681C9923D69354BF4A3 [B6BC123E51AE5C3190BCA41CFC1D637F] GoodName=Banjo-Kazooie (U) (V1.0) [b7] CRC=A4BF9306 BF0CDFD1 RefMD5=B29599651A13F681C9923D69354BF4A3 [F9E8FEF0005E26720EB0D0FDFAB7A859] GoodName=Banjo-Kazooie (U) (V1.0) [f1] CRC=16EDC447 B291F183 RefMD5=B29599651A13F681C9923D69354BF4A3 [7173250DC66CA58024C1C4D27B0F8720] GoodName=Banjo-Kazooie (U) (V1.0) [t1] CRC=16EDC447 B291F183 RefMD5=B29599651A13F681C9923D69354BF4A3 [B11F476D4BC8E039355241E871DC08CF] GoodName=Banjo-Kazooie (U) (V1.1) [!] CRC=CD7559AC B26CF5AE RefMD5=B29599651A13F681C9923D69354BF4A3 [61B5C5C3E5E1A81E5D37072C01B39B76] GoodName=Banjo-Tooie (A) [!] CRC=155B7CDF F0DA7325 SaveType=Eeprom 16KB Players=4 Rumble=Yes [8B2E56F18421A67BCA861427453A1E19] GoodName=Banjo-Tooie (E) (M4) [!] CRC=C9176D39 EA4779D1 SaveType=Eeprom 16KB Players=4 Rumble=Yes [40E98FAA24AC3EBE1D25CB5E5DDF49E4] GoodName=Banjo-Tooie (U) [!] CRC=C2E9AA9A 475D70AA SaveType=Eeprom 16KB Players=4 Rumble=Yes [BF3E84CDD01CAC05987FD8DA5191534B] GoodName=Bass Hunter 64 (E) [!] CRC=B088FBB4 441E4B1D Players=1 SaveType=Eeprom 4KB CountPerOp=1 Rumble=Yes [2C618F6C69C3B4803F08762A03835139] GoodName=Bass Rush - ECOGEAR PowerWorm Championship (J) [!] CRC=D76333AC 0CB6219D Players=1 Rumble=Yes CountPerOp=1 [B1AB1D5B3B92B0ACA380D0291DA0689E] GoodName=Bass Rush - ECOGEAR PowerWorm Championship (J) [b1] CRC=D76333AC 0CB6219D RefMD5=2C618F6C69C3B4803F08762A03835139 [1F997B26062B7D59F23193F448157EE3] GoodName=Bass Rush - ECOGEAR PowerWorm Championship (J) [b2] CRC=D76333AC 0CB6219D RefMD5=2C618F6C69C3B4803F08762A03835139 [930C7F6E5863471DDE1816D28A10EB88] GoodName=Bassmasters 2000 (U) [!] CRC=BCFACCAA B814D8EF Players=4 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [D8903586B5E479E6C4937879650D0D2D] GoodName=Bassmasters 2000 (U) [b1] CRC=BCFACCAA B814D8EF RefMD5=930C7F6E5863471DDE1816D28A10EB88 [342476D20D7A7BF4C5484D2DEFCC79E7] GoodName=Bassmasters 2000 (U) [f1] (PAL) CRC=DC41E81E AC36CAD1 RefMD5=930C7F6E5863471DDE1816D28A10EB88 [A08676124B326B1035B202C83A97468F] GoodName=Batman Beyond - Return of the Joker (U) [!] CRC=204489C1 1286CF2B Players=1 SaveType=None Rumble=Yes [E4498D8FE11A6E0CC0737D89361DE097] GoodName=Batman Beyond - Return of the Joker (U) [o1] CRC=204489C1 1286CF2B Players=1 SaveType=None Rumble=Yes [1C7FA31271E5588C968675E932C08991] GoodName=Batman Beyond - Return of the Joker (U) [o1][t1] CRC=D8928E46 965CE432 RefMD5=E4498D8FE11A6E0CC0737D89361DE097 [A5EE8A6C34863E3D0EB8C06AE8668B30] GoodName=Batman of the Future - Return of the Joker (E) (M3) [!] CRC=259F7F84 7C9EED26 Players=1 SaveType=None Rumble=Yes [F5C9B6E4DB938258EA277670B6D37F16] GoodName=Batman of the Future - Return of the Joker (E) (M3) [b1] CRC=259F7F84 7C9EED26 RefMD5=A5EE8A6C34863E3D0EB8C06AE8668B30 [8743BDDE07A2E9E0E5A0792D7D8678CB] GoodName=Batman of the Future - Return of the Joker (E) (M3) [o1] CRC=259F7F84 7C9EED26 RefMD5=A5EE8A6C34863E3D0EB8C06AE8668B30 [3406A505C22BAC2F40D9BFC6FF08CF86] GoodName=BattleTanx (U) [!] CRC=6AA4DDE7 E3E2F4E7 CountPerOp=3 SaveType=None Mempak=Yes Players=4 Rumble=Yes [94A7605A28861C43F636AE0FF7F25F2E] GoodName=BattleTanx (U) [b1] CRC=6AA4DDE7 E3E2F4E7 RefMD5=3406A505C22BAC2F40D9BFC6FF08CF86 [722D55C70368323D79AB1B63696A45E4] GoodName=BattleTanx (U) [b1][t1] CRC=3D615CF5 6984930A RefMD5=3406A505C22BAC2F40D9BFC6FF08CF86 [EDD7187C79CEBDB0D1FABC040502E940] GoodName=BattleTanx (U) [f1] (PAL) CRC=9A75C9C2 A4488353 RefMD5=3406A505C22BAC2F40D9BFC6FF08CF86 [220B85771E64C554514163120C2F82F4] GoodName=BattleTanx (U) [t1] CRC=3D615CF5 6984930A RefMD5=3406A505C22BAC2F40D9BFC6FF08CF86 [D6E667FE10AFE8F7116888EFDE98AE0E] GoodName=BattleTanx - Global Assault (E) (M3) [!] CRC=0CAD17E6 71A5B797 CountPerOp=1 Players=4 SaveType=None Mempak=Yes Rumble=Yes [654557C316F901A2CA6F7F4B43343147] GoodName=BattleTanx - Global Assault (U) [!] CRC=75A4E247 6008963D CountPerOp=3 Players=4 SaveType=None Mempak=Yes Rumble=Yes [DC5AAE1CADF43DF43184D2935C32C26C] GoodName=BattleTanx - Global Assault (U) [f1] (Country Check) CRC=8A2E80DC 00F61BE4 RefMD5=D6E667FE10AFE8F7116888EFDE98AE0E [D6D30577E6E8341495B7D8066035C21D] GoodName=BattleTanx - Global Assault (U) [f2] (PAL) CRC=90111D7E E4B49428 RefMD5=D6E667FE10AFE8F7116888EFDE98AE0E [266C0989ED0929DF499389954779EA97] GoodName=Battlezone - Rise of the Black Dogs (U) [!] CRC=55D4C4CE 7753C78A Players=4 SaveType=None Mempak=Yes Rumble=Yes [A94135D163E6091C960ADC918C1FB8A7] GoodName=Beetle Adventure Racing! (E) (M3) [!] CRC=A1B64A61 D014940B Players=4 SaveType=None Mempak=Yes CountPerOp=3 Rumble=Yes [9D5A1B779F8B43E63E8CE8427675A7EF] GoodName=Beetle Adventure Racing! (E) (M3) [h1C] CRC=A1B64A61 D014940B RefMD5=A94135D163E6091C960ADC918C1FB8A7 [6B4398CE56A9C4786F2087F681FFFAF3] GoodName=Beetle Adventure Racing! (E) (M3) [t1] CRC=59445C71 1F1FE699 RefMD5=A94135D163E6091C960ADC918C1FB8A7 [5FFD43089B7334072B2B74421618D973] GoodName=Beetle Adventure Racing! (J) [!] CRC=9C7318D2 24AE0DC1 Players=4 SaveType=None Mempak=Yes CountPerOp=3 Rumble=Yes [E126B84FA242916289D04D68C0E20BFE] GoodName=Beetle Adventure Racing! (J) [b1] CRC=9C7318D2 24AE0DC1 RefMD5=5FFD43089B7334072B2B74421618D973 [CF97C336479DDBF1217E4DDE89D9D2D3] GoodName=Beetle Adventure Racing! (U) (M3) [!] CRC=EDF419A8 BF1904CC SaveType=None Mempak=Yes Players=4 CountPerOp=3 Rumble=Yes [D11BC38F26EA2835FBF017FE9BD404FE] GoodName=Beetle Adventure Racing! (U) (M3) [b1] CRC=EDF419A8 BF1904CC RefMD5=CF97C336479DDBF1217E4DDE89D9D2D3 [40CBC5A23B7D8C1FDD47D78CACA29248] GoodName=Beetle Adventure Racing! (U) (M3) [b2] CRC=EDF419A8 BF1904CC RefMD5=CF97C336479DDBF1217E4DDE89D9D2D3 [CC9F8A2181C6C9C5ED49B77FF632395A] GoodName=Beetle Adventure Racing! (U) (M3) [f1] (PAL) CRC=1E17A377 9D8C5E86 RefMD5=CF97C336479DDBF1217E4DDE89D9D2D3 [EFFB7B42C6D7C29540C93006E6142F99] GoodName=Beetle Adventure Racing! (U) (M3) [t1] CRC=559A0FD3 897F777C RefMD5=CF97C336479DDBF1217E4DDE89D9D2D3 [C246BD299AA756459193F406A261D1D1] GoodName=Beetle Adventure Racing! (U) (M3) [t2] CRC=522409D3 9340EBFF RefMD5=CF97C336479DDBF1217E4DDE89D9D2D3 [AD7C7B994994CF56481E4450E958049F] GoodName=Berney Must Die! by Nop_ (POM '99) (PD) CRC=3A089BBC 54AB2C06 Status=0 SaveType=None Mempak=Yes [108A605E3D57A5E5C52398B675861EF4] GoodName=Berney Must Die! by Nop_ (POM '99) (PD) [t1] CRC=861F9BDC C3353C85 RefMD5=AD7C7B994994CF56481E4450E958049F [BF6780E2982C16D4A4FDB553BE8F9226] GoodName=Big Mountain 2000 (U) [!] CRC=08FFA4B7 01F453B6 SaveType=Eeprom 4KB Players=2 Rumble=Yes Mempak=Yes [CFE3E75B8B4C75F231CBBD9C99804EC3] GoodName=Big Mountain 2000 (U) [t1] CRC=B0119B37 B9774FD5 RefMD5=BF6780E2982C16D4A4FDB553BE8F9226 [0059B65E1C813BC8BD1A61A1FE009CCD] GoodName=Bike Race '98 V1.0 by NAN (PD) CRC=713FDDD3 72D6A0EF Players=1 Status=2 SaveType=None Rumble=No [A1025E61229D5D855D232210B39F5E66] GoodName=Bike Race '98 V1.0 by NAN (PD) [b1] CRC=713FDDD3 72D6A0EF RefMD5=0059B65E1C813BC8BD1A61A1FE009CCD [1CCD7DB5B3F57944CAF7DA86EF1763E3] GoodName=Bike Race '98 V1.2 by NAN (PD) CRC=F4B64159 46FC16CF Players=1 Status=2 SaveType=None Rumble=No [58B2716389BA3C5575B5A287E59F49AF] GoodName=Bike Race '98 V1.2 by NAN (PD) [b1] CRC=F4B64159 46FC16CF RefMD5=1CCD7DB5B3F57944CAF7DA86EF1763E3 [133B6615CD0936AC705DFC81E4389CBB] GoodName=Bike Race '98 V1.2 by NAN (PD) [b2] CRC=F4B64159 46FC16CF RefMD5=1CCD7DB5B3F57944CAF7DA86EF1763E3 [42672BA5E98CD21D7F3E3745E69038DD] GoodName=Bio F.R.E.A.K.S. (E) [!] CRC=AB7C101D EC58C8B0 Players=2 SaveType=None Mempak=Yes Rumble=Yes [0F412C4CDE69AE41B89D390731D34F71] GoodName=Bio F.R.E.A.K.S. (E) [b1] CRC=AB7C101D EC58C8B0 RefMD5=42672BA5E98CD21D7F3E3745E69038DD [B90AB8F7605D971CC7A6D9BA5E67D1AF] GoodName=Bio F.R.E.A.K.S. (U) [!] CRC=08123595 0510F1DE Players=2 SaveType=None Mempak=Yes Rumble=Yes [801ECC49DAF04FBA099C6F75A06F0454] GoodName=Bio F.R.E.A.K.S. (U) [b1] CRC=08123595 0510F1DE RefMD5=B90AB8F7605D971CC7A6D9BA5E67D1AF [F64B263F67ACA5DE1957299FD92FB35A] GoodName=Bio F.R.E.A.K.S. (U) [b2] CRC=08123595 0510F1DE RefMD5=B90AB8F7605D971CC7A6D9BA5E67D1AF [3F2802F12058B4511A0778A891050297] GoodName=Bio F.R.E.A.K.S. (U) [b3] CRC=B6223A7B 2139CEA6 RefMD5=B90AB8F7605D971CC7A6D9BA5E67D1AF [E02AEF75AC059FC2446BFFDD06EE64A9] GoodName=Bio F.R.E.A.K.S. (U) [h1C] CRC=08123595 0510F1DE RefMD5=B90AB8F7605D971CC7A6D9BA5E67D1AF [879A085B07B7E6D52DFE2CE636D7A239] GoodName=Bio F.R.E.A.K.S. (U) [t1] CRC=B6223A7B 2139CEA6 RefMD5=B90AB8F7605D971CC7A6D9BA5E67D1AF [F77D70959222276491222F31EBFF3BF1] GoodName=Biohazard 2 (J) [!] CRC=7EAE2488 9D40A35A SaveType=SRAM Players=1 CountPerOp=1 Rumble=Yes [13D7834291A311077B84B9A2816AF6FC] GoodName=Birthday Demo for Steve by Nep (PD) [b1] CRC=C2B35C2F 5CD995A2 [4443B11C457348B0B6B64650909F0143] GoodName=Birthday Demo for Steve by Nep (PD) CRC=C2B35C2F 5CD995A2 [889D4D337AD11CE94357511C725EAB6A] GoodName=Blast Corps (E) (M2) [!] CRC=7C64E6DB 55B924DB Players=1 SaveType=Eeprom 4KB Mempak=Yes [7C9C000B61BF0BCF81AFD4E583EC9B2A] GoodName=Blast Corps (E) (M2) [b1] CRC=7C64E6DB 55B924DB RefMD5=889D4D337AD11CE94357511C725EAB6A [36C97C12DDABB02D7D2D3F6B33B3D83F] GoodName=Blast Corps (E) (M2) [b2] CRC=7C64E6DB 55B924DB RefMD5=889D4D337AD11CE94357511C725EAB6A [A8DFDFF49144627492DA9B0B65B91845] GoodName=Blast Corps (U) (V1.0) [!] CRC=7C647C25 D9D901E6 Players=1 SaveType=Eeprom 4KB Mempak=Yes [000E40366ECE225565D3EC83BE7D97A4] GoodName=Blast Corps (U) (V1.0) [b1] CRC=7C647C25 D9D901E6 RefMD5=A8DFDFF49144627492DA9B0B65B91845 [4BFB72FC9A787543323ADEFC8EC2A042] GoodName=Blast Corps (U) (V1.0) [b2] CRC=7C647C25 D9D901E6 RefMD5=A8DFDFF49144627492DA9B0B65B91845 [5875FC73069077C93E214233B60F0BDC] GoodName=Blast Corps (U) (V1.1) [!] CRC=7C647E65 1948D305 Players=1 SaveType=Eeprom 4KB Mempak=Yes [16B82D53D7F038A8FE67A78027720516] GoodName=Blast Dozer (J) [!] CRC=65234451 EBD3346F Players=1 SaveType=Eeprom 4KB Mempak=Yes [FA3A5597012B710C844682DA586A62C9] GoodName=Blast Dozer (J) [b1] CRC=65234451 EBD3346F RefMD5=16B82D53D7F038A8FE67A78027720516 [31B4A8ED52B48E756B344C9F22736E50] GoodName=Blues Brothers 2000 (E) (M6) [!] CRC=D571C883 822D3FCF Players=2 SaveType=None Mempak=Yes Rumble=Yes [997FD8F79CD6F3CD1C1C1FD21E358717] GoodName=Blues Brothers 2000 (U) [!] CRC=7CD08B12 1153FF89 Players=2 SaveType=None Mempak=Yes Rumble=Yes [96D5910A6FFD3EE53638251ACE86E0CB] GoodName=Blues Brothers 2000 (U) [f1] (PAL-NTSC) CRC=A9A17EF3 AB1F8703 RefMD5=997FD8F79CD6F3CD1C1C1FD21E358717 [A6E03FA194A2932D36E0A67F9F64D92E] GoodName=Blues Brothers 2000 (U) [t1] CRC=A0976BE9 FF41562B RefMD5=997FD8F79CD6F3CD1C1C1FD21E358717 [A8D31D9715BB5645EFC3245A6497F542] GoodName=Blues Brothers 2000 (U) [t1][f1] (PAL-NTSC) CRC=ABB57137 960F561D RefMD5=997FD8F79CD6F3CD1C1C1FD21E358717 [B27FA5E9AD0CB47BB3A74FFAC7BC8EDF] GoodName=Body Harvest (E) (M3) [!] CRC=0B58B8CD B7B291D2 SaveType=Eeprom 4KB Players=1 CountPerOp=1 Rumble=Yes [0EF2448C243F86C4C9F194F49CFD8352] GoodName=Body Harvest (E) (M3) [f1] (NTSC) CRC=6F66B92D 80B9E520 RefMD5=B27FA5E9AD0CB47BB3A74FFAC7BC8EDF [3B8585ED03E8DDB89D7DE456317545E7] GoodName=Body Harvest (U) [!] CRC=5326696F FE9A99C3 Players=1 SaveType=Eeprom 4KB CountPerOp=1 Rumble=Yes [8D21DFCDE6534127CBB444B7361B0D99] GoodName=Body Harvest (U) [T+Spa0.98_jackic] CRC=810CED2D D7B3F710 RefMD5=3B8585ED03E8DDB89D7DE456317545E7 [77554810629D4EF4D93519745FA6066B] GoodName=Body Harvest (U) [b1] CRC=5326696F FE9A99C3 RefMD5=3B8585ED03E8DDB89D7DE456317545E7 [D266B288829193BD8205DDDCDFA5CF30] GoodName=Body Harvest (U) [b1][t1] CRC=C535091F D60CCF6C RefMD5=3B8585ED03E8DDB89D7DE456317545E7 [13532519CBC43BFA638FD5A7754EE281] GoodName=Body Harvest (U) [b2] CRC=00A46EE3 554158C6 RefMD5=3B8585ED03E8DDB89D7DE456317545E7 [D8BD69AEE8246A3127A58E202D447BA1] GoodName=Body Harvest (U) [t1] CRC=C535091F D60CCF6C RefMD5=3B8585ED03E8DDB89D7DE456317545E7 [1CF31E7F6E0DEB2C18C39DDD4EED9E51] GoodName=Bokujou Monogatari 2 (J) (V1.0) [!] CRC=B3D451C6 E1CB58E2 Players=1 Mempak=Yes CountPerOp=1 [C902BB7203C6C77DDA16ABCDF8995E32] GoodName=Bokujou Monogatari 2 (J) (V1.0) [b1] CRC=B3D451C6 E1CB58E2 RefMD5=1CF31E7F6E0DEB2C18C39DDD4EED9E51 [E627B898A7692C08B595A8D2178E34A0] GoodName=Bokujou Monogatari 2 (J) (V1.1) [!] CRC=7365D8F8 9ED9326F RefMD5=1CF31E7F6E0DEB2C18C39DDD4EED9E51 [24E3EE6A54278DB65C463804F2BB6223] GoodName=Bokujou Monogatari 2 (J) (V1.2) [!] CRC=736657F6 3C88A702 RefMD5=1CF31E7F6E0DEB2C18C39DDD4EED9E51 [B68F49AA8F6F7499184AC6B7B8570F2B] GoodName=Bomberman 64 (E) [!] CRC=5A160336 BC7B37B0 Players=4 SaveType=Eeprom 4KB Mempak=Yes [B9E6A38B28108E4D6E6A0A47BF981747] GoodName=Bomberman 64 (E) [b1] CRC=5A160336 BC7B37B0 RefMD5=B68F49AA8F6F7499184AC6B7B8570F2B [4D5C42B239DFD67E40D4E9476A208A1E] GoodName=Bomberman 64 (E) [b2] CRC=5A160336 BC7B37B0 RefMD5=B68F49AA8F6F7499184AC6B7B8570F2B [0283CC125AEA29EF72A03BEE7D759C5D] GoodName=Bomberman 64 (E) [h1C] CRC=5A160336 BC7B37B0 RefMD5=B68F49AA8F6F7499184AC6B7B8570F2B [9976833301116D0CB9E278E857921BF6] GoodName=Bomberman 64 (E) [t1] CRC=938CA401 43339F1B RefMD5=B68F49AA8F6F7499184AC6B7B8570F2B [093058ECE14C8CC1A887B2087EB5CFE9] GoodName=Bomberman 64 (U) [!] CRC=F568D51E 7E49BA1E Players=4 SaveType=Eeprom 4KB Mempak=Yes [BB4C5769EED69362F1A90A2BE19998D6] GoodName=Bomberman 64 (U) [b1] CRC=F568D51E 7E49BA1E RefMD5=093058ECE14C8CC1A887B2087EB5CFE9 [FA4347AC05BC0C0BBC8CABE3ED90B8A4] GoodName=Bomberman 64 (U) [o1] CRC=F568D51E 7E49BA1E RefMD5=093058ECE14C8CC1A887B2087EB5CFE9 [567B8914E0642721408D46627E36003B] GoodName=Bomberman 64 - Arcade Edition (J) [f1] (PAL) CRC=DF6FF0F4 29D14238 RefMD5=08E491F87445C6E5C168D982FC665D5F [852E8651D6C610CE593C35CEA678C9F1] GoodName=Bomberman 64 - Arcade Edition (J) [f2] (PAL-CRC) CRC=E87F1ACE 809F204B RefMD5=08E491F87445C6E5C168D982FC665D5F [D54FD7067BD774E32B57F9C2C0496899] GoodName=Bomberman 64 - Arcade Edition (J) [!] CRC=DF6FF0F4 29D14238 Players=4 [08E491F87445C6E5C168D982FC665D5F] GoodName=Bomberman 64 - Arcade Edition (J) [b1] CRC=DF6FF0F4 29D14238 RefMD5=D54FD7067BD774E32B57F9C2C0496899 [C714806B4CC144A3EABD234C07412109] GoodName=Bomberman 64 - Arcade Edition (J) [T+Eng1.3_Zoinkity] CRC=9780C9FB 67CF6B4A RefMD5=D54FD7067BD774E32B57F9C2C0496899 [AEC1FDB0F1CAAD86C9F457989A4CE482] GoodName=Bomberman 64 - The Second Attack! (U) [!] CRC=237E73B4 D63B6B37 Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [9058970DDF26431A4DAF353C2EEA86AB] GoodName=Bomberman 64 - The Second Attack! (U) [t1][f1] (PAL-NTSC) CRC=9BA3E5CC EB222304 RefMD5=AEC1FDB0F1CAAD86C9F457989A4CE482 [F79EF0813157880FFBAD6199E07579BE] GoodName=Bomberman Hero (E) [!] CRC=D85C4E29 88E276AF Players=1 SaveType=Eeprom 4KB Rumble=Yes [EA6D0EBD673A66C395569A2A230AEA6F] GoodName=Bomberman Hero (E) [b1] CRC=D85C4E29 88E276AF RefMD5=F79EF0813157880FFBAD6199E07579BE [141430D034C16FC4B4BA20D53EAB61C1] GoodName=Bomberman Hero (E) [b2] CRC=D85C4E29 88E276AF RefMD5=F79EF0813157880FFBAD6199E07579BE [8A8E73D70CBC902CD99C7A4E2B982778] GoodName=Bomberman Hero (E) [b3] CRC=D85C4E29 88E276AF RefMD5=F79EF0813157880FFBAD6199E07579BE [008710F628C29D69BD939066A44AB877] GoodName=Bomberman Hero (E) [f1] (NTSC) CRC=D85C4E29 88E276AF RefMD5=F79EF0813157880FFBAD6199E07579BE [EF2453BFF7AD0C4BFA9AB0BD6324EBF3] GoodName=Bomberman Hero (U) [!] CRC=4446FDD6 E3788208 Players=1 SaveType=Eeprom 4KB Rumble=Yes [5642E51D746F603DFE5A71C5CBDB5C73] GoodName=Bomberman Hero (U) [b1] CRC=4446FDD6 E3788208 RefMD5=EF2453BFF7AD0C4BFA9AB0BD6324EBF3 [1143B49D788BA477DAE98C05D6623344] GoodName=Bomberman Hero (U) [b2] CRC=DA573DB9 9442D273 RefMD5=EF2453BFF7AD0C4BFA9AB0BD6324EBF3 [1BCED1BA1BF5A0E2FF5768C714EE4627] GoodName=Bomberman Hero (U) [b3] CRC=DA573DB9 9442D273 RefMD5=EF2453BFF7AD0C4BFA9AB0BD6324EBF3 [8A0479714259954BAE41D5275AC926F4] GoodName=Bomberman Hero (U) [t1] CRC=DA573DB9 9442D273 RefMD5=EF2453BFF7AD0C4BFA9AB0BD6324EBF3 [EE273763C7391458865FF26C7EA0C3F1] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [!] CRC=67FF12CC 76BF0212 Players=1 SaveType=Eeprom 4KB Rumble=Yes [E7D3A4A73D373DA534A025E99B4D0EEF] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b1] CRC=67FF12CC 76BF0212 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [8FA5E55E5597E2615F81CD236DCA4721] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b2] CRC=DDEF1333 E7209D07 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [F39476591E147906291BA48145F304B0] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b3] CRC=DDEF1333 E7209D07 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [49E9C7AACF839E46EA2D255A99FB2613] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b4] CRC=67FF12CC 76BF0212 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [D4806CD9D9DFC7E52D6F825B5D5CC7C2] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b5] CRC=DDEF1333 E7209D07 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [30194320B54FF67CB0CDA5DDB061D933] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b6] CRC=DDEF1333 E7209D07 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [2C68A2D12C1EBFA2AD8F0BE1A09AEEE7] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b7] CRC=67FF12CC 76BF0212 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [4022B2A0F22218870764CDAE73580762] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [b8] CRC=DDEF1333 E7209D07 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [A12B361F9D38FDFE3183C2B4C1F2F217] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [o1] CRC=67FF12CC 76BF0212 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [C4543F27B4E481D0818B51036B67DFEF] GoodName=Bomberman Hero - Mirian Oujo wo Sukue! (J) [t1] CRC=DDEF1333 E7209D07 RefMD5=EE273763C7391458865FF26C7EA0C3F1 [B5772A2827BEFC81E107AE756B36BB2A] GoodName=Boot Emu by Jovis (PD) CRC=2D15DC8C D3BBDB52 [FB19AFD5E8C49978E6E6AE3622E0498A] GoodName=Bottom of the 9th (U) [!] CRC=D72FD14D 1FED32C4 SaveType=None Mempak=Yes Players=2 CountPerOp=1 [6E207C47FAAD2A4F64AE721A3A8F6161] GoodName=Bottom of the 9th (U) [b1] CRC=D72FD14D 1FED32C4 RefMD5=FB19AFD5E8C49978E6E6AE3622E0498A [62E92102D6FD1701A6E904DA6AB58AE8] GoodName=Brunswick Circuit Pro Bowling (U) [!] CRC=1E22CF2E 42AAC813 Players=4 SaveType=None Mempak=Yes [14D070077D70C94CBB1413C7641E7272] GoodName=Brunswick Circuit Pro Bowling (U) [b1] CRC=91644B9F 8CDD0DA5 RefMD5=62E92102D6FD1701A6E904DA6AB58AE8 [2D30FBE45C2858957F9EFDB5E9000033] GoodName=Brunswick Circuit Pro Bowling (U) [o1] CRC=1E22CF2E 42AAC813 RefMD5=62E92102D6FD1701A6E904DA6AB58AE8 [C3A55D506E5BD011EC20F601EA2B33BB] GoodName=Brunswick Circuit Pro Bowling (U) [o1][f1] (PAL) CRC=91644B9F 8CDD0DA5 RefMD5=62E92102D6FD1701A6E904DA6AB58AE8 [A2E4BE02876CB0F0D1E925FF95090C96] GoodName=Buck Bumble (E) (M5) [!] CRC=D5B2339C CABCCAED Players=2 SaveType=None Mempak=Yes Rumble=Yes [AEE981977D8F069003574CD10A268D47] GoodName=Buck Bumble (J) [!] CRC=D7C762B6 F83D9642 Players=2 SaveType=None Mempak=Yes Rumble=Yes [41417FCE2B37EAAE787C5A845A0015C4] GoodName=Buck Bumble (U) [!] CRC=85AE781A C756F05D Players=2 SaveType=None Mempak=Yes Rumble=Yes [01933A0CBBDE1D4EB4C58CC6C6C27633] GoodName=Buck Bumble (U) [b1][t1] CRC=3C2B07FC 8C6AC97B RefMD5=41417FCE2B37EAAE787C5A845A0015C4 [CD19788AE04DAD7AF27FD0C591983CCE] GoodName=Buck Bumble (U) [b2] CRC=E8522F04 43FA513A RefMD5=41417FCE2B37EAAE787C5A845A0015C4 [C129EE8DA7FE1B976D71932733385438] GoodName=Buck Bumble (U) [f1] (PAL) CRC=3C2AC7FA 72BC3A5F RefMD5=41417FCE2B37EAAE787C5A845A0015C4 [28F8F7D8423B291E3056047C62E2937A] GoodName=Buck Bumble (U) [t1] CRC=3C2B07FC 8C6AC97B RefMD5=41417FCE2B37EAAE787C5A845A0015C4 [ED3E962653A1CD56AAB175DEEE6EE52A] GoodName=Bug's Life, A (E) [!] CRC=8F12C096 45DC17E1 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [5BF0F2351AEE577A8345D6E13D197E06] GoodName=Bug's Life, A (E) [f1] (NTSC) CRC=09035DC5 870C1041 RefMD5=ED3E962653A1CD56AAB175DEEE6EE52A [D2860D4FBD0EC4B2711A6EF8D78F9866] GoodName=Bug's Life, A (F) [!] CRC=2B38AEC0 6350B810 SaveType=None Mempak=Yes Rumble=Yes Players=1 CountPerOp=1 [504C92A5978B7EAE7A3FD30645E06D39] GoodName=Bug's Life, A (F) [f1] (NTSC) CRC=BD58346E 67E74459 RefMD5=D2860D4FBD0EC4B2711A6EF8D78F9866 [CBEF54768670F4B5602CCBC90150007A] GoodName=Bug's Life, A (G) [!] CRC=DFF227D9 0D4D8169 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [919E5D60A7F9A79D89AC179123D47EEE] GoodName=Bug's Life, A (G) [f1] (NTSC) CRC=31E33A96 2744267B RefMD5=CBEF54768670F4B5602CCBC90150007A [E3609FD12369C464E832C6D2A4D20790] GoodName=Bug's Life, A (I) [!] CRC=F63B89CE 4582D57D Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [7FD6BFFB80F920E01EF869829D485EA3] GoodName=Bug's Life, A (U) [!] CRC=82DC04FD CF2D82F4 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [14ACC20454B0C2789C9F7EF7A556231A] GoodName=Bug's Life, A (U) [b1] CRC=82DC04FD CF2D82F4 RefMD5=7FD6BFFB80F920E01EF869829D485EA3 [6472BD444D2025B1D883FFAE35D94FD4] GoodName=Bug's Life, A (U) [b1][f1] (PAL) CRC=2FE62885 F6853DAF RefMD5=7FD6BFFB80F920E01EF869829D485EA3 [08E3F4EEEA56C873A84EA076AA362EDD] GoodName=Bug's Life, A (U) [f1] (PAL) CRC=2FE62885 F6853DAF RefMD5=7FD6BFFB80F920E01EF869829D485EA3 [B8B760613CAA702E33F271741170632A] GoodName=Bug's Life, A (U) [t1] CRC=3F4AFB7B 2D24C8F8 RefMD5=7FD6BFFB80F920E01EF869829D485EA3 [30AAE8A534C72FFC89343E8EF0F1C5A1] GoodName=Bug's Life, A (U) [t2] CRC=3F4AFB7B 2D24C8F8 RefMD5=7FD6BFFB80F920E01EF869829D485EA3 [8567382D3CD5BC0406B7B4C780F621DC] GoodName=Bust-A-Move '99 (U) [!] CRC=4222D89F AFE0B637 Players=4 SaveType=None Mempak=Yes Rumble=Yes [B292B14BBC7FFCC2A741FE87A80B8D4D] GoodName=Bust-A-Move '99 (U) [b1] CRC=8AFB2D9A 9F186C02 RefMD5=8567382D3CD5BC0406B7B4C780F621DC [4EA8627701C3D6AF50DDAA607AA3B7F9] GoodName=Bust-A-Move '99 (U) [f1] (PAL) CRC=F23CA406 EC2ACE78 RefMD5=8567382D3CD5BC0406B7B4C780F621DC [094F639A9BA63B2136D2887C8D72BCA0] GoodName=Bust-A-Move 2 - Arcade Edition (E) [!] CRC=CEDCDE1E 513A0502 Players=2 SaveType=None Mempak=Yes [AE0693C8D73E5A1407A2EDF41F1164A9] GoodName=Bust-A-Move 2 - Arcade Edition (E) [b1] CRC=B121ED86 883423F1 RefMD5=094F639A9BA63B2136D2887C8D72BCA0 [8897A39E34AEE4D3F807AF255C6617D6] GoodName=Bust-A-Move 2 - Arcade Edition (U) [!] CRC=8A86F073 CD45E54B Players=2 SaveType=None Mempak=Yes [84DD20F80DB23CB49BFE98639BE6CD71] GoodName=Bust-A-Move 2 - Arcade Edition (U) [b1] CRC=8A86F073 CD45E54B RefMD5=8897A39E34AEE4D3F807AF255C6617D6 [5065D7A833FC73CB75DED8D639AAADA5] GoodName=Bust-A-Move 2 - Arcade Edition (U) [b2] CRC=2D03FD5B D5C096D5 RefMD5=8897A39E34AEE4D3F807AF255C6617D6 [EF3D1E9059723766941FF4E0E913C941] GoodName=Bust-A-Move 2 - Arcade Edition (U) [b3] CRC=322EF540 38D316EB RefMD5=8897A39E34AEE4D3F807AF255C6617D6 [8EEF2BB9543B78197CEDDA6DA860DA97] GoodName=Bust-A-Move 2 - Arcade Edition (U) [b4] CRC=8A86F073 CD45E54B RefMD5=8897A39E34AEE4D3F807AF255C6617D6 [3EA21256DDC4157C3231AE5CC9C4652A] GoodName=Bust-A-Move 3 DX (E) [!] CRC=E328B4FA 004A28E1 Players=4 SaveType=None Mempak=Yes Rumble=Yes [16D7676C2394E422076F7CB855DE901B] GoodName=Bust-A-Move 3 DX (E) [b1] CRC=364C4ADC D3050993 RefMD5=3EA21256DDC4157C3231AE5CC9C4652A [0BD4AEB12E502C39140E4DA52F77642E] GoodName=Bust-A-Move 3 DX (E) [b2] CRC=E328B4FA 004A28E1 RefMD5=3EA21256DDC4157C3231AE5CC9C4652A [089D12EE45BFACD4A9FC93185AF5C42B] GoodName=Bust-A-Move 3 DX (E) [b3] CRC=E328B4FA 004A28E1 RefMD5=3EA21256DDC4157C3231AE5CC9C4652A [1BDC2BFDD0B6CA9D8FD354AEAF1A3CF6] GoodName=Bust-A-Move 3 DX (E) [f1] (NTSC100%) CRC=364C4ADC D3050993 RefMD5=3EA21256DDC4157C3231AE5CC9C4652A [F7CA97BE225630B7690A862FCA97E442] GoodName=Bust-A-Move 3 DX (E) [f2] (NTSC-Z64) CRC=D5BDCD1D 393AFE43 RefMD5=3EA21256DDC4157C3231AE5CC9C4652A [3CA46AD43F9B62DF409759D56468F18E] GoodName=Bust-A-Move 3 DX (E) [f3] (NTSC) CRC=D5BDCD1D 393AFE43 RefMD5=3EA21256DDC4157C3231AE5CC9C4652A [6A78DA715440C0C6872B5D78D31BFD3B] GoodName=CD64 BIOS Direct-Upgrade V1.08 CRC=549EA1B0 F666F794 [176D518AD6E1D89BC0FEF0672A4C1882] GoodName=CD64 BIOS Direct-Upgrade V1.09 CRC=8E3D8D2E 9850573F [0B7C2A6D2B3DE3D7D0FF7AAFAB6F8DA7] GoodName=CD64 BIOS Direct-Upgrade V1.10 CRC=3E93A24F AC2D58E1 [30D7D730E8C131C77EC6F6390B9EB8B3] GoodName=CD64 BIOS Direct-Upgrade V1.11 CRC=FAB972E4 1CB0882B [CF1E4E42B93ECBB080C05B73BB4AF808] GoodName=CD64 BIOS Direct-Upgrade V1.13 CRC=960621E3 7D4D5BB0 [B03E6FAFEA6A314285D0181D5D2ABBAB] GoodName=CD64 BIOS Direct-Upgrade V1.20 CRC=D32264A1 989987EA [A911F13E7D4CF157C79330E908BAE9A7] GoodName=CD64 BIOS Direct-Upgrade V1.21 CRC=4F354F88 A75E40E0 [6711B9D80D4D22AD0DC4AF20C9088763] GoodName=CD64 BIOS Direct-Upgrade V1.23 CRC=AAD9FC15 B2C9DA6F [354E8A1BC64683F01FE598F51D5AB4BE] GoodName=CD64 BIOS Direct-Upgrade V1.30 CRC=6BF11774 D330D7ED [F70A06305D5C545980D9D2D16EF122B2] GoodName=CD64 BIOS EEPROM-Burner V1.08 [a1] CRC=626C7AA3 C1480B86 [4EA4119D7D07FD965BB09A974341E0F3] GoodName=CD64 BIOS EEPROM-Burner V1.08 CRC=57D1CEA5 E2CCC89F [D47EC4844C8C3946A3222FB22E103F04] GoodName=CD64 BIOS EEPROM-Burner V1.09 CRC=CADEA283 46EAF060 [E7C8D1090FA90E9B8C29B48734CF3A78] GoodName=CD64 BIOS EEPROM-Burner V1.10 CRC=BE4AF7A0 14E3D32C [E730EDA716AE40BDBC404F7601491D77] GoodName=CD64 BIOS EEPROM-Burner V1.11 (Even Bytes) CRC=43362020 20202020 [706DB19D4AA4EAF902C8B48544884CEF] GoodName=CD64 BIOS EEPROM-Burner V1.11 (Odd Bytes) CRC=44342020 20202056 [CBEA298BFE9B59BBDBC379ABFD2CD208] GoodName=CD64 BIOS EEPROM-Burner V1.11 CRC=4A0CD2F4 F1F22FE3 [8191F6945DAB90A17E752AA3C94B0402] GoodName=CD64 BIOS EEPROM-Burner V1.21 (Even Bytes) CRC=43362020 20202020 [1DF4F3503FEFFBA6214092E0ABBA33B2] GoodName=CD64 BIOS EEPROM-Burner V1.21 (Odd Bytes) CRC=44342020 20202056 [16E77C21E1EA47FDD8C5635CFFF94BFD] GoodName=CD64 BIOS EEPROM-Burner V1.21 CRC=E74607D1 751139B4 [AAAA0551DB73728D79EBC1D1EDD127F6] GoodName=CD64 BIOS EEPROM-Burner V1.23 (Even Bytes) CRC=43362020 20202020 [168872484F1E933FF351D1C3DC1FC601] GoodName=CD64 BIOS EEPROM-Burner V1.23 (Odd Bytes) CRC=44342020 20202056 [DA027DB6DCB643B0BFCE71720A1F7500] GoodName=CD64 BIOS EEPROM-Burner V1.23 CRC=FE169919 46F54C2D [781AE174BEDA8641E3F0E1EFAD761050] GoodName=CD64 BIOS EEPROM-Burner V1.30 (Even Bytes) CRC=43362020 20202020 [3965F14D450F019BEB8591AA10AFC2BF] GoodName=CD64 BIOS EEPROM-Burner V1.30 (Odd Bytes) CRC=44342020 20202056 [51313E88D86DFF531E386529BBE45DD5] GoodName=CD64 BIOS EEPROM-Burner V1.30 CRC=C7F15051 EE3DEE75 [A99D3F4334F2F59B247FD5CB3DC85A77] GoodName=CD64 Memory Test (PD) CRC=95081A8B 49DFE4FA [226127FDBA21FC9019397ED2C5E5B19F] GoodName=CZN Module Player (PD) CRC=5B9D65DF A18AB4AE [29B79BF5812E5F9E5ECEF073D59F8915] GoodName=California Speed (E) (Prototype) CRC=CA2A7444 71DAB71C SaveType=None Mempak=Yes Players=2 CountPerOp=1 Rumble=Yes [965AD2FA317F0644E49A89A3219719CB] GoodName=California Speed (U) [!] CRC=AC16400E CF5D071A SaveType=None Mempak=Yes Players=2 CountPerOp=1 Rumble=Yes [C95353C14C4AE3DC95D1D91D6566EF92] GoodName=California Speed (U) [f1] (Country Check) CRC=AC16460E 46F60594 RefMD5=965AD2FA317F0644E49A89A3219719CB [7658075D52C403783640DFAC2F8B6A9E] GoodName=California Speed (U) [f2] (PAL) CRC=41D44009 5E94483F RefMD5=965AD2FA317F0644E49A89A3219719CB [EEEAD69D62EB43F093D9D46C38A82AC5] GoodName=California Speed (U) [t1] CRC=150DDE31 969D3994 RefMD5=965AD2FA317F0644E49A89A3219719CB [CA21467BDE6B355E7A15B8F1ADA7B24D] GoodName=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ger) [!] CRC=580162EC E3108BF1 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [A5DB496C328C36682EB770CEFE6C2064] GoodName=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ger) [f1] (NTSC) CRC=BCC83145 6B7F5DA6 RefMD5=CA21467BDE6B355E7A15B8F1ADA7B24D [59EB5646FA079BCBD7A340D7A10196DD] GoodName=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ita) [!] CRC=E48E01F5 E6E51F9B Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [D5271DB3CBE6B24099DCC6878C137FF7] GoodName=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ita) [b1] CRC=E48E01F5 E6E51F9B RefMD5=59EB5646FA079BCBD7A340D7A10196DD [BCD2A45C39128B7D7E29E351788E860E] GoodName=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ita) [f1] (NTSC) CRC=A1CC026F E09D1766 RefMD5=59EB5646FA079BCBD7A340D7A10196DD [3559BE56B70BAFB77C900516B909BFEF] GoodName=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ita) [f2] (NTSC) CRC=5D0283F5 2CDEEA76 RefMD5=59EB5646FA079BCBD7A340D7A10196DD [31BB57C1FAD0D47DC2353C1950B11886] GoodName=Carmageddon 64 (U) [!] CRC=F00F2D4E 340FAAF4 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [57146B6CD8EE7D96B01A811F98A1AC61] GoodName=Castlevania (E) (M3) [!] CRC=64F1B7CA 71A23755 Players=1 SaveType=None Mempak=Yes [DE30F7C3D077778380E2B3D507EFE2D3] GoodName=Castlevania (E) (M3) [b1] CRC=64F1B7CA 71A23755 RefMD5=57146B6CD8EE7D96B01A811F98A1AC61 [96C8DA6D1567F43570CCB362811114DE] GoodName=Castlevania (E) (M3) [t1] CRC=DA0E5024 969ED261 RefMD5=57146B6CD8EE7D96B01A811F98A1AC61 [1CC5CF3B4D29D8C3ADE957648B529DC1] GoodName=Castlevania (U) (V1.0) [!] CRC=F35D5F95 8AFE3D69 Players=1 SaveType=None Mempak=Yes [C19E5A3FCDF52C7292097F215DDC428A] GoodName=Castlevania (U) (V1.0) [b1] CRC=F35D5F95 8AFE3D69 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [1A9EBA4D8CB647FD03AAEB022D04344F] GoodName=Castlevania (U) (V1.0) [b2] CRC=F35D5F95 8AFE3D69 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [A4DB62BABE8583E5F5674FFCFF8B8DFC] GoodName=Castlevania (U) (V1.0) [b3] CRC=F35D5F95 8AFE3D69 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [3E972E3340BED6E47D3C515DD10EAEDA] GoodName=Castlevania (U) (V1.0) [b4] CRC=F35D5F95 8AFE3D69 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [1FEC5A43F756C4AAE958CD286F6451C5] GoodName=Castlevania (U) (V1.0) [t1] CRC=0B28EBA3 5E062616 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [EBDC9053485AAEE05378A9D95D991104] GoodName=Castlevania (U) (V1.0) [t2] CRC=036CBFE5 9E626365 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [8F94C0A43D697D8DEAE9DE660865A966] GoodName=Castlevania (U) (V1.0) [t3] CRC=0B28EBA3 5E062616 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [8ADA90FBD3313D5080007905D183CBD4] GoodName=Castlevania (U) (V1.0) [t4] CRC=0B28EBA3 5E062616 RefMD5=1CC5CF3B4D29D8C3ADE957648B529DC1 [CE71D1CE0A2B6D597F72CB4FC08F5844] GoodName=Castlevania (U) (V1.1) [!] CRC=F35D5335 B7667CB7 Players=1 SaveType=None Mempak=Yes [06B58673F7D31C56F8FE8186E86F6BD6] GoodName=Castlevania (U) (V1.2) [!] CRC=4BCDFF47 AAA3AF8F Players=1 SaveType=None Mempak=Yes [78D5F8A98A5ED21D0817856BCD2AD750] GoodName=Castlevania - Legacy of Darkness (E) (M3) [!] CRC=A2C54BE7 6719CBB2 Players=1 SaveType=None Mempak=Yes [3152B82C03FC7B928D3D5C43F95AEF51] GoodName=Castlevania - Legacy of Darkness (E) (M3) [h1C] CRC=A2C54BE7 6719CBB2 RefMD5=78D5F8A98A5ED21D0817856BCD2AD750 [45EF2794A1AC6AD737288A6577D55194] GoodName=Castlevania - Legacy of Darkness (E) (M3) [o1] CRC=A2C54BE7 6719CBB2 RefMD5=78D5F8A98A5ED21D0817856BCD2AD750 [25258460F98F567497B24844ABE3A05B] GoodName=Castlevania - Legacy of Darkness (U) [!] CRC=1CC06338 87388926 Players=1 SaveType=None Mempak=Yes [5F73634C622ABEDF6204CB801872C79C] GoodName=Castlevania - Legacy of Darkness (U) [b1] CRC=1CC06338 87388926 RefMD5=25258460F98F567497B24844ABE3A05B [2D6ABF559A9AAE65BBEB0E60B3F82D1B] GoodName=Castlevania - Legacy of Darkness (U) [f1] (PAL) CRC=0CE3D2E6 6C6E443D RefMD5=25258460F98F567497B24844ABE3A05B [DE4CA7C5F9DD9216771451A5AFF9F634] GoodName=Castlevania - Legacy of Darkness (U) [f2] (PAL) CRC=7FD0761E 2190A9ED RefMD5=25258460F98F567497B24844ABE3A05B [956FCD46E850E9D10E623C6749D5524E] GoodName=Castlevania - Legacy of Darkness (U) [t1] CRC=64B62D16 43A2A592 RefMD5=25258460F98F567497B24844ABE3A05B [31FB88048076ACE4BD4205C5F40414AB] GoodName=Centre Court Tennis (E) [!] CRC=DCCF2134 9DD63578 Players=4 Mempak=Yes [F52661EF93B9FD4DF16F1F113082AEAA] GoodName=Centre Court Tennis (E) [f1] (NTSC) CRC=B6C4F400 92A39D47 RefMD5=31FB88048076ACE4BD4205C5F40414AB [53EE0172E29CDCBBFA5957A442863E5A] GoodName=Centre Court Tennis (E) [h1C] CRC=DCCF2134 9DD63578 RefMD5=31FB88048076ACE4BD4205C5F40414AB [1CD90B13B7FD6AFDCB838F801D807826] GoodName=Chameleon Twist (E) [!] CRC=B9AF8CC6 DEC9F19F Players=4 SaveType=Eeprom 4KB Rumble=Yes [AB7D5366FEDCF8EC2D414B6001BEB399] GoodName=Chameleon Twist (E) [b1] CRC=B9AF8CC6 DEC9F19F RefMD5=1CD90B13B7FD6AFDCB838F801D807826 [7C74D08A04B6B1B670D90CDB153F083C] GoodName=Chameleon Twist (E) [b2] CRC=B9AF8CC6 DEC9F19F RefMD5=1CD90B13B7FD6AFDCB838F801D807826 [2151AB8629DACD8936439FC90F0AFD10] GoodName=Chameleon Twist (E) [b3] CRC=B9AF8CC6 DEC9F19F RefMD5=1CD90B13B7FD6AFDCB838F801D807826 [3682AEBA1DA191A1CB2C513B1F834F70] GoodName=Chameleon Twist (E) [f1] (NTSC) CRC=4191BA80 41C5E21A RefMD5=1CD90B13B7FD6AFDCB838F801D807826 [C71750C4B84081F3331D957D3FE932AD] GoodName=Chameleon Twist (E) [o1] CRC=B9AF8CC6 DEC9F19F RefMD5=1CD90B13B7FD6AFDCB838F801D807826 [3728BE19FDCFC3ECEBD8C7504C13D1F5] GoodName=Chameleon Twist (E) [o2] CRC=B9AF8CC6 DEC9F19F RefMD5=1CD90B13B7FD6AFDCB838F801D807826 [C0EB519122D63A944A122437EC1B98EE] GoodName=Chameleon Twist (J) [!] CRC=A4F2F521 F0EB168E Players=4 SaveType=Eeprom 4KB Rumble=Yes [397BE52D4FB7DF1E26C6275E05425571] GoodName=Chameleon Twist (U) (V1.0) [!] CRC=6420535A 50028062 Players=4 SaveType=Eeprom 4KB Rumble=Yes [AB299B3943161B9C2ABF03F5A9824E9F] GoodName=Chameleon Twist (U) (V1.0) [b1] CRC=6420535A 50028062 RefMD5=397BE52D4FB7DF1E26C6275E05425571 [959E64F082449BDBD0E5164C32491470] GoodName=Chameleon Twist (U) (V1.0) [b2] CRC=6420535A 50028062 RefMD5=397BE52D4FB7DF1E26C6275E05425571 [277D852DF9C71BE8DCBA01BA8C862482] GoodName=Chameleon Twist (U) (V1.0) [b3] CRC=6420535A 50028062 RefMD5=397BE52D4FB7DF1E26C6275E05425571 [0A04F5F5938218B510A573B86967B199] GoodName=Chameleon Twist (U) (V1.0) [t1] CRC=1CD50DF2 345593AF RefMD5=397BE52D4FB7DF1E26C6275E05425571 [D8A88ACFCD89DF7A59D9A1B050FDA740] GoodName=Chameleon Twist (U) (V1.1) [!] CRC=D81963C7 4271A3AA Players=4 SaveType=Eeprom 4KB Rumble=Yes [45D1D039AB7926ADC748DE640AFD986A] GoodName=Chameleon Twist 2 (E) [!] CRC=07A69D01 9A7D41A1 Players=1 SaveType=None Mempak=Yes Rumble=Yes [3A5EDF7256EA5E7AF4B451E07CC54003] GoodName=Chameleon Twist 2 (E) [b1] CRC=07A69D01 9A7D41A1 RefMD5=45D1D039AB7926ADC748DE640AFD986A [740AD4DB03952BBE997DB09947A41E62] GoodName=Chameleon Twist 2 (J) [!] CRC=0549765A 93B9D042 Players=1 SaveType=None Mempak=Yes Rumble=Yes [7A638431CE966DDA97B282FF04B1D9D7] GoodName=Chameleon Twist 2 (J) [b1] CRC=0549765A 93B9D042 RefMD5=740AD4DB03952BBE997DB09947A41E62 [24658C0D8AC2C4FD58A74F13BCA1D16A] GoodName=Chameleon Twist 2 (J) [b2] CRC=7D5772F8 3A6785EF RefMD5=740AD4DB03952BBE997DB09947A41E62 [99605763AD74D40D5B2D24CF3F0A3CD5] GoodName=Chameleon Twist 2 (J) [b3] CRC=0549765A 93B9D042 RefMD5=740AD4DB03952BBE997DB09947A41E62 [33B9DDDD6D7039CE1C9E6773056A65C8] GoodName=Chameleon Twist 2 (J) [b4] CRC=0549765A 93B9D042 RefMD5=740AD4DB03952BBE997DB09947A41E62 [A55AF433E65E3690E2DC2B16018E9A0F] GoodName=Chameleon Twist 2 (J) [b5] CRC=0549765A 93B9D042 RefMD5=740AD4DB03952BBE997DB09947A41E62 [4C5F3C38743EBB2D12154A83C026DA46] GoodName=Chameleon Twist 2 (J) [o2] CRC=0549765A 93B9D042 RefMD5=740AD4DB03952BBE997DB09947A41E62 [D85C29FD57FE481A34AFBCDB9774395A] GoodName=Chameleon Twist 2 (J) [t1] CRC=7D5772F8 3A6785EF RefMD5=740AD4DB03952BBE997DB09947A41E62 [00327E0B5DF6DCE6DECC31353F33A3D3] GoodName=Chameleon Twist 2 (U) [!] CRC=CD538CE4 618AFCF9 Players=1 SaveType=None Mempak=Yes Rumble=Yes [80F4CD56317218264E35894BA22CAD35] GoodName=Chameleon Twist 2 (U) [t1] CRC=752E1BF8 E81DF66D RefMD5=00327E0B5DF6DCE6DECC31353F33A3D3 [4A3263EAB67FAB2D1171A23765D73AC6] GoodName=Chaos 89 Demo (PD) CRC=EDA1A0C7 58EE0464 [DD53E1F83E8789D23DF6AF942FFEF236] GoodName=Charlie Blast's Territory (E) [!] CRC=FB3C48D0 8D28F69F SaveType=None Players=4 CountPerOp=1 Rumble=Yes [A7C15E0C1E7D898C1B20276DF7A62660] GoodName=Charlie Blast's Territory (E) [o1] CRC=FB3C48D0 8D28F69F RefMD5=DD53E1F83E8789D23DF6AF942FFEF236 [747E76D50DC3C06FD35E146129706A60] GoodName=Charlie Blast's Territory (U) [!] CRC=1E0E96E8 4E28826B SaveType=None Players=4 CountPerOp=1 Rumble=Yes [59FA8C6D533D36C0FFC2AAFAB7166E6F] GoodName=Charlie Blast's Territory (U) [b1] CRC=1E0E96E8 4E28826B RefMD5=747E76D50DC3C06FD35E146129706A60 [7FFD84FC7D112EAB4EEF15CB10189A38] GoodName=Charlie Blast's Territory (U) [hIR] CRC=1E0E96E8 4E28826B RefMD5=747E76D50DC3C06FD35E146129706A60 [7CBB43473597F48AA9A8E0B0D38CE685] GoodName=Charlie Blast's Territory (U) [hI] CRC=A6FD0808 6E6B3ECA RefMD5=747E76D50DC3C06FD35E146129706A60 [8F6BED633BE214CF039DBDAC356231CE] GoodName=Chopper Attack (E) [!] CRC=2E359339 3FA5EDA6 Players=1 SaveType=Eeprom 4KB Rumble=Yes [AC129AB2688C02419FC190A87F2A2E93] GoodName=Chopper Attack (E) [b1] CRC=2E359339 3FA5EDA6 RefMD5=8F6BED633BE214CF039DBDAC356231CE [0A3955C704210225D95937DCAB86C9E3] GoodName=Chopper Attack (E) [t1] CRC=D852E238 0E52A960 RefMD5=8F6BED633BE214CF039DBDAC356231CE [C37E8AFB4F3ECC86D01CE7388CA59347] GoodName=Chopper Attack (U) [!] CRC=214CAD94 BE1A3B24 Players=1 SaveType=Eeprom 4KB Rumble=Yes [14AEB927F3620EFE48AF7FC748C1931F] GoodName=Chopper Attack (U) [b1] CRC=ACBF6069 EABEE162 RefMD5=C37E8AFB4F3ECC86D01CE7388CA59347 [B8BEA2194D7D75A1711C024F5069D18E] GoodName=Chopper Attack (U) [b2] CRC=214CAD94 BE1A3B24 RefMD5=C37E8AFB4F3ECC86D01CE7388CA59347 [34957B173CD33C999B954E7034FC01EA] GoodName=Chopper Attack (U) [b3] CRC=214CAD94 BE1A3B24 RefMD5=C37E8AFB4F3ECC86D01CE7388CA59347 [B34CBCA3EEE5C010FF3E504AF2064069] GoodName=Chopper Attack (U) [b4] CRC=BF5D6D65 3F4A9C03 RefMD5=C37E8AFB4F3ECC86D01CE7388CA59347 [5FA39EF0EBE18DA55C260A3A89F935B6] GoodName=Chopper Attack (U) [b5] CRC=214CAD94 BE1A3B24 RefMD5=C37E8AFB4F3ECC86D01CE7388CA59347 [64C75E19890ACDE25842A815A21D55C9] GoodName=Chopper Attack (U) [b6] CRC=214CAD94 BE1A3B24 RefMD5=C37E8AFB4F3ECC86D01CE7388CA59347 [F10D601D64786C52CAC1FD0AB5511C82] GoodName=Chopper Attack (U) [t1] CRC=BF5D6D65 3F4A9C03 RefMD5=C37E8AFB4F3ECC86D01CE7388CA59347 [8287A908E36E79B2D3AF0BD22C43ECD9] GoodName=Choro Q 64 (J) [!] CRC=2BCCF9C4 403D9F6F Players=4 SaveType=Eeprom 4KB Mempak=Yes [2C944319017A21652566CC4196C714CC] GoodName=Choro Q 64 (J) [b1] CRC=2BCCF9C4 403D9F6F RefMD5=8287A908E36E79B2D3AF0BD22C43ECD9 [470E1635A9693102B426A840DBD691E5] GoodName=Choro Q 64 (J) [b2] CRC=2BCCF9C4 403D9F6F RefMD5=8287A908E36E79B2D3AF0BD22C43ECD9 [04A2C1A6EFAE28E07A4AD77603081F86] GoodName=Choro Q 64 (J) [b3] CRC=2BCCF9C4 403D9F6F RefMD5=8287A908E36E79B2D3AF0BD22C43ECD9 [5F4D852BD3B707C1B4FE29F2FE19C687] GoodName=Choro Q 64 (J) [b4] CRC=2BCCF9C4 403D9F6F RefMD5=8287A908E36E79B2D3AF0BD22C43ECD9 [7151AE130BA8DC97A205B62FF0EE0FB6] GoodName=Choro Q 64 (J) [h1C] CRC=2BCCF9C4 403D9F6F RefMD5=8287A908E36E79B2D3AF0BD22C43ECD9 [9081370141079031EBBDBCA56FC8C7D8] GoodName=Choro Q 64 II - Hacha Mecha Grand Prix Race (J) [!] CRC=26CD0F54 53EBEFE0 Players=4 Mempak=Yes Rumble=Yes Transferpak=Yes [78838C202C4FF5A460586451EE9182AA] GoodName=Chou Kuukan Night Pro Yakyuu King (J) [!] CRC=8ACE6683 3FBA426E Players=4 Mempak=Yes [5224CCBE260A4B7713D662D9BC269063] GoodName=Chou Kuukan Night Pro Yakyuu King (J) [b1] CRC=8ACE6683 3FBA426E RefMD5=78838C202C4FF5A460586451EE9182AA [9C39391D103E6DB39CEC6C774EDB082A] GoodName=Chou Kuukan Night Pro Yakyuu King (J) [h1C] CRC=8ACE6683 3FBA426E RefMD5=78838C202C4FF5A460586451EE9182AA [97EAB4DC83DA0AD2890DE2AAAA5D109A] GoodName=Chou Kuukan Night Pro Yakyuu King 2 (J) [!] CRC=3A180FF4 5C8E8AF7 Players=4 Mempak=Yes Rumble=Yes [9466618F4497DA6C9091E05CC9666786] GoodName=Chou Snobow Kids (J) [!] CRC=A7941528 61F1199D Players=4 SaveType=Eeprom 4KB Rumble=Yes [74341014043CC42D8804DADBF252B344] GoodName=Chou Snobow Kids (J) [f1] (PAL) CRC=2FEB152B 9C205EA5 RefMD5=9466618F4497DA6C9091E05CC9666786 [BA145D51B681EF4432DB59C1DA703047] GoodName=Christmas Flame Demo by Halley's Comet Software (PD) CRC=B484EB31 D44B1928 [2A0BF5A9A136D57AF01D199B16899634] GoodName=City-Tour GP - Zennihon GT Senshuken (J) [!] CRC=F8009DB0 6B291823 Players=2 SaveType=Eeprom 16KB Mempak=Yes Rumble=Yes CountPerOp=1 [4808E8129B22AC8B3185B37243113005] GoodName=City-Tour GP - Zennihon GT Senshuken (J) [b1] CRC=F8009DB0 6B291823 RefMD5=2A0BF5A9A136D57AF01D199B16899634 [2BD614A2A1A317ECBEEB4193954C5FA5] GoodName=City-Tour GP - Zennihon GT Senshuken (J) [b2] CRC=F8009DB0 6B291823 RefMD5=2A0BF5A9A136D57AF01D199B16899634 [E226801C0B57FD2F2D2E303986DB5E5C] GoodName=City-Tour GP - Zennihon GT Senshuken (J) [b3] CRC=F8009DB0 6B291823 RefMD5=2A0BF5A9A136D57AF01D199B16899634 [30E7E083B978408D5B7760D0CE4DC61D] GoodName=Clay Fighter - Sculptor's Cut (U) [!] CRC=FA5A3DFF B4C9CDB9 SaveType=None Players=4 [052BB2C8C4174633A0D38DEB4D31C719] GoodName=Clay Fighter - Sculptor's Cut (U) [b1] CRC=FA5A3DFF B4C9CDB9 RefMD5=30E7E083B978408D5B7760D0CE4DC61D [D47AB8CA78D9686A7021EBBBA00B0AA0] GoodName=Clay Fighter - Sculptor's Cut (U) [b2] CRC=FA5A3DFF B4C9CDB9 RefMD5=30E7E083B978408D5B7760D0CE4DC61D [B8047551F6E44E367862E9BC9C2A4DDF] GoodName=Clay Fighter - Sculptor's Cut (U) [h1C] CRC=FA5A3DFF B4C9CDB9 RefMD5=30E7E083B978408D5B7760D0CE4DC61D [CCD869C8D45C3998ADDCBF43791D6C56] GoodName=Clay Fighter - Sculptor's Cut (U) [h2C] CRC=FA5A3DFF B4C9CDB9 RefMD5=30E7E083B978408D5B7760D0CE4DC61D [CD00C317003B03CD0BBEEC4570D2B55D] GoodName=Clay Fighter - Sculptor's Cut (U) [t1] CRC=6C48FE11 8E1A27EC RefMD5=30E7E083B978408D5B7760D0CE4DC61D [CBBEAFF5A9074D1A5507CF46CD683D36] GoodName=Clay Fighter 63 1-3 (Beta) [!] CRC=2B6FA7C0 09A71225 Players=4 SaveType=None [BE41BA94878999987DC8D2FD3A5551D9] GoodName=Clay Fighter 63 1-3 (Beta) [b1] CRC=2B6FA7C0 09A71225 [41965B533F3DD95663361D9DF68B0C1F] GoodName=Clay Fighter 63 1-3 (E) [!] CRC=8E9692B3 4264BB2A Players=4 SaveType=None [46B95EA3EB82654439A6750443BCDE53] GoodName=Clay Fighter 63 1-3 (E) [b1][h1C] CRC=8E9692B3 4264BB2A RefMD5=41965B533F3DD95663361D9DF68B0C1F [2084974C9098B2D01C1F58B0E56EE058] GoodName=Clay Fighter 63 1-3 (E) [h1C] CRC=8E9692B3 4264BB2A RefMD5=41965B533F3DD95663361D9DF68B0C1F [3207BF22E305C488109B09A03706F36F] GoodName=Clay Fighter 63 1-3 (U) [!] CRC=F03C24CA C5237BCC Players=4 SaveType=None [7A4ACAB8997D180C045D9286C917ED1B] GoodName=Clay Fighter 63 1-3 (U) [b1] CRC=F03C24CA C5237BCC RefMD5=3207BF22E305C488109B09A03706F36F [0EDBCB64159B7E32DDA165A7A363AB35] GoodName=Clay Fighter 63 1-3 (U) [b2] CRC=F03C24CA C5237BCC RefMD5=3207BF22E305C488109B09A03706F36F [D41EE755C8DDF4BBD5E368670C672488] GoodName=Clay Fighter 63 1-3 (U) [o1] CRC=2B6FA7C0 09A71225 RefMD5=3207BF22E305C488109B09A03706F36F [6746F4CC43ACEBF3F04B1677B16C1935] GoodName=Clay Fighter 63 1-3 (U) [o2] CRC=F03C24CA C5237BCC RefMD5=3207BF22E305C488109B09A03706F36F [0E38732BC5F564D74D57EF0A0CBA8D56] GoodName=Cliffi's Little Intro by Cliffi (POM '99) (PD) [b1] CRC=10637557 03E93693 [BE2AB7CD9DBDDA8DDAE1EA288C663F15] GoodName=Cliffi's Little Intro by Cliffi (POM '99) (PD) CRC=4B0313E2 65657446 [42DA4C7D040F9E7CD046A42EC3E68027] GoodName=Command & Conquer (E) (M2) [!] CRC=AE5B9465 C54D6576 Players=1 SaveType=Flash RAM Rumble=Yes [4D972AE7FAA1AA3ED26026F6F46C8A6A] GoodName=Command & Conquer (E) (M2) [b1] CRC=AE5B9465 C54D6576 RefMD5=42DA4C7D040F9E7CD046A42EC3E68027 [C0CC62AC4B06416C9DB5B765ADE5F626] GoodName=Command & Conquer (E) (M2) [b2] CRC=AE5B9465 C54D6576 RefMD5=42DA4C7D040F9E7CD046A42EC3E68027 [1D26E8B65CD2F1BF1EABAFFDBBFC1F26] GoodName=Command & Conquer (E) (M2) [b3] CRC=AE5B9465 C54D6576 RefMD5=42DA4C7D040F9E7CD046A42EC3E68027 [E19F762182F4B4ADF5D8F6D998033059] GoodName=Command & Conquer (E) (M2) [f1] (Z64) CRC=EA630EC7 2B2F37F3 RefMD5=42DA4C7D040F9E7CD046A42EC3E68027 [1A9195662C89DCBEA88BCFA99B096CDE] GoodName=Command & Conquer (G) [!] CRC=B5025BAD D32675FD Players=1 SaveType=Flash RAM Rumble=Yes [19A646E0148EA6695E797C1990919B8A] GoodName=Command & Conquer (G) [f1] (Z64) CRC=705AC38A A8D714E8 RefMD5=1A9195662C89DCBEA88BCFA99B096CDE [B436F4717AC585B0D847756468FD6393] GoodName=Command & Conquer (U) [!] CRC=95286EB4 B76AD58F Players=1 SaveType=Flash RAM Rumble=Yes [57044E8F223D117F55B22E7FD2EDF71E] GoodName=Command & Conquer (U) [b1] CRC=F921961E E09D8B11 RefMD5=B436F4717AC585B0D847756468FD6393 [715D537C6D78440C085DDD22E827C260] GoodName=Command & Conquer (U) [f1] (Z64) CRC=22AD2E8E 73CC712C RefMD5=B436F4717AC585B0D847756468FD6393 [B206F917C1B4FD41CDADC4064C48B07B] GoodName=Congratulations Demo for SPLiT by Widget and Immortal (PD) [b1] CRC=D2B908C8 E0E73A1D [2616B2901F794EADFD26D5FA2BF5564D] GoodName=Congratulations Demo for SPLiT by Widget and Immortal (PD) CRC=D2B908C8 E0E73A1D [05194D49C14E52055DF72A54D40791E1] GoodName=Conker's Bad Fur Day (E) [!] CRC=373F5889 9A6CA80A SaveType=Eeprom 16KB Players=4 Rumble=Yes [70E9EB9BF2F7BC76CA38CE450BA01C2E] GoodName=Conker's Bad Fur Day (U) (Debug Version) [f1] (Decrypted) CRC=8BC3A47A 74221294 RefMD5=00E2920665F2329B95797A7EAABC2390 [13ECBAEEF7111D5343D73A80E03E353A] GoodName=Conker's Bad Fur Day (U) (Demo) (V_ECTS_Decrypted) CRC=A08D0F77 6F82E38C Players=4 Rumble=Yes [00E2920665F2329B95797A7EAABC2390] GoodName=Conker's Bad Fur Day (U) [!] CRC=30C7AC50 7704072D SaveType=Eeprom 16KB Players=4 Rumble=Yes [256564DAF29311497917BAAA14ED3F6D] GoodName=Conker's Bad Fur Day (U) [T+Fre1.3_Corrigo] CRC=30C7AC50 7704072D RefMD5=00E2920665F2329B95797A7EAABC2390 [79A8A007092D1E5B00D0ED94F83620EB] GoodName=Conker's Bad Fur Day (U) [T+Spa1.1_Blade133bo] CRC=34AEB154 A4253B86 RefMD5=00E2920665F2329B95797A7EAABC2390 [DB7A03B77D44DB81B8A3FCDFC4B72D8C] GoodName=Cruis'n Exotica (U) [!] CRC=46A3F7AF 0F7591D0 SaveType=Eeprom 4KB Players=2 Rumble=Yes [A8266778591994EFA3A3B9E6E806F8C8] GoodName=Cruis'n Exotica (U) [t1] CRC=1E4C4743 FEA2C4D1 RefMD5=DB7A03B77D44DB81B8A3FCDFC4B72D8C [69CD5BA6BC9310B9E37CCB1BC6BD16AD] GoodName=Cruis'n USA (E) [!] CRC=503EA760 E1300E96 Players=2 SaveType=Eeprom 4KB Mempak=Yes [00A3E885F8D899646228A21D946B2102] GoodName=Cruis'n USA (U) (V1.0) [!] CRC=FF2F2FB4 D161149A Players=2 SaveType=Eeprom 4KB Mempak=Yes [190906A8A5F1C1D4909F6374A784ECA4] GoodName=Cruis'n USA (U) (V1.0) [T+Ita0.40] CRC=FF2F2FB4 D161149A RefMD5=00A3E885F8D899646228A21D946B2102 [635C94434922DC73C58965004E3F699D] GoodName=Cruis'n USA (U) (V1.0) [b1] CRC=FF2F2FB4 D161149A RefMD5=00A3E885F8D899646228A21D946B2102 [D37AB17D3E27ED333704C44DCFAA28E7] GoodName=Cruis'n USA (U) (V1.0) [b2] CRC=FF2F2FB4 D161149A RefMD5=00A3E885F8D899646228A21D946B2102 [1D4843F0C69E273A1099A4267BB9F526] GoodName=Cruis'n USA (U) (V1.0) [b3] CRC=FF2F2FB4 D161149A RefMD5=00A3E885F8D899646228A21D946B2102 [B0679C685A1FB4D2BA96E4BB941262DE] GoodName=Cruis'n USA (U) (V1.0) [b4] CRC=FF2F2FB4 D161149A RefMD5=00A3E885F8D899646228A21D946B2102 [A8D5B5F1902AFB1346D97A9D0D52B292] GoodName=Cruis'n USA (U) (V1.0) [b5] CRC=FF2F2FB4 D161149A RefMD5=00A3E885F8D899646228A21D946B2102 [41CA21BD737E16BA81168982B74276F1] GoodName=Cruis'n USA (U) (V1.0) (VC) [!] CRC=FF2F2FB4 D161149A RefMD5=00A3E885F8D899646228A21D946B2102 [45FC88E2BA6711F25F0DE988E719DF29] GoodName=Cruis'n USA (U) (V1.1) [!] CRC=5306CF45 CBC49250 Players=2 SaveType=Eeprom 4KB Mempak=Yes [2838A9018AD2BCB8B7F6161C746A1B71] GoodName=Cruis'n USA (U) (V1.2) [!] CRC=B3402554 7340C004 Players=2 SaveType=Eeprom 4KB Mempak=Yes [AF950A1B6C460D7FC3E78375D35047EF] GoodName=Cruis'n World (E) [!] CRC=83F3931E CB72223D SaveType=Eeprom 16KB Players=4 Rumble=Yes [20DB5E4DDB0CD5B04C4BF09CDC95592F] GoodName=Cruis'n World (E) (V1.1) [!] CRC=33E61153 97A2E2C5 SaveType=Eeprom 16KB Players=4 Rumble=Yes [626478CC0790B1452045A3D853B46C18] GoodName=Cruis'n World (E) [b1] CRC=312E2FC5 CB76AB4D RefMD5=AF950A1B6C460D7FC3E78375D35047EF [942A09966EC752A5EE81D042AF11D4BB] GoodName=Cruis'n World (E) [b2] CRC=AFF44E2D 2ECB9679 RefMD5=AF950A1B6C460D7FC3E78375D35047EF [B22A6E184CB0657882CB4D6A81534254] GoodName=Cruis'n World (E) [f1] CRC=AFF44E2D 2ECB9679 RefMD5=AF950A1B6C460D7FC3E78375D35047EF [0BD71426A0240CA4D871A8F54B7761F0] GoodName=Cruis'n World (E) [f2] CRC=AFF44E2D 2ECB9679 RefMD5=AF950A1B6C460D7FC3E78375D35047EF [12CE267F5D538C2959BDEBA5E87BDE79] GoodName=Cruis'n World (E) [f3] (NTSC) CRC=AF3E4E2D 9C63E651 RefMD5=AF950A1B6C460D7FC3E78375D35047EF [AADA4CBD938E58A447B399A1D46F03E6] GoodName=Cruis'n World (U) [!] CRC=DFE61153 D76118E6 SaveType=Eeprom 16KB Players=4 Rumble=Yes [B97C963235635672CBEAB35154DFDFA2] GoodName=Cruis'n World (U) [b1] CRC=E2A32049 46E8F8E2 RefMD5=AADA4CBD938E58A447B399A1D46F03E6 [82C6213EF921BF2805B3CA7CA4F08BFB] GoodName=Cruis'n World (U) [b2] CRC=E2A32049 46E8F8E2 RefMD5=AADA4CBD938E58A447B399A1D46F03E6 [63DA3150AC7B603187DE3951A3270F6E] GoodName=Cruis'n World (U) [b3] CRC=DFE61153 D76118E6 RefMD5=AADA4CBD938E58A447B399A1D46F03E6 [4BCDE237F4A390A564369696D0579760] GoodName=Cruis'n World (U) [f1] CRC=E2A32049 46E8F8E2 RefMD5=AADA4CBD938E58A447B399A1D46F03E6 [AD4A781024E29F4A735CB4B87F2D59DB] GoodName=Cruis'n World (U) [o1] CRC=DFE61153 D76118E6 RefMD5=AADA4CBD938E58A447B399A1D46F03E6 [8D4DAA86BF542D8A55460F56C52F7D02] GoodName=Cube Demo (PD) CRC=0E3ED77B 8E1C26FD [6F936ECE2BA8EA8C74BDBBA9BDA1407A] GoodName=Cube Demo (PD) [b1] CRC=0E3ED77B 8E1C26FD RefMD5=8D4DAA86BF542D8A55460F56C52F7D02 [9A3014ED85F796CCB836E85E78D2618A] GoodName=Cube Demo (PD) [b2] CRC=0E3ED77B 8E1C26FD RefMD5=8D4DAA86BF542D8A55460F56C52F7D02 [827CFFD3648116511ED2D5DA76C83FBB] GoodName=Cube Demo by Msftug (PD) CRC=37BDF228 92CF779C [33F2BC6847985F96DE8177147DCD3B85] GoodName=Custom Robo (Ch) (iQue) [!] Players=2 [A06D2E83CF2628915E8847F609474661] GoodName=Custom Robo (J) [!] CRC=83CB0B87 7E325457 Players=2 [115118DD5E0F02D82BA1BF070A7B78F1] GoodName=Custom Robo V2 (J) [!] CRC=079501B9 AB0232AB Players=4 SaveType=Eeprom 16KB Rumble=Yes [8C4A4CD472D610CDA5459B3A92F21D30] GoodName=CyberTiger (E) [!] CRC=D1A78A07 52A3DD3E Players=4 SaveType=None Mempak=Yes Rumble=Yes [88072F30D4F9CF384B2B3A0300649218] GoodName=CyberTiger (U) [!] CRC=E8FC8EA1 9F738391 Players=4 SaveType=None Mempak=Yes Rumble=Yes [9801AAA87D650C42B021F94D5C34C7A4] GoodName=DKONG Demo (PD) CRC=B323E37C BBC35EC4 [F0D62C8FD773F55A34EAAC20D3B95F17] GoodName=DS1 Manager V1.0 by R. Bubba Magillicutty (PD) CRC=1194FFD2 808C6FB1 [4F94D90294D6E5C1FC116E073DD3F542] GoodName=DS1 Manager V1.1 by R. Bubba Magillicutty (PD) CRC=D7484C2A 56CFF26D [52037ED117D09F46F82C3F72044366E7] GoodName=DS1 SRAM Manager V1.1 by _Sage_ (PD) CRC=201DA461 EC0C992B [0B86FA9259E2B751111A1701091644B1] GoodName=Dance Dance Revolution - Disney Dancing Museum (J) [!] CRC=7188F445 84410A68 Players=2 Rumble=Yes [3A1488C2A8A8F2AB9368D7C056EB02A2] GoodName=Dance Dance Revolution - Disney Dancing Museum (J) [o1] CRC=7188F445 84410A68 RefMD5=0B86FA9259E2B751111A1701091644B1 [885A29B9A52183B96E5D636F2B765231] GoodName=Dance Dance Revolution - Disney Dancing Museum (J) [o2] CRC=7188F445 84410A68 RefMD5=0B86FA9259E2B751111A1701091644B1 [4242FDE5B74F22AAF5746459E126121F] GoodName=Dark Rift (E) [!] CRC=7ED67CD4 B4415E6D Players=2 SaveType=None [0DD2887AF64C5786C1C66877AFCC0B97] GoodName=Dark Rift (E) [b1] CRC=7ED67CD4 B4415E6D RefMD5=4242FDE5B74F22AAF5746459E126121F [ECB170EBBFDA0E932C07524040BCC36C] GoodName=Dark Rift (U) [!] CRC=A4A52B58 23759841 Players=2 SaveType=None [CBFEAD02C508DADFB44A00E7F7ED61B8] GoodName=Dark Rift (U) [t1] CRC=DAA66890 ED4CCD04 RefMD5=ECB170EBBFDA0E932C07524040BCC36C [A2A4A0318DAB366A595336B6F80FF3AB] GoodName=Deadly Arts (U) [!] CRC=F5363349 DBF9D21B Players=2 SaveType=None Mempak=Yes Rumble=Yes [F403FCEB3FCD41BB5830142989FC9486] GoodName=Deadly Arts (U) [b1] CRC=F5363349 DBF9D21B RefMD5=A2A4A0318DAB366A595336B6F80FF3AB [C644E318B33C4EBD94695C0C3E1E80FF] GoodName=Defi au Tetris Magique (F) [!] CRC=3F66A9D9 9BCB5B00 SaveType=None Players=2 Rumble=Yes [772FA166E5DB51EFFC77FB8D832AC4D2] GoodName=Densha de Go! 64 (J) [!] CRC=17C54A61 4A83F2E7 Players=1 SaveType=Eeprom 16KB Rumble=Yes CountPerOp=1 [BA99C445ADC6994C97FE6463F3E0EC10] GoodName=Densha de Go! 64 (J) [f1] (PAL) CRC=CF138879 2A6144CB RefMD5=772FA166E5DB51EFFC77FB8D832AC4D2 [FDFFA662AE3357BF5970338EE7589F6C] GoodName=Densha de Go! 64 (J) (Localization Patch v1.01) CRC=68D128AE 67D60F21 RefMD5=772FA166E5DB51EFFC77FB8D832AC4D2 Transferpak=Yes [1051E1402EE110F3C5E372C9E1C5B338] GoodName=Derby Stallion 64 (J) (Beta) CRC=96BA4EFB C9988E4E Players=4 SaveType=Flash RAM Mempak=Yes [7F57463856540104B21A5289312B626F] GoodName=Derby Stallion 64 (J) [!] CRC=A5F667E1 DA1FBD1F Players=4 SaveType=Flash RAM Mempak=Yes [BDA717ECC8434F12F313342485828B58] GoodName=Destruction Derby 64 (E) (M3) [!] CRC=630AA37D 896BD7DB Players=4 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [7FCCB47498EEC06E96AE9372247D1E90] GoodName=Destruction Derby 64 (U) [!] CRC=DEE584A2 0F161187 Players=4 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [02EEF6ED11174664A548626337879E8C] GoodName=Destruction Derby 64 (U) [f1] (PAL) CRC=8637C692 CAD23999 RefMD5=7FCCB47498EEC06E96AE9372247D1E90 [825EA802BC3CBA523667B64DD696C597] GoodName=Destruction Derby 64 (U) [t1] CRC=8637BEAA 9B0EB296 RefMD5=7FCCB47498EEC06E96AE9372247D1E90 [6D75719BFA6244C4591070D3F7356072] GoodName=Dexanoid R1 by Protest Design (PD) CRC=76712159 35666812 Players=1 SaveType=None Status=3 Rumble=No [875FA77726E7CD99BD410E3FC86C7777] GoodName=Dexanoid R1 by Protest Design (PD) [b1] CRC=1EDA4DE0 22BF698D RefMD5=6D75719BFA6244C4591070D3F7356072 [CF2276AFD84E06AC780DBA2E0EA4806D] GoodName=Dexanoid R1 by Protest Design (PD) [f1] (PAL) CRC=CFEAACE9 1D532607 RefMD5=6D75719BFA6244C4591070D3F7356072 [AE13E575386775E766F0E00AD2A40C9E] GoodName=Dexanoid R1 by Protest Design (PD) [f2] (PAL) CRC=3C7AEE05 56099CB6 RefMD5=6D75719BFA6244C4591070D3F7356072 [8E4D5C6D95EFD1C94BB13644F7672909] GoodName=Dexanoid R1 by Protest Design (PD) [t1] CRC=0EC580B5 EBEE9C03 RefMD5=6D75719BFA6244C4591070D3F7356072 [54BE265E7B2C28AB92BF1A4130ACB5A2] GoodName=Dezaemon 3D (J) [!] CRC=8979169C F189F6A0 Players=1 Rumble=Yes [01E34CD8A451F0B5AEF93CCF9ADB37AF] GoodName=Dezaemon 3D (J) [b1] CRC=8979169C F189F6A0 RefMD5=54BE265E7B2C28AB92BF1A4130ACB5A2 [60A5F3E1E94F696BF5384022247B4059] GoodName=Dezaemon 3D (J) [b1][t1] CRC=33487563 AC0AE62A RefMD5=54BE265E7B2C28AB92BF1A4130ACB5A2 [358941CA393F6D7415E99B28D49CCF68] GoodName=Dezaemon 3D (J) [b2] CRC=8979169C F189F6A0 RefMD5=54BE265E7B2C28AB92BF1A4130ACB5A2 [108B1A72E6F93E6935E1AD8D619797DB] GoodName=Dezaemon 3D (J) [t1] CRC=33487563 AC0AE62A RefMD5=54BE265E7B2C28AB92BF1A4130ACB5A2 [820929EBBE6FD332AC1720F94B745A8B] GoodName=Die Hard 64 (U) (Prototype) (Level 1) CRC=870611BA D8B1226C [3D1E03B097F2124F8F713013D8219291] GoodName=Die Hard 64 (U) (Prototype) (Level 2) CRC=08D49262 03763D39 [1B28C4CA21648D318BC6DD3EF27BB1FA] GoodName=Die Hard 64 (U) (Prototype) (Level 3) CRC=A1F51C25 16D61291 [0F0B7B78B345FBF2581D834CB4A81245] GoodName=Diddy Kong Racing (E) (M3) (V1.0) [!] CRC=FD73F775 9724755A Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [79748E4E030B047DBAE8252C21305C75] GoodName=Diddy Kong Racing (E) (M3) (V1.0) [f1] CRC=85443325 77D72F56 RefMD5=0F0B7B78B345FBF2581D834CB4A81245 [542FED7864218156EA90050013CD048E] GoodName=Diddy Kong Racing (E) (M3) (V1.0) [o1] CRC=FD73F775 9724755A RefMD5=0F0B7B78B345FBF2581D834CB4A81245 [6B2BAFE540E0AF052A78E85B992BE999] GoodName=Diddy Kong Racing (E) (M3) (V1.1) [!] CRC=596E145B F7D9879F Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [14ABD7C0FA3B5256FC62824039F06A20] GoodName=Diddy Kong Racing (E) (M3) (V1.1) [T+Ita1.0_Rulesless] CRC=568E02F5 E212A80C RefMD5=6B2BAFE540E0AF052A78E85B992BE999 [35CF26D4D33717BA730D7978E2F2107D] GoodName=Diddy Kong Racing (E) (M3) (V1.1) [f1] (Z64) CRC=D84C17CA 13F8F651 RefMD5=6B2BAFE540E0AF052A78E85B992BE999 [10747662A55241B9234CD114C940504F] GoodName=Diddy Kong Racing (J) [!] CRC=7435C9BB 39763CF4 Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [0D68A405BCB04318A294DBEABF1DE063] GoodName=Diddy Kong Racing (J) [f1] (Z64) CRC=F389A35A 17785562 RefMD5=10747662A55241B9234CD114C940504F [4F0E07F0EEAC7E5D7CE3A75461888D03] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [!] CRC=53D440E7 7519B011 Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [94D81D14A2D768DD0EDA3A845AFB25CD] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [T+Bra_EmuBrazil] CRC=53D440E7 7519B011 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [49551E729A39F9640058AB5771A49311] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [b1] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [DBE3F0869F817DCD52A5CB9D43BB4FD1] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [b2] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [AB34FECD9A7A1030EC0892328F9CEF8A] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [b3] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [699A6BA5281EA0C83190E9D45C708C26] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [b4] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [F388EE4148A7A4A2C8A815823D23149C] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [b5] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [C980D2C07B98452110A3A8E52DB5DA88] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [b6] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [07703E5A6268EEDF552FE770F24273A7] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [b7] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [A3551578B7298A2E4719A9108E0AA37B] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [f1] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [1236FB3FC8464B559BDEDFA966D6679F] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [f1][h1C] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [A1D47DB4C6B93C78FE55CBFC1BB28D28] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [f2] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [B4E658DFF037706FFB2EB64F1DFDBB3F] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [f3] CRC=E9C8E262 A1D5FACA RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [FA94645F1A15ABA440AD0136ED92E9D1] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [f4] CRC=2954A98F C2236510 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [511833A46BE4E00D1B3655C88E278422] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [o1] CRC=53D440E7 7519B011 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [DF4FC3C46307527707F9106E75074829] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [o1][f1] CRC=D5295672 9CB57015 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [422FD8833F865C4A6C17FCAC4450A69E] GoodName=Diddy Kong Racing (U) (M2) (V1.0) [o2] CRC=53D440E7 7519B011 RefMD5=4F0E07F0EEAC7E5D7CE3A75461888D03 [B31F8CCA50F31ACC9B999ED5B779D6ED] GoodName=Diddy Kong Racing (U) (M2) (V1.1) [!] CRC=E402430D D2FCFC9D Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [FBCCFED51A43B0012CE927CC73D6AADA] GoodName=Diddy Kong Racing SRAM by Group5 (PD) CRC=9F35059D 48B7F411 Players=4 SaveType=SRAM [C4C1B52F9C4469C6C747942891DE3CFD] GoodName=Dinosaur Planet (Dec 2000 Beta) CRC=906C3F77 CE495EA1 Players=1 SaveType=Flash RAM [0E0E920AB13EF13508F5A98CC4CD2FF8] GoodName=Disney's Donald Duck - Goin' Quackers (U) [!] CRC=C16C421B A21580F7 Players=1 SaveType=None Mempak=Yes CountPerOp=3 [BD1DE2FC1CF31096423563A40ECBF933] GoodName=Disney's Tarzan (E) [!] CRC=D614E5BF A76DBCC1 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [AF740B224E5DD0BD09F7254811559ADF] GoodName=Disney's Tarzan (E) [h1C] CRC=D614E5BF A76DBCC1 RefMD5=BD1DE2FC1CF31096423563A40ECBF933 [5D82E903F65341487DDC11AF80AD607A] GoodName=Disney's Tarzan (F) [!] CRC=001A3BD0 AFB3DE1A Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [DF3CDD959E8C63B45F557FC197CE0E63] GoodName=Disney's Tarzan (G) [!] CRC=4C261323 4F295E1A Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [A29E203DDB6293B7D105BF4A2EEEDD1E] GoodName=Disney's Tarzan (G) [h1C] CRC=4C261323 4F295E1A RefMD5=DF3CDD959E8C63B45F557FC197CE0E63 [EAE7E0EE5328ED9F13B9CF9990189928] GoodName=Disney's Tarzan (U) [!] CRC=CBFE69C7 F2C0AB2A Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [C56AD8ABD0FB5EFEF1FA0229F9A2EFF0] GoodName=Disney's Tarzan (U) [f1] (PAL) CRC=988C4CC3 C9F310C5 RefMD5=EAE7E0EE5328ED9F13B9CF9990189928 [CC8B0A9F15B92D68963668A3495A6BF6] GoodName=Disney's Tarzan (U) [f2] (PAL) CRC=8BDDD635 EC0E9198 RefMD5=EAE7E0EE5328ED9F13B9CF9990189928 [E9C2B20EA27E6CAB89842AF4D768724E] GoodName=Disney's Tarzan (U) [t1] CRC=8BEE2831 D09BC906 RefMD5=EAE7E0EE5328ED9F13B9CF9990189928 [38DCF67CBA39A84108ADF48EE53544B0] GoodName=Display List Ate My Mind Demo by Kid Stardust (PD) CRC=887C368D D1663AA2 [A92F9FCD93D20778ED8FF15546BB30F5] GoodName=Doctor V64 BIOS V1.01 CRC=204F4E4C 59000000 [3509A4E21E43CEDBD704F8A1192C31DF] GoodName=Doctor V64 BIOS V1.02 CRC=204F4E4C 59000000 [A7BD2F54D9646D43A2A4AD388450223B] GoodName=Doctor V64 BIOS V1.03 CRC=204F4E4C 59000000 [30E25793ACC95529F8C69A55C6679E73] GoodName=Doctor V64 BIOS V1.04 CRC=204F4E4C 59000000 [9B69D303AFFA2CD9ABA96C21A2C21476] GoodName=Doctor V64 BIOS V1.05 CRC=204F4E4C 59000000 [ADE88A1544D469D77D4568364EF25319] GoodName=Doctor V64 BIOS V1.08 CRC=204F4E4C 59000000 [1C0FCFC7B304698F77069A5F31D27DE1] GoodName=Doctor V64 BIOS V1.09 CRC=204F4E4C 59000000 [A133F08F88F6D49E1D23D051524AD094] GoodName=Doctor V64 BIOS V1.10 CRC=204F4E4C 59000000 [601E5335E43F83676F9F341B57D03611] GoodName=Doctor V64 BIOS V1.10r (RBubba Hack) CRC=204F4E4C 59000000 [4AFA73E31031C0F582C11CDA47CC8729] GoodName=Doctor V64 BIOS V1.11 CRC=204F4E4C 59000000 [AAC7B04083FB1B9AC5B478AD89D8D3BA] GoodName=Doctor V64 BIOS V1.21 CRC=00000000 00000000 [4EAE45340300293065CEF5B598C0AC6E] GoodName=Doctor V64 BIOS V1.22 CRC=00000000 00000000 [ED9D2C04A7A0934372216ED8321EA6E3] GoodName=Doctor V64 BIOS V1.30 CRC=204F4E4C 59000000 [041813684340CE4D988B2EBA341CE5C5] GoodName=Doctor V64 BIOS V1.31 (Blue) CRC=204F4E4C 59000000 [2DF942636FB2BF924844A8F4129913BE] GoodName=Doctor V64 BIOS V1.31 CRC=204F4E4C 59000000 [B978DD8BA5F4DAC6850B7D1297EB1F11] GoodName=Doctor V64 BIOS V1.32 CRC=00000000 00000000 [F015AE0F3AD80975FB21B43EF7F14422] GoodName=Doctor V64 BIOS V1.33 CRC=00000000 00000000 [F9D9666DE2F946C9A7D6173DFADF9A81] GoodName=Doctor V64 BIOS V1.33b CRC=204F4E4C 59000000 [E60CE3D4354066CFD80129CB6C2466D5] GoodName=Doctor V64 BIOS V1.40 CRC=204F4E4C 59000000 [D62566C4A47396BFC97173D8CF468A5D] GoodName=Doctor V64 BIOS V1.40b CRC=00000000 00000000 [22134E81100D2854323B064EDD98AAC4] GoodName=Doctor V64 BIOS V1.41 CRC=204F4E4C 59000000 [25D9CDCD8C23AF6559228C4435FF0CB3] GoodName=Doctor V64 BIOS V1.41b CRC=00000000 00000000 [69A7D3A2F2805BC2FC84DB917F8AF592] GoodName=Doctor V64 BIOS V1.50 CRC=204F4E4C 59000000 [9516794650A56E60353135BB9A63C872] GoodName=Doctor V64 BIOS V1.51 CRC=204F4E4C 59000000 [FCB5472F929C8DA0DAED4C0984F8053B] GoodName=Doctor V64 BIOS V1.52 (CH2 Hack) CRC=204F4E4C 59000000 [27369BF665AD2FE9F23C6C6D202AA5E8] GoodName=Doctor V64 BIOS V1.52 CRC=204F4E4C 59000000 [941BA29D2945FA5C903FB0FC6491AC62] GoodName=Doctor V64 BIOS V1.53 CRC=00000000 00000000 [E7C2944774E1610EE6DF7358717B5DA3] GoodName=Doctor V64 BIOS V1.60 CRC=00000000 00000000 [B85FCEC60C7BEA9106BD9B9C14479EE7] GoodName=Doctor V64 BIOS V1.61 CRC=00000000 00000000 [D4BC7E3227225E303A7F6491C1DBB4CB] GoodName=Doctor V64 BIOS V1.70 CRC=00000000 00000000 [BCAC0108F0D521FF5478BA6C50B23774] GoodName=Doctor V64 BIOS V1.71 CRC=00000000 00000000 [D2DA27872F13C0BBB2D686C495F13499] GoodName=Doctor V64 BIOS V1.72 CRC=00000000 00000000 [13CD4C03FCA1BC23AE8B57885E76BCA6] GoodName=Doctor V64 BIOS V1.73 CRC=00000000 00000000 [A2604CB559D289837F718DB02AFEA85E] GoodName=Doctor V64 BIOS V1.74 (Revive Version) CRC=00000000 00000000 [8B95ABB5F6E71454FE2C415A0787A384] GoodName=Doctor V64 BIOS V1.74 CRC=00000000 00000000 [83B122B18B98B96A63C6F824833116BC] GoodName=Doctor V64 BIOS V1.75 CRC=00000000 00000000 [B444CC20AEFAD0DE4A552D8DD0486E82] GoodName=Doctor V64 BIOS V1.76 CRC=00000000 00000000 [B5D92FF099B3B74C6D0F0D75590EAC36] GoodName=Doctor V64 BIOS V1.80 CRC=00000000 00000000 [8CD8FDF74A47CA163CD23AE1D01B7E95] GoodName=Doctor V64 BIOS V1.81 CRC=00000000 00000000 [AAD6807D240FC3FF4FEDAB57135AD458] GoodName=Doctor V64 BIOS V1.82 CRC=00000000 00000000 [4121DD79CEBF67EBCA1AA2B3A7AED858] GoodName=Doctor V64 BIOS V1.83 CRC=00000000 00000000 [D3EA654D4679E0BF40BB671CA7D4A7A3] GoodName=Doctor V64 BIOS V1.90 CRC=00000000 00000000 [CF8B2C134C3FCD5A5D74402D75CA0543] GoodName=Doctor V64 BIOS V1.91 CRC=00000000 00000000 [0F83626497B7ACC4AAB3EB39CDE893D3] GoodName=Doctor V64 BIOS V1.92 CRC=00000000 00000000 [6B626C55C99CD12E88A3DB3B52372104] GoodName=Doctor V64 BIOS V1.93 CRC=00000000 00000000 [483BD87237BB38884E7E22F4981ACFDB] GoodName=Doctor V64 BIOS V1.94 CRC=00000000 00000000 [553F6E6766B85CB0247E5CA62F515C75] GoodName=Doctor V64 BIOS V2.00 CRC=00000000 00000000 [A89761018FA98E5C919F4CA0BB3E6001] GoodName=Doctor V64 BIOS V2.00b CRC=00000000 00000000 [AE36DD0BCC2F515917B0CF52AEE48AC1] GoodName=Doctor V64 BIOS V2.01 (Red) CRC=00000000 00000000 [0C91C461ED69EC1E93E9E0DEF9053546] GoodName=Doctor V64 BIOS V2.01 CRC=00000000 00000000 [BA2816F0B775099E42F124E5C43FE30C] GoodName=Doctor V64 BIOS V2.01b CRC=00000000 00000000 [DDD1958DF0330B79288B51E65E1E36A0] GoodName=Doctor V64 BIOS V2.02 CRC=00000000 00000000 [5AAA98D1FDF963FB88B3D25476924A04] GoodName=Doctor V64 BIOS V2.02b CRC=00000000 00000000 [030EAB316DC3A2D33AAC3DE15FDC4473] GoodName=Doctor V64 BIOS V2.03 (Black) CRC=00000000 00000000 [2F4E88C48823714825F35148F5B5738D] GoodName=Doctor V64 BIOS V2.03 (Blue) CRC=00000000 00000000 [7F34EB3E1363580FEA95B23A9CB1C3AF] GoodName=Doctor V64 BIOS V2.03 (Green) CRC=00000000 00000000 [A550DEBDF72B753B52882A1A573560B5] GoodName=Doctor V64 BIOS V2.03 (Purple) CRC=00000000 00000000 [014A2B82FDF9A72FC5A26A7EAF8F8176] GoodName=Doctor V64 BIOS V2.03 (Red) CRC=00000000 00000000 [41010B4BFE1F8DB801237B02A9FA265F] GoodName=Doctor V64 BIOS V2.03 CRC=00000000 00000000 [E8B403A0F0E212FA5C1220AF10D9C379] GoodName=Donald Duck - Quack Attack (E) (M5) [!] CRC=3DF17480 193DED5A Players=1 SaveType=None Mempak=Yes CountPerOp=3 [07C4944DDAAD234F1F6B0B200BEA60B2] GoodName=Donald Duck - Quack Attack (E) (M5) [b1] CRC=85E42D70 132BD5C2 RefMD5=E8B403A0F0E212FA5C1220AF10D9C379 [3BAFF04C5DD367F362248DC627D848C1] GoodName=Donald Duck - Quack Attack (E) (M5) [f1] (NTSC) CRC=8A5B9018 0A661D8F RefMD5=E8B403A0F0E212FA5C1220AF10D9C379 [3141A1EE8DCDE0F772E915E629823F13] GoodName=Donchan Puzzle Hanabi de Doon! (Aleck64) CRC=D52FE29D 8EA6A759 SaveType=Eeprom 4KB [AF83E0CF36298E62E9EB2EB8C89AA710] GoodName=Animal Crossing (Ch) (iQue) [!] CRC=916EB31B F47097A5 [118E9CE360B97A6F8DAB2C9F30660BF5] GoodName=Donkey Kong 64 (E) (M4) [!] CRC=11936D8C 6F2C4B43 SaveType=Eeprom 16KB Players=4 Rumble=Yes CountPerOp=1 [428067DC7DB42DFC977A775F0A6E55B1] GoodName=Donkey Kong 64 (E) (M4) [b1] CRC=11936D8C 6F2C4B43 RefMD5=118E9CE360B97A6F8DAB2C9F30660BF5 [C48C46362602766EA758FAAEED88AF50] GoodName=Donkey Kong 64 (E) (M4) [f1] (Boot&Save) CRC=1F95CAAA 047FC22A RefMD5=118E9CE360B97A6F8DAB2C9F30660BF5 [7BE2AAB259C437E8BA91FF8E5903837C] GoodName=Donkey Kong 64 (E) (M4) [f1] (Save) CRC=1F95CAAA 047FC22A RefMD5=118E9CE360B97A6F8DAB2C9F30660BF5 [5B677F4BF93D6578252FCAD2C8CEB637] GoodName=Donkey Kong 64 (J) [!] CRC=053C89A7 A5064302 SaveType=Eeprom 16KB Players=4 CountPerOp=1 Rumble=Yes [98A5836E3A5DA7BD0B5819E7498ACEA2] GoodName=Donkey Kong 64 (U) (Kiosk Demo) [!] CRC=0DD4ABAB B5A2A91E SaveType=Eeprom 16KB CountPerOp=1 Rumble=Yes [843DB032839BF1AA74759F2E39A2ABDC] GoodName=Donkey Kong 64 (U) (Kiosk Demo) [b1] CRC=F5C21403 8FCA0710 RefMD5=98A5836E3A5DA7BD0B5819E7498ACEA2 [34E6B35260F03CA72593FA373E38BBEA] GoodName=Donkey Kong 64 (U) (Kiosk Demo) [b2] CRC=0DD4ABAB B5A2A91E RefMD5=98A5836E3A5DA7BD0B5819E7498ACEA2 [3F1A1B941E58FF977EF47B65CE359A26] GoodName=Donkey Kong 64 (U) (Kiosk Demo) [f1] (PAL) CRC=F5C21403 8FCA0710 RefMD5=98A5836E3A5DA7BD0B5819E7498ACEA2 [9EC41ABF2519FC386CADD0731F6E868C] GoodName=Donkey Kong 64 (U) [!] CRC=EC58EABF AD7C7169 SaveType=Eeprom 16KB Players=4 CountPerOp=1 Rumble=Yes [6B4772AA1743FEAC1919618B3FC6B3E1] GoodName=Donkey Kong 64 (U) [b1] CRC=EC58EABF AD7C7169 RefMD5=9EC41ABF2519FC386CADD0731F6E868C [4D4483C0CA3B86997E41A7032F6AD25F] GoodName=Donkey Kong 64 (U) [f1] (Save) CRC=CE84793D 27ECC1AD RefMD5=9EC41ABF2519FC386CADD0731F6E868C [CED71061B6A8581DC0B95970D522848A] GoodName=Donkey Kong 64 (U) [f2] CRC=CE84793D 27ECC1AD RefMD5=9EC41ABF2519FC386CADD0731F6E868C [E56EF244D61B15DBAEF474F9C0C0B23A] GoodName=Donkey Kong 64 (U) [f3] CRC=CED986FD 3344AC38 RefMD5=9EC41ABF2519FC386CADD0731F6E868C [11DA2A2D0E91074BB8FF1FCB029535FD] GoodName=Donkey Kong 64 - Tag Anywhere (V5) (U) CRC=31739C69 A99E3CB2 RefMD5=9EC41ABF2519FC386CADD0731F6E868C [190CCCA6526DC4A1F611E3B40F5131C0] GoodName=Doom 64 (E) [!] CRC=2C739EAC 9EF77726 Players=1 SaveType=None Mempak=Yes [B482F51B616F4337F1B3BF5EFDD650D4] GoodName=Doom 64 (E) [b1] CRC=2C739EAC 9EF77726 RefMD5=190CCCA6526DC4A1F611E3B40F5131C0 [06F15EF2228C1B1147C41DCCAA07D9DE] GoodName=Doom 64 (J) [!] CRC=7AA65B36 FDCEE5AD Players=1 SaveType=None Mempak=Yes [053BB6D2E14D67F0FB0B509F2A6B4485] GoodName=Doom 64 (J) [b1] CRC=7AA65B36 FDCEE5AD RefMD5=06F15EF2228C1B1147C41DCCAA07D9DE [B67748B64A2CC7EFD2F3AD4504561E0E] GoodName=Doom 64 (U) (V1.0) [!] CRC=A83E101A E937B69D Players=1 SaveType=None Mempak=Yes [BF710F7D1D51EC89AC3F58022B2B5D7F] GoodName=Doom 64 (U) (V1.0) [T+Bra1.0_Doom64BR] CRC=B01A1DAB 7F7827E3 RefMD5=B67748B64A2CC7EFD2F3AD4504561E0E [6EACFE4F39265F24FB8145FDED8272F6] GoodName=Doom 64 (U) (V1.0) [b1] CRC=A83E101A E937B69D RefMD5=B67748B64A2CC7EFD2F3AD4504561E0E [81FD532B1C7C2CCD687E56696E073C83] GoodName=Doom 64 (U) (V1.0) [b2] CRC=A83E101A E937B69D RefMD5=B67748B64A2CC7EFD2F3AD4504561E0E [7497ADADADA89230827C06E4BFFBBBD8] GoodName=Doom 64 (U) (V1.0) [o1] CRC=A83E101A E937B69D RefMD5=B67748B64A2CC7EFD2F3AD4504561E0E [4DC885150DFEC67ACDD807F9FFE9596E] GoodName=Doom 64 (U) (V1.0) [t1] CRC=13D0EE29 D57A41AD RefMD5=B67748B64A2CC7EFD2F3AD4504561E0E [29E85B9D9072AC232CEB87EFE826269A] GoodName=Doom 64 (U) (V1.0) [t2] CRC=13D0EE29 D57A41AD RefMD5=B67748B64A2CC7EFD2F3AD4504561E0E [FE63F970BB7F1D6798878D5835E1026C] GoodName=Doom 64: Complete Edition (Doom 64 Hack) CRC=5318786C 994249C6 RefMD5=1B1378BB9EE819F740550F566745AF73 [1B1378BB9EE819F740550F566745AF73] GoodName=Doom 64 (U) (V1.1) [!] CRC=423E96F4 CE88F05B Players=1 SaveType=None Mempak=Yes [C2166455E94E89E9E3AB612B4377C443] GoodName=Doraemon - Nobita to 3tsu no Seireiseki (J) [!] CRC=BFF7B1C2 AEBF148E Players=4 [989E7B15D24649B784813E1A07DF6887] GoodName=Doraemon - Nobita to 3tsu no Seireiseki (J) [b1] CRC=BFF7B1C2 AEBF148E RefMD5=C2166455E94E89E9E3AB612B4377C443 [7E0DA017551101DA1C4FB6A0C49A2328] GoodName=Doraemon - Nobita to 3tsu no Seireiseki (J) [b2] CRC=BFF7B1C2 AEBF148E RefMD5=C2166455E94E89E9E3AB612B4377C443 [BE0000D3415787F9920E178942C297C5] GoodName=Doraemon - Nobita to 3tsu no Seireiseki (J) [b3] CRC=BFF7B1C2 AEBF148E RefMD5=C2166455E94E89E9E3AB612B4377C443 [C2909D5799099819E9A7ECE3CD4737FC] GoodName=Doraemon - Nobita to 3tsu no Seireiseki (J) [t1] CRC=55C0515C 901DA4A7 RefMD5=C2166455E94E89E9E3AB612B4377C443 [0580D96A71671C9E6972FDCF5897CC26] GoodName=Doraemon 2 - Nobita to Hikari no Shinden (J) [!] CRC=B6306E99 B63ED2B2 SaveType=Eeprom 16KB Players=1 Rumble=Yes [7CC16A6090CAC3749DD6B71CA7A58605] GoodName=Doraemon 2 - Nobita to Hikari no Shinden (J) [b1] CRC=B6306E99 B63ED2B2 RefMD5=0580D96A71671C9E6972FDCF5897CC26 [5A28008B05923016EA411BACE06EF32A] GoodName=Doraemon 2 - Nobita to Hikari no Shinden (J) [b2] CRC=4E30BD3A B77D6DFB RefMD5=0580D96A71671C9E6972FDCF5897CC26 [7E4BCA92DA50145C9906B2A72F9351B5] GoodName=Doraemon 2 - Nobita to Hikari no Shinden (J) [f1] (PAL) CRC=4E30BD3A B77D6DFB RefMD5=0580D96A71671C9E6972FDCF5897CC26 [58ADC17903754FEBF77DC9CD3DB8B7D8] GoodName=Doraemon 2 - Nobita to Hikari no Shinden (J) [f2] CRC=4E30BD3A B77D6DFB RefMD5=0580D96A71671C9E6972FDCF5897CC26 [BEFA319919474BAE05DFCB570CC0CF31] GoodName=Doraemon 2 - Nobita to Hikari no Shinden (J) [t1] CRC=4ECEB1DE 552B6E88 RefMD5=0580D96A71671C9E6972FDCF5897CC26 [A4A1D490BA67831775FC381B846E2168] GoodName=Doraemon 3 - Nobita no Machi SOS! (J) [!] CRC=A8275140 B9B056E8 SaveType=Eeprom 16KB Players=1 Rumble=Yes [FB7565FE1EAAED1CACFAE3B011FA6CB6] GoodName=Doraemon 3 - Nobita no Machi SOS! (J) [f1] (PAL-NTSC) CRC=D8059804 92739B11 RefMD5=A4A1D490BA67831775FC381B846E2168 [A4F7C57C180297B2E7BA5A5FEB44FE0B] GoodName=Doubutsu no Mori (J) [!] CRC=BD8E206D 98C35E1C Players=1 SaveType=Flash RAM Mempak=Yes [4AB8D6535028805F5794D3F01003CFD5] GoodName=Doubutsu no Mori (J) [T+Eng2007-08-10_Brandon Dixon] CRC=BD8E206D 98C35E1C RefMD5=A4F7C57C180297B2E7BA5A5FEB44FE0B [01BDCC854D0AB798500E7BC31A24D94F] GoodName=Doubutsu no Mori (J) [T+Eng2010-12-02_Zoinkity] CRC=0290AEB9 67A3B6C1 RefMD5=A4F7C57C180297B2E7BA5A5FEB44FE0B [7DDBCA3F642CB4CAA780E81733C94037] GoodName=Doubutsu no Mori (J) [T+Eng90%] CRC=8F0CC36D C738259E RefMD5=A4F7C57C180297B2E7BA5A5FEB44FE0B [7C58DB7EE170912A2DF84E67A489058A] GoodName=Doubutsu no Mori (J) [T-Eng2007-02-08_Brandon Dixon] CRC=BD8E206D 98C35E1C RefMD5=A4F7C57C180297B2E7BA5A5FEB44FE0B [5E2A5C56CA1A0CCAEA3AE5F852E0C58D] GoodName=Doubutsu no Mori (J) [T-Eng2007-02-09_Brandon Dixon] CRC=BD8E206D 98C35E1C RefMD5=A4F7C57C180297B2E7BA5A5FEB44FE0B [0AA8E4B96EBB5B8A5CF91CFB04BC3741] GoodName=Doubutsu no Mori (J) [T-Eng2007-03-22_Brandon Dixon] CRC=BD8E206D 98C35E1C RefMD5=A4F7C57C180297B2E7BA5A5FEB44FE0B [DD291B9C65420FD892107F6C665B7A45] GoodName=Dr. Mario 64 (Ch) (iQue) [!] CRC=EF62A343 11E41E37 Players=4 [FE49420725F9C1CF0F15BA5682D27709] GoodName=Dr. Mario 64 (Ch) (V2) (iQue) (Manual) [!] [B524D10A8A26764EB2198ACEC3F09948] GoodName=Dr. Mario 64 (Ch) (V4) (iQue) (Manual) [!] [1A7936367413E5D6874ABDA6D623AD32] GoodName=Dr. Mario 64 (U) [!] CRC=769D4D13 DA233FFE Players=4 SaveType=Eeprom 4KB [36B3D908FB50E5521DEFBEB2C39F47B0] GoodName=Dr. Mario 64 (U) [T+Jap1.0_Zoinkity] CRC=B74388D7 7DBD6DFB RefMD5=1A7936367413E5D6874ABDA6D623AD32 [0AD0800D351F77EC31092096D58C25F0] GoodName=Dragon King by CrowTRobo (PD) [b1] CRC=19E0E54C CB721FD2 [944ECED50E57D46779576F732CB27DC0] GoodName=Dragon King by CrowTRobo (PD) CRC=19E0E54C CB721FD2 [770D0D2BB08235613569667A284BCA2C] GoodName=Dragon Sword 64 (E) (Prototype) CRC=40DFEDA0 3AA09CB2 [64011DD56FF84CF9EB46153E7AECCD26] GoodName=Dragon Sword 64 (U) (Prototype) (1999-08-25) CRC=AE6b1E11 B7CBD69E [F120FADB52B414EB4FB7D13092AC3CDB] GoodName=Dual Heroes (E) [!] CRC=B6524461 ED6D04B1 SaveType=None Mempak=Yes Players=2 [B01D031BE1789565E2B8A44CD76B96C6] GoodName=Dual Heroes (E) [b1] CRC=B6524461 ED6D04B1 RefMD5=F120FADB52B414EB4FB7D13092AC3CDB [DFEBF3A9570B95D95CA6BE2CE8311D1D] GoodName=Dual Heroes (E) [b2] CRC=B6524461 ED6D04B1 RefMD5=F120FADB52B414EB4FB7D13092AC3CDB [B406AD1694D65725FD31A054F6ECE213] GoodName=Dual Heroes (E) [f1] (NTSC) CRC=926C2E3B 9829A216 RefMD5=F120FADB52B414EB4FB7D13092AC3CDB [E7652ED5CECEB5B1BC14495C58546D1C] GoodName=Dual Heroes (J) [!] CRC=056EAB63 C215FCD5 Players=2 SaveType=None Mempak=Yes [A7D3E42EFFD6E7935DA7C9A6B6899CAC] GoodName=Dual Heroes (J) [o1] CRC=056EAB63 C215FCD5 RefMD5=E7652ED5CECEB5B1BC14495C58546D1C [54C610270D3F5EEA39BC6A8F73B3B909] GoodName=Dual Heroes (J) [o2] CRC=056EAB63 C215FCD5 RefMD5=E7652ED5CECEB5B1BC14495C58546D1C [923D65E69F51858C697E0E5759CD038B] GoodName=Dual Heroes (U) [!] CRC=A62230C3 F0834488 Players=2 SaveType=None Mempak=Yes [E3EF8D7ACCA9CCB551C26B0F879E6B25] GoodName=Dual Heroes (U) [b1] CRC=A62230C3 F0834488 RefMD5=923D65E69F51858C697E0E5759CD038B [02192B4B3797983BBE5E452336584208] GoodName=Duck Dodgers Starring Daffy Duck (U) (M3) [!] CRC=FBB9F1FA 6BF88689 Players=1 SaveType=Eeprom 4KB CountPerOp=1 Rumble=Yes [B5A5A71483679DCCACBDA770647A9DBF] GoodName=Duck Dodgers Starring Daffy Duck (U) (M3) [t1] CRC=83E7E0D2 B5B7E503 RefMD5=02192B4B3797983BBE5E452336584208 [86E98AACA0D90BF744DA090539BA4AD8] GoodName=Duke Nukem - ZER0 H0UR (E) [!] CRC=DC36626A 3F3770CB Players=4 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [51A1EEE441240229BEB2E6CD8FAB285C] GoodName=Duke Nukem - ZER0 H0UR (E) [f1] (NTSC) CRC=0BD8008B 26051E1D RefMD5=86E98AACA0D90BF744DA090539BA4AD8 [E2B73FEB0843874EA831A2E0076FCB72] GoodName=Duke Nukem - ZER0 H0UR (F) [!] CRC=32CA974B B2C29C50 Players=4 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [026789D47DB5FE202A76F89797B33AC7] GoodName=Duke Nukem - ZER0 H0UR (U) [!] CRC=04DAF07F 0D18E688 Players=4 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [69ED326664E48BAA9CE743E6E9C450DA] GoodName=Duke Nukem - ZER0 H0UR (U) [b1] CRC=04DAF07F 0D18E688 RefMD5=026789D47DB5FE202A76F89797B33AC7 [75239D11AEE906C9ABEA752BA1E2AA00] GoodName=Duke Nukem - ZER0 H0UR (U) [b2] CRC=BCEAF9B7 F84FF876 RefMD5=026789D47DB5FE202A76F89797B33AC7 [4446E99E8D43E1B7557412ACEA918F68] GoodName=Duke Nukem - ZER0 H0UR (U) [b3] CRC=BCEAF9B7 F84FF876 RefMD5=026789D47DB5FE202A76F89797B33AC7 [BD4E03620567C6291F11B9217AC67C28] GoodName=Duke Nukem - ZER0 H0UR (U) [b4] CRC=04DAF07F 0D18E688 RefMD5=026789D47DB5FE202A76F89797B33AC7 [A3D49AAC6BC8EEA0D707042A68D2D48C] GoodName=Duke Nukem - ZER0 H0UR (U) [t1] CRC=BCEAF9B7 F84FF876 RefMD5=026789D47DB5FE202A76F89797B33AC7 [8657CBA95C409B74C1F5632CBC36643F] GoodName=Duke Nukem 64 (E) [!] CRC=57BFF74D DE747743 Players=4 SaveType=None Mempak=Yes Rumble=Yes [BB2472B3F8A41FBF3AEC3CCEF7EA8C78] GoodName=Duke Nukem 64 (E) (Beta) CRC=FF14C1DA 167FDE92 RefMD5=8657CBA95C409B74C1F5632CBC36643F [A6AC9D140112BD7A3AA8A5ABA79EBD88] GoodName=Duke Nukem 64 (E) [b1] CRC=57BFF74D DE747743 RefMD5=8657CBA95C409B74C1F5632CBC36643F [31F08F1D2F789C5D698B7E05F287E7AE] GoodName=Duke Nukem 64 (E) [o1] CRC=57BFF74D DE747743 RefMD5=8657CBA95C409B74C1F5632CBC36643F [E2E79C7167BDB26E176D220904739C91] GoodName=Duke Nukem 64 (F) CRC=1E12883D D3B92718 Players=4 SaveType=None Mempak=Yes Rumble=Yes [C7F1A43764A26DA2E43F2A36A5F76E4C] GoodName=Duke Nukem 64 (U) [!] CRC=A273AB56 DA33DB9A Players=4 SaveType=None Mempak=Yes Rumble=Yes [9BE63892A2AA2B20B75B3AC4E7B7DCDF] GoodName=Duke Nukem 64 (U) [b1] CRC=3F84EB47 141964BF RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [685EB7D3D1F2C82932EDF7B476A6E21B] GoodName=Duke Nukem 64 (U) [b2] CRC=A273AB56 DA33DB9A RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [D13D7E9AA29D972CB93C39A15F304FAA] GoodName=Duke Nukem 64 (U) [b3] CRC=A273AB56 DA33DB9A RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [82FE3916997DA14A02C2301AC2B5E321] GoodName=Duke Nukem 64 (U) [h1C] CRC=A273AB56 DA33DB9A RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [6F14B999499E90761D8444F784564AB3] GoodName=Duke Nukem 64 (U) [o1] CRC=A273AB56 DA33DB9A RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [557F89A263B2028936753956F7902299] GoodName=Duke Nukem 64 (U) [t1] CRC=3F84EB47 141964BF RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [A6DF7D8C1E2DAB58496EF633AC09366E] GoodName=Duke Nukem 64 (U) [t2] CRC=3F84EB47 141964BF RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [8B7E6FF3453F660DCFC7B968E622E7C9] GoodName=Duke Nukem 64 (U) [t3] CRC=3F84EB47 141964BF RefMD5=C7F1A43764A26DA2E43F2A36A5F76E4C [9A008AF4E90D7C55F21039F4E82170EF] GoodName=Dynamix Intro (Hidden Song) by Widget and Immortal (PD) CRC=B8E73356 040E42EC [5809670A42CA34D39A39598EFA82F5F3] GoodName=Dynamix Intro by Widget and Immortal (PD) CRC=086E91C9 89F47C51 Players=0 Status=3 Rumble=No SaveType=None [E06B804B5A8809C42E99B229106CC813] GoodName=Dynamix Readme by Widget and Immortal (PD) CRC=186CC1A9 A0DE4C8D RefMD5=5809670A42CA34D39A39598EFA82F5F3 [F32E61E30C5BC232A01E52F8BC2EEF07] GoodName=Dynamix Intro by Widget and Immortal (PD) [h1C] CRC=086E91C9 89F47C51 RefMD5=5809670A42CA34D39A39598EFA82F5F3 [1830EDE2557E8685E6F76D05CC65076A] GoodName=ECW Hardcore Revolution (E) [!] CRC=8C38E5DB B37C27D7 SaveType=None Mempak=Yes Players=4 Rumble=Yes [5D1E41AA28169E71B4919FA08F1ACD9B] GoodName=ECW Hardcore Revolution (G) [!] CRC=2138A076 408AD8B2 SaveType=None Mempak=Yes Players=4 Rumble=Yes [91545C2642DB6349B8D18BF0BEE29162] GoodName=ECW Hardcore Revolution (E) [b1] CRC=8C38E5DB B37C27D7 RefMD5=1830EDE2557E8685E6F76D05CC65076A [8EEBB16B7A4D39AE8BC8CCCBC41F0A01] GoodName=ECW Hardcore Revolution (U) [!] CRC=BDF9766D BD068D70 Players=4 SaveType=None Mempak=Yes Rumble=Yes [BF2DF4B86FAA2181A7ACFE2643FA2293] GoodName=Earthworm Jim 3D (E) (M6) [!] CRC=492B9DE8 C6CCC81C Players=1 SaveType=Eeprom 4KB [97EA079ECF105EA16654A855644D870A] GoodName=Earthworm Jim 3D (E) (M6) [b1] CRC=492B9DE8 C6CCC81C RefMD5=BF2DF4B86FAA2181A7ACFE2643FA2293 [980DFB38AD9A883119DE135F45B7DB36] GoodName=Earthworm Jim 3D (U) [!] CRC=DF574191 9EB5123D Players=1 SaveType=Eeprom 4KB [554EE4BF15388DDE586DE90AC72EF5FA] GoodName=Earthworm Jim 3D (U) [T+Rus] CRC=34DBB6CF EA06789D RefMD5=980DFB38AD9A883119DE135F45B7DB36 [B27336A278658AC6D62AB6C4C3FB1DB6] GoodName=Earthworm Jim 3D (U) [f1] (PAL) CRC=04853364 948ACF82 RefMD5=980DFB38AD9A883119DE135F45B7DB36 [6B870EBEDCBD81B9FF369008F904C1CD] GoodName=Earthworm Jim 3D (U) [hI] CRC=04842D98 1A9FF551 RefMD5=980DFB38AD9A883119DE135F45B7DB36 [60F0CBE10DCE67FDD6527A78B51DCCBC] GoodName=Earthworm Jim 3D (U) [t1] CRC=0484CD98 1AFE0B59 RefMD5=980DFB38AD9A883119DE135F45B7DB36 [935DD85AD198BBDE92161CDCE47CBFB3] GoodName=Eikou no Saint Andrews (J) [!] CRC=0DED0568 1502515E Players=4 Mempak=Yes [936DB74AE766BB1219E8A712F0D06E4A] GoodName=Eikou no Saint Andrews (J) [b1] CRC=0DED0568 1502515E RefMD5=935DD85AD198BBDE92161CDCE47CBFB3 [0F7C52AD7C7C88103960F44FCD0B119A] GoodName=Eikou no Saint Andrews (J) [b2] CRC=0DED0568 1502515E RefMD5=935DD85AD198BBDE92161CDCE47CBFB3 [08CCA8D372EA8C38148F77AB5A03354D] GoodName=Eikou no Saint Andrews (J) [h1C] CRC=0DED0568 1502515E RefMD5=935DD85AD198BBDE92161CDCE47CBFB3 [CEC824B5DA28B974B1562338EB728805] GoodName=Eikou no Saint Andrews (J) [h2C] CRC=0DED0568 1502515E RefMD5=935DD85AD198BBDE92161CDCE47CBFB3 [7EB0C27F162B74032C3823E721EDA00B] GoodName=Eleven Beat - World Tournament (Aleck64) CRC=6D9D1FE4 84D10BEA [15DF97A59B2354B130DEC3FB86BBA513] GoodName=Elmo's Letter Adventure (U) [!] CRC=F2A653CB 60633B3B SaveType=None Players=1 CountPerOp=1 [F733453ED26AFA0ACA8D3EB3B5B6D8EA] GoodName=Elmo's Number Journey (U) [!] CRC=02B1538F C94B88D0 Players=1 SaveType=None [9B456ACB96291FC8B55232A08AE03346] GoodName=Eltale Monsters (J) [!] CRC=E13AE2DC 4FB65CE8 Players=1 SaveType=None Mempak=Yes [752EF6D2C2A6DBBB8CBAEFB596412C1D] GoodName=Eltale Monsters (J) [b1] CRC=E13AE2DC 4FB65CE8 RefMD5=9B456ACB96291FC8B55232A08AE03346 [D42CC78A2BF0D34518B8E0D0439E432E] GoodName=Eltale Monsters (J) [b2] CRC=E13AE2DC 4FB65CE8 RefMD5=9B456ACB96291FC8B55232A08AE03346 [75A8F25B679A0D148F0D8E1143104845] GoodName=Eurasia First N64 Intro by Sispeo (PD) CRC=52F22511 B9D85F75 [761DC0DE0913D697ED1F9899948552BB] GoodName=Eurasia Intro by Ste (PD) [b1] CRC=52F22511 B9D85F75 [F7E6C9CFF1BC16B0DEDA0ECEFC5C3DFB] GoodName=Eurasia Intro by Ste (PD) CRC=93A94333 5A613C39 [F1D0406A74AD74BE5891620B7FE6640D] GoodName=Evek - V64jr Save Manager by WT_Riker (PD) CRC=D49DFF90 8DB53A8C [F4B41863440137C6A3BA22942F3E0DA2] GoodName=Excitebike 64 (Ch) (iQue) [!] Players=4 CountPerOp=1 [876F87C91A4B6339DAA8FC1F41EB7ACD] GoodName=Excitebike 64 (Ch) (iQue) (Manual) [!] [8FA253FD69B73DF9A831EF2F731491F2] GoodName=Excitebike 64 (E) [!] CRC=202A8EE4 83F88B89 SaveType=Eeprom 16KB Players=4 CountPerOp=1 Mempak=Yes Rumble=Yes [BF15A61AFF71C93BF5E05243F57BCA1D] GoodName=Excitebike 64 (J) [!] CRC=861C3519 F6091CE5 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes [E0018C33346714B63A55C0E040F23DEA] GoodName=Excitebike 64 (U) (Kiosk Demo) [!] CRC=AF754F7B 1DD17381 SaveType=Eeprom 16KB Mempak=Yes Rumble=Yes [7200D1C1CF489FAFFF767729F215E6E6] GoodName=Excitebike 64 (U) (V1.0) [!] CRC=07861842 A12EBC9F SaveType=Eeprom 16KB Players=4 CountPerOp=1 Mempak=Yes Rumble=Yes [496929EA74183198D121035EA808C480] GoodName=Excitebike 64 (U) (V1.0) [b1] CRC=07861842 A12EBC9F RefMD5=7200D1C1CF489FAFFF767729F215E6E6 [48D1FA279FEA4C99CFEEC90E9AD1668F] GoodName=Excitebike 64 (U) (V1.0) [f1] CRC=E5B7F405 2C4462BF RefMD5=7200D1C1CF489FAFFF767729F215E6E6 [285D3277D28CA3B9A5A2BE8971CCD767] GoodName=Excitebike 64 (U) (V1.0) [f2] (Save) CRC=E5B7F405 2C4462BF RefMD5=7200D1C1CF489FAFFF767729F215E6E6 [21954E4E404D9E87DBDB87DD309F3E94] GoodName=Excitebike 64 (U) (V1.1) [!] CRC=F9D411E3 7CB29BC0 SaveType=Eeprom 16KB Players=4 CountPerOp=1 Mempak=Yes Rumble=Yes [6DCFDE0423D1DB58EA9E6A8F1BFFD849] GoodName=Explode Demo by NaN (PD) CRC=3E5D6755 9AE4BD3B [3B2CA0DA0810C95B31DF8C1FB8811BE2] GoodName=Extreme-G (E) (M5) [!] CRC=8E9D834E 1E8B29A9 Players=4 SaveType=None Mempak=Yes Rumble=Yes [BF72E10EB79E00E095829112576F01FE] GoodName=Extreme-G (E) (M5) [b1] CRC=8E9D834E 1E8B29A9 RefMD5=3B2CA0DA0810C95B31DF8C1FB8811BE2 [A059E27DE410BDA05D8603C22776979F] GoodName=Extreme-G (E) (M5) [b2] CRC=8E9D834E 1E8B29A9 RefMD5=3B2CA0DA0810C95B31DF8C1FB8811BE2 [B74A059D227830C606BA79134278F55E] GoodName=Extreme-G (E) (M5) [b3] CRC=8E9D834E 1E8B29A9 RefMD5=3B2CA0DA0810C95B31DF8C1FB8811BE2 [2257945EABC008E4D6464196B288D5BF] GoodName=Extreme-G (E) (M5) [b4] CRC=8E9D834E 1E8B29A9 RefMD5=3B2CA0DA0810C95B31DF8C1FB8811BE2 [972D0468CEB1221214ADED7181DA7853] GoodName=Extreme-G (E) (M5) [h1C] CRC=8E9D834E 1E8B29A9 RefMD5=3B2CA0DA0810C95B31DF8C1FB8811BE2 [A7CD65E5A4A8838D1CD452BA66E74DF6] GoodName=Extreme-G (J) [!] CRC=EE802DC4 690BD57D Players=4 SaveType=None Mempak=Yes Rumble=Yes [3E660D3F991C0529E90BFEC0244DB31A] GoodName=Extreme-G (U) [!] CRC=FDA245D2 A74A3D47 SaveType=None Mempak=Yes Players=4 Rumble=Yes [6D954294E254E239B3EA694C2D9ADFF9] GoodName=Extreme-G (U) [h1C] CRC=FDA245D2 A74A3D47 RefMD5=3E660D3F991C0529E90BFEC0244DB31A [E5D2C7CE59282C0D716DD67CA787CF7B] GoodName=Extreme-G (U) [o1] CRC=FDA245D2 A74A3D47 RefMD5=3E660D3F991C0529E90BFEC0244DB31A [B760D4C35303C74B893F1168415D743D] GoodName=Extreme-G (U) [t1] CRC=9FD881BC 0A62D002 RefMD5=3E660D3F991C0529E90BFEC0244DB31A [BB7F98E657FB4B5FCC7DC04BD72E2D2B] GoodName=Extreme-G XG2 (E) (M5) [!] CRC=1185EC85 4B5A7731 Players=4 SaveType=None Mempak=Yes Rumble=Yes [F17884A2C16FB6FD11A74D65B1388B4A] GoodName=Extreme-G XG2 (J) [!] CRC=399B9B81 D533AD11 Players=4 SaveType=None Mempak=Yes Rumble=Yes [44FE06BA3686C02A7988F27600A533DA] GoodName=Extreme-G XG2 (U) [!] CRC=5CD4150B 470CC2F1 Players=4 SaveType=None Mempak=Yes Rumble=Yes [B0F9C3EC65C1C88A43C694EBF429E008] GoodName=Extreme-G XG2 (U) [t1] CRC=21910973 0F2E70D2 RefMD5=44FE06BA3686C02A7988F27600A533DA [A6BD93EA576CDF8569F68171452F7E8A] GoodName=F-1 Pole Position 64 (E) (M3) [!] CRC=FDD248B2 569A020E Players=1 SaveType=None Mempak=Yes [ACBB37B24238F82B2333B710CBEE388A] GoodName=F-1 Pole Position 64 (E) (M3) [b1] CRC=FDD248B2 569A020E RefMD5=A6BD93EA576CDF8569F68171452F7E8A [049DB657F4223D949F56E9DC5B6A9180] GoodName=F-1 Pole Position 64 (U) (M3) [!] CRC=AE82687A 9A3F388D Players=1 SaveType=None Mempak=Yes [6CE5D16E977B1D4E0E71E209B2932099] GoodName=F-1 Pole Position 64 (U) (M3) [b1] CRC=AE82687A 9A3F388D RefMD5=049DB657F4223D949F56E9DC5B6A9180 [C8C14D748679AE6F8FF1A62C4AD3B61E] GoodName=F-1 Pole Position 64 (U) (M3) [b2] CRC=AE82687A 9A3F388D RefMD5=049DB657F4223D949F56E9DC5B6A9180 [9E684FDCAC7B5999CC863084DECA463D] GoodName=F-1 Pole Position 64 (U) (M3) [h1C] CRC=AE82687A 9A3F388D RefMD5=049DB657F4223D949F56E9DC5B6A9180 [9FBE3363DA6C146EF2E29605BCA834FF] GoodName=F-1 World Grand Prix (E) (Prototype) [!] CRC=CC3CC8B3 0EC405A4 Players=2 SaveType=Eeprom 4KB Rumble=Yes [08B8942E977A81CAF81DAC2237E1AA65] GoodName=F-1 World Grand Prix (E) (Prototype) [h1C] CRC=CC3CC8B3 0EC405A4 RefMD5=9FBE3363DA6C146EF2E29605BCA834FF [FAC450EAFF8FA46A1414DB02E6EEAB9F] GoodName=F-1 World Grand Prix (E) [!] CRC=C006E3C0 A67B4BBB Players=2 SaveType=Eeprom 4KB Rumble=Yes [35F6C42D5A9284688284C24250F4D6BE] GoodName=F-1 World Grand Prix (F) [!] CRC=B70BAEE5 3A5005A8 Players=2 SaveType=Eeprom 4KB Rumble=Yes [A8C78454C70BD73375AAF69C4078D5DA] GoodName=F-1 World Grand Prix (G) [!] CRC=38442634 66B3F060 Players=2 SaveType=Eeprom 4KB Rumble=Yes [AA15FA62A776917E594A17B49BBC6980] GoodName=F-1 World Grand Prix (G) [b1] CRC=38442634 66B3F060 RefMD5=A8C78454C70BD73375AAF69C4078D5DA [43115145F2DC0F3D0C6091D05CB9FA52] GoodName=F-1 World Grand Prix (G) [b1][o1] CRC=38442634 66B3F060 RefMD5=A8C78454C70BD73375AAF69C4078D5DA [38B0DB4916328672ED592759FFB1F09C] GoodName=F-1 World Grand Prix (G) [h1C] CRC=38442634 66B3F060 RefMD5=A8C78454C70BD73375AAF69C4078D5DA [3CEE1895A80005940887C9830B09DDE6] GoodName=F-1 World Grand Prix (G) [o1] CRC=38442634 66B3F060 RefMD5=A8C78454C70BD73375AAF69C4078D5DA [6E5858A47CB42F9B1CB26042BA229EF6] GoodName=F-1 World Grand Prix (G) [o1][h1C] CRC=38442634 66B3F060 RefMD5=A8C78454C70BD73375AAF69C4078D5DA [F248F0AAE609111BA9DFF9FD7AFBC485] GoodName=F-1 World Grand Prix (J) [!] CRC=64BF47C4 F4BD22BA Players=2 SaveType=Eeprom 4KB Rumble=Yes [7DFE40E387971269F38FE3CBE803567A] GoodName=F-1 World Grand Prix (J) [h1C] CRC=64BF47C4 F4BD22BA RefMD5=F248F0AAE609111BA9DFF9FD7AFBC485 [A81B1DE864DF3F4BB0903760BE673F21] GoodName=F-1 World Grand Prix (U) [!] CRC=CC3CC8B3 0EC405A4 SaveType=Eeprom 4KB Players=2 Rumble=Yes [4E450DD2899FE7434110E30E19DD10A2] GoodName=F-1 World Grand Prix (U) [h1C] CRC=CC3CC8B3 0EC405A4 RefMD5=A81B1DE864DF3F4BB0903760BE673F21 [05426547E5AD9DBF88CF0A401032079D] GoodName=F-1 World Grand Prix (U) [h2C] CRC=CC3CC8B3 0EC405A4 RefMD5=A81B1DE864DF3F4BB0903760BE673F21 [BC0FD2468AC7769A37C3C58CD5699585] GoodName=F-1 World Grand Prix II (E) (M4) [!] CRC=07C1866E 5775CCDE Players=2 Rumble=Yes [D9B59E463A73FA880E6682A08D1C3071] GoodName=F-1 World Grand Prix II (E) (M4) [f1] (NTSC) CRC=67C38660 94038DC6 RefMD5=BC0FD2468AC7769A37C3C58CD5699585 [E94A9142B1D981A6556747BA147E1A19] GoodName=F-1 World Grand Prix II (E) (M4) [h1C] CRC=07C1866E 5775CCDE RefMD5=BC0FD2468AC7769A37C3C58CD5699585 [4024477AAED7DD5FF5EA60BF568123B7] GoodName=F-ZERO X (Ch) (iQue) [!] Players=4 [8400C0875E16F599C1B7FC433E339D58] GoodName=F-ZERO X (Ch) (V2) (iQue) (Manual) [!] [9729FC397E8D178EA974869E07DF0502] GoodName=F-ZERO X (Ch) (V4) (iQue) (Manual) [!] [EE79A8FE287B5DCAEA584439363342FC] GoodName=F-ZERO X (E) [!] CRC=776646F6 06B9AC2B Players=4 SaveType=SRAM Rumble=Yes [0722E679F9695D9E5F1D2823DC7D8004] GoodName=F-ZERO X (E) [b1] CRC=776646F6 06B9AC2B RefMD5=EE79A8FE287B5DCAEA584439363342FC [99DC3FF78356CE77CB240AC7782EE6E5] GoodName=F-ZERO X (E) [b2] CRC=DAA6CA7D 56AA4394 RefMD5=EE79A8FE287B5DCAEA584439363342FC [2E95E5833894A6E1E3D109E3B3D809F1] GoodName=F-ZERO X (E) [b3] CRC=EC986EA9 EB463E4A RefMD5=EE79A8FE287B5DCAEA584439363342FC [308384EEEB6A88B5B498179E7484944F] GoodName=F-ZERO X (E) [b4] CRC=DAA6CA7D 56AA4394 RefMD5=EE79A8FE287B5DCAEA584439363342FC [D1368C0E3869B85947A55C3DA6FFCA10] GoodName=F-ZERO X (E) [f1] CRC=DAA6CA7D 56AA4394 RefMD5=EE79A8FE287B5DCAEA584439363342FC [ACE58F325D5EECBE033B21F2C7BFE870] GoodName=F-ZERO X (E) [h1C] CRC=776646F6 06B9AC2B RefMD5=EE79A8FE287B5DCAEA584439363342FC [58D200D43620007314304F4E6C9E6528] GoodName=F-ZERO X (J) [!] CRC=4D3E622E 9B828B4E Players=4 SaveType=SRAM Rumble=Yes [C14AE14C6DE0DCA126C423C4ADBEE315] GoodName=F-ZERO X (J) [b1] CRC=076C5C15 BDA9D062 RefMD5=58D200D43620007314304F4E6C9E6528 [E6EC9D86F94CEB2E311F9C23BBD3781F] GoodName=F-ZERO X (J) [b2] CRC=076C5C15 BDA9D062 RefMD5=58D200D43620007314304F4E6C9E6528 [6AC12C2D6C0CCDF27C0D5179A500BB2D] GoodName=F-ZERO X (J) [b3] CRC=076C5C15 BDA9D062 RefMD5=58D200D43620007314304F4E6C9E6528 [75AEA2B252309552E434B30EDFE72711] GoodName=F-ZERO X (J) [t1] CRC=076C5C15 BDA9D062 RefMD5=58D200D43620007314304F4E6C9E6528 [C1CDB77BEA29A4B6F9A0829F8BA8A3F3] GoodName=F-ZERO X (U) (DXP Track Pack Hack) CRC=3983D1A9 2004158C SaveType=SRAM Players=4 Rumble=Yes [753437D0D8ADA1D12F3F9CF0F0A5171F] GoodName=F-ZERO X (U) [!] CRC=B30ED978 3003C9F9 SaveType=SRAM Players=4 Rumble=Yes [20F5EEEE849DB44146AAFB1B97A857F6] GoodName=F-ZERO X (U) [T+Por0.99_byftr] CRC=485256FF CF6DF912 RefMD5=753437D0D8ADA1D12F3F9CF0F0A5171F [3AE32658B839FFA3189E3CA84E0B884A] GoodName=F-ZERO X (U) [f1] (Sex V1.0 Hack) CRC=7E399849 03DAC1CD [8363F102FE496B8D06494AA22E183A3E] GoodName=F-ZERO X (U) [f1] (Sex V1.1 Hack) CRC=D767D118 A1B07602 [7AC3B9A3AA846C439575912811B3E6E0] GoodName=F-ZERO X (U) [f1] CRC=B0B4EDFF B2A20628 RefMD5=753437D0D8ADA1D12F3F9CF0F0A5171F [EA168957B644AFE852DA1B827AFC3F9F] GoodName=F-ZERO X (U) [f2] (GameShark) CRC=0B46D03D 5FFAE173 RefMD5=753437D0D8ADA1D12F3F9CF0F0A5171F [44D5F87127053A21DB120BD108B7AC0C] GoodName=F1 Racing Championship (B) (M2) [!] CRC=53CCAD28 AEA6EDA2 Players=2 SaveType=None Mempak=Yes Rumble=Yes [9581FC6CEAC86DC8A2AEE4053043E422] GoodName=F1 Racing Championship (E) (M5) [!] CRC=3CECBCB8 6126BF07 Players=2 SaveType=None Mempak=Yes Rumble=Yes [AA951294528CA2CF55F810F9FE433F8D] GoodName=F1 Racing Championship (E) (M5) [f1] (NTSC) CRC=67D239A0 960F3A1A RefMD5=9581FC6CEAC86DC8A2AEE4053043E422 [26B18D35984528AE2F90ADBB2F2642F7] GoodName=FIFA - Road to World Cup 98 (E) (M7) [!] CRC=0E31EDF0 C37249D5 Players=4 SaveType=None Mempak=Yes [479554129EB27A3546BAC96C80AF4F88] GoodName=FIFA - Road to World Cup 98 (E) (M7) [o1] CRC=0E31EDF0 C37249D5 RefMD5=26B18D35984528AE2F90ADBB2F2642F7 [2C6D146A8473511CFCFBBE8518F49D71] GoodName=FIFA - Road to World Cup 98 (U) (M7) [!] CRC=CB1ACDDE CF291DF2 Players=4 SaveType=None Mempak=Yes [4E275B05BABCA9F2CD77749026BEA5ED] GoodName=FIFA - Road to World Cup 98 (U) (M7) [b1] CRC=CB1ACDDE CF291DF2 RefMD5=2C6D146A8473511CFCFBBE8518F49D71 [4CAAE8CA91F58D746B6A00BCBC122B87] GoodName=FIFA - Road to World Cup 98 (U) (M7) [b2] CRC=CB1ACDDE CF291DF2 RefMD5=2C6D146A8473511CFCFBBE8518F49D71 [217D93B21FEC3A5506DB014BF445B581] GoodName=FIFA - Road to World Cup 98 (U) (M7) [b3] CRC=CB1ACDDE CF291DF2 RefMD5=2C6D146A8473511CFCFBBE8518F49D71 [4421F891F0BA3CC7AA0FD566A162F2C8] GoodName=FIFA - Road to World Cup 98 (U) (M7) [b4] CRC=CB1ACDDE CF291DF2 RefMD5=2C6D146A8473511CFCFBBE8518F49D71 [0B8303E33B3F6E57531FB8EB3FAE65E9] GoodName=FIFA - Road to World Cup 98 (U) (M7) [o1] CRC=CB1ACDDE CF291DF2 RefMD5=2C6D146A8473511CFCFBBE8518F49D71 [3611779F29997267622CBC80E2D087CC] GoodName=FIFA - Road to World Cup 98 - World Cup heno Michi (J) [!] CRC=F5733C67 17A3973A Players=4 SaveType=None Mempak=Yes [6432C622C05EA9CD3217E280AC2CE37C] GoodName=FIFA 99 (E) (M8) [!] CRC=0198A651 FC219D84 Players=4 SaveType=None Mempak=Yes [940FFB6C94F84BFFD972A69ED86DD2FD] GoodName=FIFA 99 (E) (M8) [hI] CRC=F82C85BE DEB717E2 RefMD5=6432C622C05EA9CD3217E280AC2CE37C [148DE3073727B9FD156F10AFADD46864] GoodName=FIFA 99 (U) [!] CRC=7613A630 3ED696F3 Players=4 SaveType=None Mempak=Yes [22082B8D892A2560032FD4DA5AB975A1] GoodName=FIFA 99 (U) [b1] CRC=21250314 E6A82CB9 RefMD5=148DE3073727B9FD156F10AFADD46864 [9A7006212947EE7648EE1D13162E55E0] GoodName=FIFA Soccer 64 (E) (M3) [!] CRC=C3F19159 65D2BC5A Players=4 SaveType=None Mempak=Yes [1D71761771E3BFFC091E38B9E8B5E590] GoodName=FIFA Soccer 64 (E) (M3) [b1] CRC=C3F19159 65D2BC5A RefMD5=9A7006212947EE7648EE1D13162E55E0 [B5FBF033D76FDE89375D84B8918A5B61] GoodName=FIFA Soccer 64 (E) (M3) [o1] CRC=C3F19159 65D2BC5A RefMD5=9A7006212947EE7648EE1D13162E55E0 [084ABA16D84C87712A731D485FCDBE3E] GoodName=FIFA Soccer 64 (E) (M3) [o2] CRC=C3F19159 65D2BC5A RefMD5=9A7006212947EE7648EE1D13162E55E0 [376FFEC460443409BC29BB815ABFB42A] GoodName=FIFA Soccer 64 (E) (M3) [o3] CRC=C3F19159 65D2BC5A RefMD5=9A7006212947EE7648EE1D13162E55E0 [CF55223F9E3BD118969A34950BEDFD1F] GoodName=FIFA Soccer 64 (E) (M3) [o4] CRC=C3F19159 65D2BC5A RefMD5=9A7006212947EE7648EE1D13162E55E0 [CC7C58A032AABA19E72CCBFA6B3EEFF6] GoodName=FIFA Soccer 64 (U) (M3) [!] CRC=C3F19159 65D2BC5A Players=4 SaveType=None Mempak=Yes [CA56F2DE80839EC88750C15A21AA7C53] GoodName=FIFA Soccer 64 (U) (M3) [b1] CRC=C3F19159 65D2BC5A RefMD5=CC7C58A032AABA19E72CCBFA6B3EEFF6 [37B24EE746A1EFD54730B5E24551E8CB] GoodName=FIFA Soccer 64 (U) (M3) [o1] CRC=C3F19159 65D2BC5A RefMD5=CC7C58A032AABA19E72CCBFA6B3EEFF6 [D99B1A3F6D72DEFD76F3620959B94944] GoodName=Famista 64 (J) [!] CRC=6DFF4C37 B1B763FD Mempak=Yes [EACE2271AE7F32A71625C9074115D640] GoodName=Famista 64 (J) [b1] CRC=6DFF4C37 B1B763FD [FE1B92F6A7E15A1AF367FAD957375B20] GoodName=Famista 64 (J) [b2] CRC=6DFF4C37 B1B763FD [4C9B2848A2EED723C331973A926488AB] GoodName=Famista 64 (J) [b3] CRC=6DFF4C37 B1B763FD [35F3928F12DA627DB79EDFC96B93F8D3] GoodName=Famista 64 (J) [b4] CRC=6DFF4C37 B1B763FD [9213243118ACCE5664D1A35CCDCCD87E] GoodName=Famista 64 (J) [b5] CRC=6DFF4C37 B1B763FD [155FA36DD3927A73534461B50417325F] GoodName=Famista 64 (J) [b6] CRC=6DFF4C37 B1B763FD [30413678CE47E1A2EB8DA80AF0D768F5] GoodName=Famista 64 (J) [b7] CRC=6DFF4C37 B1B763FD [ADAD4FF18E09D2F5B29AA6B5F159EF4E] GoodName=Famista 64 (J) [o1] CRC=6DFF4C37 B1B763FD [04DD2A319F4F5C22569B612CFDF9F00C] GoodName=Fighter Destiny 2 (U) [!] CRC=AEEF2F45 F97E30F1 Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [7B5AFA5D60F53FA640A5F2F24F5B2741] GoodName=Fighter Destiny 2 (U) [f1] (PAL-NTSC) CRC=11FBD007 E7029A81 RefMD5=04DD2A319F4F5C22569B612CFDF9F00C [EF5CB24CE3FE4E0F850901205437B574] GoodName=Fighter's Destiny (E) [!] CRC=36F1C74B F2029939 Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [44B0BE1C4B48F6119D3AC9424903D0EB] GoodName=Fighter's Destiny (F) [!] CRC=0C41F9C2 01717A0D Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [1CF379ACA2397222AF9F3DC5D8E3C444] GoodName=Fighter's Destiny (G) [!] CRC=FE94E570 E4873A9C Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [D61D97A7658C419A25A9BAC96B0A3DF8] GoodName=Fighter's Destiny (U) [!] CRC=52F78805 8B8FCAB7 Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [6E7C82AFF9F73A3DBF5B18D924BDF103] GoodName=Fighter's Destiny (U) [b1] CRC=52F78805 8B8FCAB7 RefMD5=D61D97A7658C419A25A9BAC96B0A3DF8 [5FB4DE8B475C4427F0F30A28C1266CF9] GoodName=Fighter's Destiny (U) [o1] CRC=52F78805 8B8FCAB7 RefMD5=D61D97A7658C419A25A9BAC96B0A3DF8 [722C3A74A90305D6079A37994CEBF5B2] GoodName=Fighting Cup (J) [!] CRC=49E46C2D 7B1A110C Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [0035E8205336982E362402AAEA37D147] GoodName=Fighting Force 64 (E) [!] CRC=66CF0FFE AD697F9C Players=2 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [E7008D17FD71D9C2BDA1362C885388B2] GoodName=Fighting Force 64 (U) [!] CRC=32EFC7CB C3EA3F20 Players=2 SaveType=None Mempak=Yes CountPerOp=1 Rumble=Yes [13962910EFD82C2A2333CF38EE1FCD96] GoodName=Fighting Force 64 (U) [T+Ita_Cattivik66] CRC=32EFC7CB C3EA3F20 RefMD5=E7008D17FD71D9C2BDA1362C885388B2 [55868ECCCC14F43BF61032DE21D9F026] GoodName=Fighting Force 64 (U) [t1] CRC=655BE931 9FB2E4FB RefMD5=E7008D17FD71D9C2BDA1362C885388B2 [F427033D9184ACA164B971E559C0B420] GoodName=Fighting Force 64 (U) [t1][f1] (PAL) CRC=6976748D 1BF61F62 RefMD5=E7008D17FD71D9C2BDA1362C885388B2 [3B86A6C5B478A0D33A6547D3EA276AFE] GoodName=Fire Demo by Lac (PD) CRC=8E248649 2E1CDE52 SaveType=None Players=0 Rumble=No Status=3 [75F4A7E5932FB4AE791875E770E51C72] GoodName=Fireworks Demo by CrowTRobo (PD) CRC=ECAEC238 EE351DDA [BD46DD6275077D5A701482571F5DCDCC] GoodName=Fish Demo by NaN (PD) CRC=5CABD891 6229F6CE [ADD115AAD0AB7D33BFD243936D809178] GoodName=Flying Dragon (E) [!] CRC=22E9623F B60E52AD SaveType=None Mempak=Yes Players=2 CountPerOp=1 Rumble=Yes [272B359D8F8AC48ACBF053C262F422E4] GoodName=Flying Dragon (U) [!] CRC=A92D52E5 1D26B655 SaveType=None Mempak=Yes Players=2 CountPerOp=1 Rumble=Yes [46E9A352AD6AFB83B0557EC659957B2E] GoodName=Flying Dragon (U) [b1] CRC=A92D52E5 1D26B655 RefMD5=272B359D8F8AC48ACBF053C262F422E4 [1E672743A9B6B4E9DFB40D4004735F38] GoodName=Flying Dragon (U) [b2] CRC=A92D52E5 1D26B655 RefMD5=272B359D8F8AC48ACBF053C262F422E4 [171E55BF4383676C0B8F3D38B0D6A739] GoodName=Fogworld USA Demo by Horizon64 (PD) [h1C][o1] CRC=11C646E7 4D86C048 [B9A7BEFADFC4C46D61883B012FD2E69F] GoodName=Fogworld USA Demo by Horizon64 (PD) CRC=11C646E7 4D86C048 [8286DED701DFA22436D311BD5B93BD29] GoodName=Forsaken 64 (E) (M4) [!] CRC=142A17AA 13028D96 Players=4 SaveType=None Mempak=Yes Rumble=Yes [74650F7154E0B2DD7C364F511B0D6A77] GoodName=Forsaken 64 (G) [!] CRC=C3CD76FF 9B9DCBDE Players=4 SaveType=None Mempak=Yes Rumble=Yes [F023F3189722A96ACDCF0BDD9154EF11] GoodName=Forsaken 64 (G) [h1C] CRC=C3CD76FF 9B9DCBDE RefMD5=74650F7154E0B2DD7C364F511B0D6A77 [B775E4FF0205C405E3AA0A8DF50C54DE] GoodName=Forsaken 64 (G) [o1] CRC=C3CD76FF 9B9DCBDE RefMD5=74650F7154E0B2DD7C364F511B0D6A77 [5CDEE5503A57D14533C66B35A5848899] GoodName=Forsaken 64 (U) [!] CRC=9E330C01 8C0314BA Players=4 SaveType=None Mempak=Yes Rumble=Yes [C61FBF0BE56FBCD8FD373EDFB5D3E538] GoodName=Forsaken 64 (U) [b1] CRC=9E330C01 8C0314BA RefMD5=5CDEE5503A57D14533C66B35A5848899 [795F7C1D3D98125C3AEA0FFFE54410DE] GoodName=Forsaken 64 (U) [t1] CRC=21FF0391 09F141A1 RefMD5=5CDEE5503A57D14533C66B35A5848899 [ECB92E2663D5B3EEA08A149FC31E3701] GoodName=Forsaken 64 (U) [t2] CRC=21FF0391 09F141A1 RefMD5=5CDEE5503A57D14533C66B35A5848899 [A50182B02E3F0D28BE1AC341DDC92DCA] GoodName=Forsaken 64 (U) [t3] CRC=5E0C3DF7 8BA027D9 RefMD5=5CDEE5503A57D14533C66B35A5848899 [360DC6BE6D06DCA12E53C077AC0D2571] GoodName=Fox Sports College Hoops '99 (U) [!] CRC=3261D479 ED0DBC25 Players=2 SaveType=None Mempak=Yes [EE0C756F832827E3ACDF6DBD410ADCA4] GoodName=Fox Sports College Hoops '99 (U) [f1] (PAL) CRC=3261D429 70AF148E RefMD5=360DC6BE6D06DCA12E53C077AC0D2571 [5C4496C6D937364DE0022D1C07BE38A1] GoodName=Fractal Zoomer Demo by RedboX (PD) CRC=30E6FE79 3EEA5386 [7C87831B28D5E49F4EC2BDAE9D01F3B9] GoodName=Freekworld BBS Intro by Rene (PD) [a1] CRC=714001E3 2EB04B67 [DE7384A7DA97EEEAEF80CBEFBD17961A] GoodName=Freekworld BBS Intro by Rene (PD) CRC=714001E3 2EB04B67 [7CCB9B385D1405603E7F645352EA62AA] GoodName=Freekworld New Intro by Ste (PD) CRC=69458FFE C9D007AB [372F76C0DBE0BE41F5A0A47252869E8E] GoodName=Friendship Demo by Renderman (PD) [b1] CRC=CEE5C8CD D3D85466 [C18F1C91F6F15971DB18167EB72E6CEF] GoodName=Friendship Demo by Renderman (PD) CRC=CEE5C8CD D3D85466 [097189B4C9BF6775E4685951B6E66F24] GoodName=Frogger 2 (U) (Prototype 1) [!] CRC=AD19A172 9004666A Mempak=Yes [CB2C9C6104C3EF69A1CF979525F2F73D] GoodName=Frogger 2 (U) (Prototype 2) [!] CRC=E8E5B179 44AA30E8 Mempak=Yes [27F61A55E27EA7F1EDE4CA11966ACC7C] GoodName=Frogger 2 (U) (Alpha) [o1] CRC=E8E5B179 44AA30E8 RefMD5=CB2C9C6104C3EF69A1CF979525F2F73D [FA6CE44ECF86DEC0AFA321D82CD3ED6E] GoodName=Frogger 2 (U) (Alpha) [o2] CRC=E8E5B179 44AA30E8 RefMD5=CB2C9C6104C3EF69A1CF979525F2F73D [BBCDE4966BEE5602A80D9B8C1011DFA6] GoodName=Fushigi no Dungeon - Fuurai no Shiren 2 - Oni Shuurai! Shiren Jou! (J) [!] CRC=F774EAEE F0D8B13E Players=1 SaveType=SRAM Mempak=Yes CountPerOp=1 [316C59DAE45C20250A0419A937E7D65B] GoodName=G.A.S.P!! Fighter's NEXTream (E) [!] CRC=68FCF726 49658CBC Players=2 SaveType=None Mempak=Yes Rumble=Yes [6C73558DE5A1EEE6597D7264F9A11B0C] GoodName=G.A.S.P!! Fighter's NEXTream (J) [!] CRC=AF8679B6 5E1011BF Players=2 SaveType=None Mempak=Yes Rumble=Yes [D7C983F603EE7AE8156C6EAEEF7195C4] GoodName=G.A.S.P!! Fighter's NEXTream (J) [o1] CRC=AF8679B6 5E1011BF RefMD5=6C73558DE5A1EEE6597D7264F9A11B0C [F61757BE8ECF0D7068C23CFCE23D2F10] GoodName=GBlator for CD64 (PD) [f1] (V64-PAL) CRC=5D1795D2 C0D72338 [ECE232D98B095604D1C15F9571DE45F8] GoodName=GBlator for CD64 (PD) CRC=5D8B9226 47605A2A [E3FDAB4E3C417E623A02875D6A6E7467] GoodName=GBlator for NTSC Dr V64 (PD) CRC=5C1AAD1C AF7BF297 [0F85543F27896856EB82C52E3C7CCAB5] GoodName=GBlator for PAL Dr V64 (PD) CRC=5D0F8DD2 990BE538 [628AA3CD492559B705488F634797E045] GoodName=GT 64 - Championship Edition (E) (M3) [!] CRC=EE4A0E33 8FD588C9 SaveType=Eeprom 16KB Players=2 CountPerOp=1 Mempak=Yes Rumble=Yes [15DB716942C36A0CB392226001536A2A] GoodName=GT 64 - Championship Edition (E) (M3) [b1] CRC=B6A90FB4 E2C235BA RefMD5=628AA3CD492559B705488F634797E045 [6969E979395A0AF64CAF2DF9C1054C94] GoodName=GT 64 - Championship Edition (E) (M3) [f1] (NTSC) CRC=B6A90FB4 E2C235BA RefMD5=628AA3CD492559B705488F634797E045 [F3E25D0A7B98E8E25B7570A6E056D33C] GoodName=GT 64 - Championship Edition (E) (M3) [f2] (NTSC) CRC=93A292F1 ADF98E2E RefMD5=628AA3CD492559B705488F634797E045 [FE81AA381719FADA693D803BAE7D5EB9] GoodName=GT 64 - Championship Edition (U) [!] CRC=C49ADCA2 F1501B62 Players=2 SaveType=Eeprom 16KB CountPerOp=1 Mempak=Yes Rumble=Yes [4695A944B019F3829F2616591659A7CE] GoodName=GT 64 - Championship Edition (U) [b1] CRC=C49ADCA2 F1501B62 RefMD5=FE81AA381719FADA693D803BAE7D5EB9 [9B5A92F32B9C807B2A9C01E42EF8F461] GoodName=GT Demo (PD) [a1] CRC=2575EF19 D13D2A2C [C41F0D1EDD2C8259EB27A8C97CAA3D71] GoodName=GT Demo (PD) CRC=2575EF19 D13D2A2C [3DE02CF363E4D081530FEF53FDAB5780] GoodName=Game Boy 64 (POM '98) (PD) (Illegal Mode Enabled) CRC=97FC2167 4616872B [6C36E6A39ABBAB3E9139E9ECBC67E569] GoodName=Game Boy 64 (POM '98) (PD) CRC=97FC2167 4616872B [47C7DF82B3ADEAE19C8AFACE40FEB1AC] GoodName=Game Boy 64 + Super Mario 3 (PD) CRC=60D0A702 432236C6 [7AD954ADD3779FB3BE5904D1B935EBFB] GoodName=GameBooster 64 V1.1 (NTSC) (Unl) [b1] CRC=1A5C1CAD 7BAF97F2 [C60F99DCF6B05FAA2C33970462F93865] GoodName=GameBooster 64 V1.1 (NTSC) (Unl) [f1] CRC=5C1AAD1C AF7BF297 [60D0264B38E22EF0D6B9549E4C81C29F] GoodName=GameBooster 64 V1.1 (NTSC) (Unl) CRC=12678830 4E5AE439 [DB02D36555E2473EA3036B8E0868254E] GoodName=GameBooster 64 V1.1 (PAL) (Unl) [b1] CRC=D06002A7 2243C636 [4C383E57BC1062466328D0B59FB7AA67] GoodName=GameBooster 64 V1.1 (PAL) (Unl) [f1] (Sound) CRC=3BCCD2DB 953FA1F5 [1A56FE2B2FE339C7DD4FF8D37EC8654B] GoodName=GameBooster 64 V1.1 (PAL) (Unl) CRC=12678830 4E5AE439 [437EFD7FD7F84F4C0F802D3BF1F8464E] GoodName=GameShark Pro V2.0 (Unl) CRC=16FB52A4 7AED1FB3 [F275A4216744D8F04B4A0CD74DE53111] GoodName=GameShark Pro V3.3 (Apr 2000) (Unl) [!] CRC=EA6D5BF8 E2B4696C [9F556D184D945369DDD11B5F815814A8] GoodName=GameShark Pro V3.3 (Mar 2000) (Unl) [!] CRC=8F89ABA0 C34C2610 [96CA36D474E82C270A129D775C63167A] GoodName=Ganbare Goemon - Derodero Douchuu Obake Tenkomori (J) [!] CRC=457B9CD9 09C55352 Players=2 SaveType=SRAM Rumble=Yes CountPerOp=1 [7EB07675E2E9CB547A3B238AA71F57CC] GoodName=Ganbare Goemon - Derodero Douchuu Obake Tenkomori (J) [t1] CRC=BD8E0304 33E3998A RefMD5=96CA36D474E82C270A129D775C63167A [3F50712011BE1CB59B45684D7D61F11E] GoodName=Ganbare Goemon - Derodero Douchuu Obake Tenkomori (J) [t2] CRC=A39C0306 F1DD4CC6 RefMD5=96CA36D474E82C270A129D775C63167A [2BDE49F2855030DE342976C9A95B81B3] GoodName=Ganbare Goemon - Mononoke Sugoroku (J) [!] CRC=B2C6D27F 2DA48CFD Players=4 SaveType=SRAM Mempak=Yes [9B929E0BF8D63E62820F2FA6257CC5CF] GoodName=Ganbare Goemon - Neo Momoyama Bakufu no Odori (J) [!] CRC=832C168B 56A2CDAE Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [7F4E8F2ECF04BE27E660AC2EFDAC0C68] GoodName=Ganbare Goemon - Neo Momoyama Bakufu no Odori (J) [b1] CRC=832C168B 56A2CDAE RefMD5=9B929E0BF8D63E62820F2FA6257CC5CF [19BFC2C0124C009B51FE1724B07FAC81] GoodName=Ganbare Goemon - Neo Momoyama Bakufu no Odori (J) [b2] CRC=832C168B 56A2CDAE RefMD5=9B929E0BF8D63E62820F2FA6257CC5CF [A2B81C0B7E3989152CA90901D05E6352] GoodName=Ganbare Goemon - Neo Momoyama Bakufu no Odori (J) [h1C] CRC=832C168B 56A2CDAE RefMD5=9B929E0BF8D63E62820F2FA6257CC5CF [A7C82BB5098A7526D5417EE9A8981F48] GoodName=Ganbare Goemon - Neo Momoyama Bakufu no Odori (J) [h1C][t1] CRC=7BB5698F D99BF02B RefMD5=9B929E0BF8D63E62820F2FA6257CC5CF [8D8F3A8393F3F5489B3B144369565594] GoodName=Ganbare Nippon! Olympics 2000 (J) [!] CRC=21FFFD0A FA0D1D98 Players=4 SaveType=SRAM Rumble=Yes [28C2108A375F7731E719333A09439D2F] GoodName=Gauntlet Legends (E) [!] CRC=D543BCD6 2BA5E256 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [0806E6DB8B2BF0501BE9F2D78D280DCF] GoodName=Gauntlet Legends (E) [b1] CRC=D543BCD6 2BA5E256 RefMD5=28C2108A375F7731E719333A09439D2F [3B2615D754A61E45B1034D555D830A78] GoodName=Gauntlet Legends (J) [!] CRC=70B0260E 6716D04C Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [9CB963E8B71F18568F78EC1AF120362E] GoodName=Gauntlet Legends (U) [!] CRC=729B5E32 B728D980 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [50F8E73CA0160EB1A339AC2137A7B559] GoodName=Gauntlet Legends (U) [f1] (PAL) CRC=AA89A18D 0FC2AFE6 RefMD5=9CB963E8B71F18568F78EC1AF120362E [5270D98F9E67DC7EF354ECE109C2A18F] GoodName=Getter Love!! (J) [!] CRC=489C84E6 4C6E49F9 Players=4 Mempak=Yes Rumble=Yes [0AC7A16F8AFCC03031835C89D095D7B9] GoodName=Getter Love!! (J) [T+Eng1.01_ozidual] CRC=CDDB4BDF 84E5EFAC RefMD5=5270D98F9E67DC7EF354ECE109C2A18F [3BE170E7E94A03BD4E36732EB137EE39] GoodName=Getter Love!! (J) [b1] CRC=489C84E6 4C6E49F9 RefMD5=5270D98F9E67DC7EF354ECE109C2A18F [1E6573F2A7454C133EB05A14C15909A9] GoodName=Getter Love!! (J) [b2] CRC=489C84E6 4C6E49F9 RefMD5=5270D98F9E67DC7EF354ECE109C2A18F [43B9A7A5CCB6EA3F4860F9F80D73669D] GoodName=Gex 3 - Deep Cover Gecko (E) (M2) (Fre-Ger) [!] CRC=874733A4 A823745A Players=1 SaveType=None Mempak=Yes Rumble=Yes [9F0492A34D7A2D7C4E9F29DC1848A04A] GoodName=Gex 3 - Deep Cover Gecko (E) (M3) (Eng-Spa-Ita) [!] CRC=99179359 2FE7EBC3 Players=1 SaveType=None Mempak=Yes Rumble=Yes [6770DDEC84EB21A5E0D0F55DFD52A01A] GoodName=Gex 3 - Deep Cover Gecko (U) [!] CRC=3EDC7E12 E26C1CC9 Players=1 SaveType=None Mempak=Yes Rumble=Yes [6E0FCFF93600A28C379EF52940C54E68] GoodName=Gex 3 - Deep Cover Gecko (U) [f1] (PAL) CRC=E68A9F6E 24FB3315 RefMD5=6770DDEC84EB21A5E0D0F55DFD52A01A [EF0988EFDCEA31B88A3920CEEC17B4FF] GoodName=Gex 3 - Deep Cover Gecko (U) [t1] CRC=E6896018 6013AD31 RefMD5=6770DDEC84EB21A5E0D0F55DFD52A01A [5BBA457E286D250101CE274E0E58080D] GoodName=Gex 64 - Enter the Gecko (E) [!] CRC=E68A000E 639166DD Players=1 SaveType=None Mempak=Yes [47F9D900C97ECE154BB40A9C6DCCD3FD] GoodName=Gex 64 - Enter the Gecko (U) [!] CRC=89FED774 CAAFE21B Players=1 SaveType=None Mempak=Yes [A33677B04870DE18013B760B4F53F6BF] GoodName=Gex 64 - Enter the Gecko (U) [f1] (PAL) CRC=4445612B F8CC9F8B RefMD5=47F9D900C97ECE154BB40A9C6DCCD3FD [68828BDCAAE1C222DABB679B74B8ACD0] GoodName=Gex 64 - Enter the Gecko (U) [t1] CRC=71ED5D14 76A110D0 RefMD5=47F9D900C97ECE154BB40A9C6DCCD3FD [3419EC10EE470F1888811D4A9B5FAACE] GoodName=Ghemor - CD64 Xfer & Save Util (CommsLink) by CrowTRobo (PD) CRC=2F67DC59 74AAD9F1 [20DA03C2098F83A790E929AC9A4CDB2E] GoodName=Ghemor - CD64 Xfer & Save Util (Parallel) by CrowTRobo (PD) CRC=0D99E899 43E0FCD1 [2F2163C53DB135792331DF00398B3F87] GoodName=Glover (E) (M3) [!] CRC=F5237301 99E3EE93 Players=1 SaveType=Eeprom 4KB [8881FBEAE9B84485CF66876B60CD45DF] GoodName=Glover (E) (M3) [f1] (NTSC) CRC=4D2B5318 47DB5316 RefMD5=2F2163C53DB135792331DF00398B3F87 [43C3375BBD6496B6C51D08EC193BC8ED] GoodName=Glover (Prototype) CRC=254CC736 6F5C721B [87AA5740DFF79291EE97832DA1F86205] GoodName=Glover (U) [!] CRC=8E6E01FF CCB4F948 Players=1 SaveType=Eeprom 4KB [A1C34717476027DFBA72EEA56F94D650] GoodName=Glover (U) [b1] CRC=0E450FFC 9FFC8375 RefMD5=87AA5740DFF79291EE97832DA1F86205 [873DC63304F632A71B309988C39C48F7] GoodName=Glover (U) [b2] CRC=7773E2BB 71D0A925 RefMD5=87AA5740DFF79291EE97832DA1F86205 [87615822A0E00DD4FC7FDF636D4B8139] GoodName=Glover (U) [t1] CRC=51938192 BD4A98A1 RefMD5=87AA5740DFF79291EE97832DA1F86205 [4E15D92CCA23E1A01BB65246431B5C5A] GoodName=Glover 2 - Unreleased Beta Version (New Build) (Prototype) CRC=8E9F21D2 DC19C5AB [A8567DDABD3672FFF18BC5DF933CF8C7] GoodName=Glover 2 (Prototype) CRC=B7F40BCF 553556A5 [29BC5C1A24D3979D376AD421000AC9CB] GoodName=Goemon's Great Adventure (U) [!] CRC=4252A5AD AE6FBF4E Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [231BAC1AFB3DE138072C2D697783059B] GoodName=Golden Nugget 64 (U) [!] CRC=4690FB1C 4CD56D44 Players=4 SaveType=None Mempak=Yes [7CE28ADAB6FE43207B4BB19564C38AEF] GoodName=Golden Nugget 64 (U) [b1] CRC=4690FB1C 4CD56D44 RefMD5=231BAC1AFB3DE138072C2D697783059B [5340DD96CF1CD7AC6D72000D40B915CE] GoodName=Golden Nugget 64 (U) [b2] CRC=4690FB1C 4CD56D44 RefMD5=231BAC1AFB3DE138072C2D697783059B [E048C2FE226634F039882C35A2A4EEA9] GoodName=Golden Nugget 64 (U) [b3] CRC=4690FB1C 4CD56D44 RefMD5=231BAC1AFB3DE138072C2D697783059B [2DB6ED9A6A244CB209FFDF52D9006E4D] GoodName=Golden Nugget 64 (U) [b3][f1] (PAL) CRC=438CEBDC 44C1837C RefMD5=231BAC1AFB3DE138072C2D697783059B [F68F02A69829469F208D538D7CF4A215] GoodName=Golden Nugget 64 (U) [b3][h1C] CRC=4690FB1C 4CD56D44 RefMD5=231BAC1AFB3DE138072C2D697783059B [CFF69B70A8AD674A0EFE5558765855C9] GoodName=GoldenEye 007 (E) [!] CRC=0414CA61 2E57B8AA Players=4 SaveType=Eeprom 4KB Rumble=Yes Status=4 [6E23E6BAD28F8AC5C07344DCB0C266B8] GoodName=GoldenEye 007 (E) [T+Spa2.0_Sogun&IlDucci] CRC=625E0850 1F1B2327 RefMD5=CFF69B70A8AD674A0EFE5558765855C9 [ECD4F078DC77F4B2D12C1C0F5CABA323] GoodName=GoldenEye 007 (E) [b1] CRC=0414CA61 2E57B8AA RefMD5=CFF69B70A8AD674A0EFE5558765855C9 [D83BDE156D6FC400C28308A447B8FCA0] GoodName=GoldenEye 007 (E) [h1C] CRC=0414CA61 2E57B8AA RefMD5=CFF69B70A8AD674A0EFE5558765855C9 [F7A0EFCF8DB90FBD6FD9BFC570A4804A] GoodName=GoldenEye 007 (E) [t1] (Rapid Fire) CRC=540F359D FF327745 RefMD5=CFF69B70A8AD674A0EFE5558765855C9 [1880DA358F875C0740D4A6731E110109] GoodName=GoldenEye 007 (J) [!] CRC=A24F4CF1 A82327BA Players=4 SaveType=Eeprom 4KB Rumble=Yes Status=4 [FB916F914D9635F8FCBCE37A6466079D] GoodName=GoldenEye 007 (J) [t1] (Rapid Fire) CRC=B244B30C 72A648D8 RefMD5=1880DA358F875C0740D4A6731E110109 [3AA7D5F55E3E5E6C7419CC1625AF69BC] GoodName=GoldenEye 007 (U) (Frozen Enemies Hack) CRC=DCBCACD1 D72FAA33 [9AB9FB9782C7BB42A48C1465CD8F4EF6] GoodName=GoldenEye 007 (E) (Citadel Hack) CRC=44853212 B1F75C3E [ECAB0839D3ED0E3AA8516EF1C077CF0D] GoodName=GoldenEye 007 (U) (Citadel Hack) CRC=1C6F7718 CBAC1E7E [7DD2F0E19E35511C3E1C81D206CDC472] GoodName=GoldenEye 007 (U) (G5 Multi (for backups) Hack) CRC=F2C3A524 A1C4DB13 [F4AB4CD6A8AF21E8A51BF48578CC7F24] GoodName=GoldenEye 007 (U) (G5 Multi Hack) CRC=DCBC50D1 09FD1AA3 [FD35D8A9DE0F5AB500A588A6AB5F6FB9] GoodName=GoldenEye 007 (U) (Tetris Hack) CRC=A84D23BA A1974DBD [3BC50511DE8598A49E79F4CF2E4CF8E0] GoodName=GoldenEye 007 (U) (God Mode Hack) CRC=DCBCACD1 E1051EA6 [86C6B996A55F90FC2410B16AE4BA5EE0] GoodName=GoldenEye 007 (U) (No Music Hack) CRC=DCBCACD1 A67DDFB4 [15B57CDECA506B34FF6246ED06AABD50] GoodName=GoldenEye 007 (U) (No Power Bar Hack) CRC=DCBCACD1 F294D541 [70C525880240C1E838B8B1BE35666C3B] GoodName=GoldenEye 007 (U) [!] CRC=DCBC50D1 09FD1AA3 Players=4 SaveType=Eeprom 4KB Rumble=Yes Status=4 [78F83525E0CC98641AEACE37E3FF7F16] GoodName=GoldenEye 007 (U) [T+Spa2.0_Sogun&IlDucci] CRC=3A03E50F E78D1CA7 RefMD5=70C525880240C1E838B8B1BE35666C3B [0B5A50E8D477B3BC53BE997264FE84A5] GoodName=GoldenEye 007 (U) [b1] CRC=DCBC50D1 09FD1AA3 RefMD5=70C525880240C1E838B8B1BE35666C3B [C7A22DC5D95EBE1F8EDB0D68C13027C1] GoodName=GoldenEye 007 (U) [h1C] CRC=DCBC50D1 09FD1AA3 RefMD5=70C525880240C1E838B8B1BE35666C3B [22FF6C18EB028792EF350554B1E1FA68] GoodName=GoldenEye 007 (U) [o1] CRC=DCBC50D1 09FD1AA3 RefMD5=70C525880240C1E838B8B1BE35666C3B [6B8BA063C40420C164AA81ACB6089CB6] GoodName=GoldenEye 007 (U) [o2] CRC=DCBC50D1 09FD1AA3 RefMD5=70C525880240C1E838B8B1BE35666C3B [18C00B5C3D9DF09AB9E8A737E61C3B47] GoodName=GoldenEye 007 (U) [t1] (Rapid Fire) CRC=E09DAF6C 8A2B86F4 RefMD5=70C525880240C1E838B8B1BE35666C3B [2E50BC853F6EFC1E0D5E4679739F43C4] GoodName=GoldenEye 007 (U) [t2] CRC=8E1B3303 9D4F5035 RefMD5=70C525880240C1E838B8B1BE35666C3B [95B784D6DD3470903BAF6BBB533E088B] GoodName=GoldenEye 007 (U) [t3] (All Guns Zoom Mode) CRC=1C6F7718 CBAC1E7E RefMD5=70C525880240C1E838B8B1BE35666C3B [AD3D099C84096DBACAD7F1CF982631B2] GoodName=GoldenEye 007 Intro by SonCrap (PD) CRC=9303DD17 0813B398 [67F2E18ED18A5F0EA3FE2D913E3F1786] GoodName=GoldenEye X ; Alternate Title=GoldenEye X (5e Clouds) CRC=FDF95D15 618546CA RefMD5=E03B088B6AC9E0080440EFED07C1E40F [435D75D07878D305293EC4D591B86303] GoodName=GoldenEye X ; Alternate Title=GoldenEye X (5e Cloudless) CRC=E8B3F63D E5A997B1 RefMD5=E03B088B6AC9E0080440EFED07C1E40F [EA0E3E6AEFA58738A12906298373218B] GoodName=GoldenEye 007 (UE) (Switch Online) [!] CRC=DCBC50D1 9FD1AA3 Players=4 SaveType=Eeprom 4KB Rumble=Yes [9B8A7541D0234F4D97004ECBC216D9C2] GoodName=HIPTHRUST by MooglyGuy (PD) CRC=88A12FB3 8A583CBD [821A739790F1D390DC7D4168C5E032DE] GoodName=HSD Quick Intro (PD) CRC=BD1263E5 388C9BE7 [26F7D8F4640EBDFA823F84E5F89D62BF] GoodName=HSV Adventure Racing (A) [!] CRC=72611D7D 9919BDD2 Players=4 SaveType=None CountPerOp=3 Rumble=Yes Mempak=Yes [7B38C3F7DA8D9778B41B0047A133590A] GoodName=HSV Adventure Racing (A) [b1] CRC=72611D7D 9919BDD2 RefMD5=26F7D8F4640EBDFA823F84E5F89D62BF [8C7AF37A3CB7306EBCCAC4029EB5C57D] GoodName=HSV Adventure Racing (A) [f1] (NTSC) CRC=B20CC247 B879579A RefMD5=26F7D8F4640EBDFA823F84E5F89D62BF [3D4C7B11076BAFA4620BCC154C0EEEF3] GoodName=Hamster Monogatari 64 (J) [!] CRC=95A80114 E0B72A7F Players=1 Mempak=Yes CountPerOp=1 [617197EF2B6B51E58488C9F6B75F112E] GoodName=Hard Coded Demo by Silo and Fractal (PD) [a1] CRC=775AFA9C 0EB52EF6 CountPerOp=1 [FB8974C6130A6B8585EA98D6661553BC] GoodName=Hard Coded Demo by Silo and Fractal (PD) CRC=775AFA9C 0EB52EF6 CountPerOp=1 [193913BB063F3D945019E8F765F48F1C] GoodName=Hard Pom '99 Demo by TS_Garp (POM '99) (PD) CRC=9856E53D AF483207 [A02A4FB4B93E9847348440652CEF8D4D] GoodName=Harukanaru Augusta Masters 98 (J) [!] CRC=09AE57B1 182A5637 Players=1 Mempak=Yes Rumble=Yes [397A69AA3829EA5FECB4CDF399084E31] GoodName=Harukanaru Augusta Masters 98 (J) [b1] CRC=09AE57B1 182A5637 RefMD5=A02A4FB4B93E9847348440652CEF8D4D [FA6B3E3A04DE8D96B2C26F974F59A34D] GoodName=Harukanaru Augusta Masters 98 (J) [b2] CRC=09AE57B1 182A5637 RefMD5=A02A4FB4B93E9847348440652CEF8D4D [4454122EC735252E40EC22FF5DE021C6] GoodName=Harukanaru Augusta Masters 98 (J) [h1C] CRC=09AE57B1 182A5637 RefMD5=A02A4FB4B93E9847348440652CEF8D4D [6DA848A70D83ECE130D274124760928E] GoodName=Harvest Moon 64 (U) [!] CRC=98DF9DFC 6606C189 Players=1 SaveType=SRAM CountPerOp=1 [3CDD87026EFEC9A03648D225F97858A5] GoodName=Harvest Moon 64 (U) [T+Pol001] CRC=98DF9DFC 6606C189 RefMD5=6DA848A70D83ECE130D274124760928E [245FD6D774B74D4703822511CA174A54] GoodName=Harvest Moon 64 (U) [b1] CRC=98DF9DFC 6606C189 RefMD5=6DA848A70D83ECE130D274124760928E [218DE5B3709555DA3870CE859D1975E5] GoodName=Harvest Moon 64 (U) [f1] (PAL) CRC=6BCF21E8 CAB5AF4F RefMD5=6DA848A70D83ECE130D274124760928E [956AEC111B74720D55496F81ADA0FEFD] GoodName=Harvest Moon 64 (U) [t1] CRC=60CC9644 C62AE877 RefMD5=6DA848A70D83ECE130D274124760928E [54AD823812D2C2E8B1688C4ACE2E654D] GoodName=Harvest Moon 64 (U) [t1][f1] (PAL-NTSC) CRC=60CC9644 C62AE877 RefMD5=6DA848A70D83ECE130D274124760928E [19F4694B8557BC095EE07B5C8FBD23B5] GoodName=Heavy 64 Demo by Destop (PD) CRC=5D391A40 84D7A637 [5E8539E037EEA88C5A2746F60E431C8D] GoodName=Heiwa Pachinko World 64 (J) [!] CRC=3E70E866 4438BAE8 Players=1 [78E2ED1DB5F90E2EA9C04771B27685BC] GoodName=Heiwa Pachinko World 64 (J) [T+Eng1.0_Zoinkity] CRC=3AE679E2 1A3C42DB RefMD5=5E8539E037EEA88C5A2746F60E431C8D [9D0D85E3A0C94B98D6404E8FC28E7B01] GoodName=Heiwa Pachinko World 64 (J) [b1] CRC=3E70E866 4438BAE8 RefMD5=5E8539E037EEA88C5A2746F60E431C8D [C2BEDCB364162D6DAC86548D7721F827] GoodName=Heiwa Pachinko World 64 (J) [b2] CRC=3E70E866 4438BAE8 RefMD5=5E8539E037EEA88C5A2746F60E431C8D [3B6994B373BEC6E917F0B834AA6D1A46] GoodName=Heiwa Pachinko World 64 (J) [b3] CRC=3E70E866 4438BAE8 RefMD5=5E8539E037EEA88C5A2746F60E431C8D [013E130D0D4F132741AA38D1A397E10A] GoodName=Heiwa Pachinko World 64 (J) [h1C] CRC=3E70E866 4438BAE8 RefMD5=5E8539E037EEA88C5A2746F60E431C8D [FDF797C5FFB531FCF04E0A1928691EA3] GoodName=Heiwa Pachinko World 64 (J) [o1] CRC=3E70E866 4438BAE8 RefMD5=5E8539E037EEA88C5A2746F60E431C8D [1546877FD85C00A83515005727E5FDA5] GoodName=Hercules - The Legendary Journeys (E) (M6) [!] CRC=AE90DBEB 79B89123 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [6BBD8C42F6EF8F5B9541D6F4DB657DD7] GoodName=Hercules - The Legendary Journeys (U) [!] CRC=7F3CEB77 8981030A Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [57D8E020643146B325A11612FEFACF74] GoodName=Hercules - The Legendary Journeys (U) [o1] CRC=7F3CEB77 8981030A RefMD5=6BBD8C42F6EF8F5B9541D6F4DB657DD7 [8CF8043BDFA89A2B0C4699D0E695E844] GoodName=Hercules - The Legendary Journeys (U) [t1][f1] (PAL-NTSC) CRC=DB7184C9 F53AC14A RefMD5=6BBD8C42F6EF8F5B9541D6F4DB657DD7 [C2C3115821C738A4834E977E8325F89E] GoodName=Hercules - The Legendary Journeys (U) [t1][f1][b1] CRC=DB7184C9 F53AC14A RefMD5=6BBD8C42F6EF8F5B9541D6F4DB657DD7 [3F1CF2D6C1580FDCCD662F9FCF8C4214] GoodName=Hercules - The Legendary Journeys (U) [t1][f2] (PAL-NTSC) CRC=DB7184C9 F53AC14A RefMD5=6BBD8C42F6EF8F5B9541D6F4DB657DD7 [2080262A251D270F9CE819887F2104A7] GoodName=Hexen (E) [!] CRC=95B2B30B 2B6415C1 Players=4 SaveType=None Mempak=Yes CountPerOp=1 [E86A8BF46985B7CE8459AFBE5FC3DCC3] GoodName=Hexen (E) [h1C] CRC=95B2B30B 2B6415C1 RefMD5=2080262A251D270F9CE819887F2104A7 [A5921C00111200257284CE0ABA0904CA] GoodName=Hexen (F) [!] CRC=5C1B5FBD 7E961634 Players=4 SaveType=None Mempak=Yes CountPerOp=1 [08CBB141DEC604E4DAD2787F237D57A2] GoodName=Hexen (G) [!] CRC=9AB3B50A BC666105 Players=4 SaveType=None Mempak=Yes CountPerOp=1 [35E9ECE11306EF7D8F5F09F65761D365] GoodName=Hexen (G) [h1C] CRC=9AB3B50A BC666105 RefMD5=08CBB141DEC604E4DAD2787F237D57A2 [672152CF4DCB5D0A19662C11EFF71452] GoodName=Hexen (J) [!] CRC=66751A57 54A29D6E Players=4 SaveType=None Mempak=Yes CountPerOp=1 [EB98F1B8C6898AF7417F6882946DA9B3] GoodName=Hexen (U) [!] CRC=9CAB6AEA 87C61C00 Players=4 SaveType=None Mempak=Yes CountPerOp=1 [B06625703DB3A03BAE3D02FD0F904541] GoodName=Hexen (U) [b1] CRC=9CAB6AEA 87C61C00 RefMD5=EB98F1B8C6898AF7417F6882946DA9B3 [EA5A22A5A2DA96D88939171CEA41A1F1] GoodName=Hexen (U) [h1C] CRC=9CAB6AEA 87C61C00 RefMD5=EB98F1B8C6898AF7417F6882946DA9B3 [9301923AE938320FF0186B7279AFE6D8] GoodName=Hexen (U) [t1] CRC=E6BA0A06 8A3D2C2F RefMD5=EB98F1B8C6898AF7417F6882946DA9B3 [59BA99120BE9D438C53EAED6091B9B7D] GoodName=Hexen (U) [t2] CRC=E6BA0A06 8A3D2C2F RefMD5=EB98F1B8C6898AF7417F6882946DA9B3 [1280C78F286FC1C437A4905EE42C47F1] GoodName=Hey You, Pikachu! (U) [!] CRC=D3F10E5D 052EA579 Players=1 SaveType=Eeprom 4KB Rumble=Yes AiDmaModifier=88 [DCC316EFFC4928F5B0AE8D273D8024BF] GoodName=HiRes CFB Demo (PD) CRC=4072572D A23DB72C [73084495F3209C54900525436BBBC531] GoodName=Hiryuu no Ken Twin (J) [!] CRC=35FF8F1A 6E79E3BE Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [8976913EFBE98EFED3B0B32CBCAA8B49] GoodName=Hiryuu no Ken Twin (J) [h1C] CRC=35FF8F1A 6E79E3BE RefMD5=73084495F3209C54900525436BBBC531 [E0C39E55DE1D588371D5F99056F3578C] GoodName=Hiryuu no Ken Twin (J) [h2C] CRC=35FF8F1A 6E79E3BE RefMD5=73084495F3209C54900525436BBBC531 [EA9B6EA32CCEB8F7EFBB2FEA211B8E89] GoodName=Hiryuu no Ken Twin (J) [h3C] CRC=35FF8F1A 6E79E3BE RefMD5=73084495F3209C54900525436BBBC531 [80CC112F62E9A8581A1BB6A1D1E1488B] GoodName=Holy Magic Century (E) [!] CRC=277B129D DD3879FF Players=1 SaveType=None Mempak=Yes [FA6A2E00BBFF236DAC91F08544AFFA40] GoodName=Holy Magic Century (E) [b1] CRC=277B129D DD3879FF RefMD5=80CC112F62E9A8581A1BB6A1D1E1488B [988F5ABD96259196343659E913666820] GoodName=Holy Magic Century (F) CRC=B35FEBB0 7427B204 Players=1 SaveType=None Mempak=Yes [668908C495432AD099C5439E38809053] GoodName=Holy Magic Century (F) [h1C] CRC=B35FEBB0 7427B204 RefMD5=988F5ABD96259196343659E913666820 [27D3EFBD35B1F580330961480B988FB5] GoodName=Holy Magic Century (F) [o1] CRC=B35FEBB0 7427B204 RefMD5=988F5ABD96259196343659E913666820 [AB676C3E9D26A77450DDB4AACD1A3861] GoodName=Holy Magic Century (G) [!] CRC=75FA0E14 C9B3D105 Players=1 SaveType=None Mempak=Yes [ACF823A6EF4E77FE5B940D716DCED6E9] GoodName=Holy Magic Century (G) [b1] CRC=75FA0E14 C9B3D105 RefMD5=AB676C3E9D26A77450DDB4AACD1A3861 [E26F4FFD2AA19E6EE9F9216A15189F14] GoodName=Holy Magic Century (G) [b2] CRC=75FA0E14 C9B3D105 RefMD5=AB676C3E9D26A77450DDB4AACD1A3861 [F40D3DE4745BACC69458BAB25D6067F9] GoodName=Holy Magic Century (G) [b3] CRC=75FA0E14 C9B3D105 RefMD5=AB676C3E9D26A77450DDB4AACD1A3861 [B1A67AEBC2BE89A800E5EB60C0DFA968] GoodName=Hoshi no Kirby 64 (J) (V1.0) [!] CRC=C1D702BD 6D416547 SaveType=SRAM Players=4 Rumble=Yes [460A42ED5612EBBF92F386689067384E] GoodName=Hoshi no Kirby 64 (J) (V1.0) [f1] CRC=22F301B6 D0A03C3C RefMD5=B1A67AEBC2BE89A800E5EB60C0DFA968 [07EA11684D74DA87719F05A1BDC4CCB3] GoodName=Hoshi no Kirby 64 (J) (V1.0) [f2] CRC=57CD5D6D 046282B1 RefMD5=B1A67AEBC2BE89A800E5EB60C0DFA968 [FFDB4456F799722BCFE430632C3986AE] GoodName=Hoshi no Kirby 64 (J) (V1.1) [!] CRC=CA1BB86F 41CCA5C5 Players=4 SaveType=SRAM Rumble=Yes [3EC0471E2CBEE17471DDBF80C56606D5] GoodName=Hoshi no Kirby 64 (J) (V1.2) [!] CRC=0C581C7A 3D6E20E4 Players=4 SaveType=Eeprom 16KB Rumble=Yes [35E039F8E79843917D02BE06D00C457B] GoodName=Hoshi no Kirby 64 (J) (V1.3) [!] CRC=BCB1F89F 060752A2 Players=4 SaveType=Eeprom 16KB Rumble=Yes [EF34DA35EF8A0734843CB182C19FEB26] GoodName=Hot Wheels Turbo Racing (E) (M3) [!] CRC=E7D20193 C1158E93 Players=2 SaveType=None Mempak=Yes Rumble=Yes [BB8A58282C5D4E32B34556407ACD920E] GoodName=Hot Wheels Turbo Racing (E) (M3) [b1] CRC=E7D20193 C1158E93 RefMD5=EF34DA35EF8A0734843CB182C19FEB26 [4311A1AEF1898678331F7E3486055307] GoodName=Hot Wheels Turbo Racing (U) [!] CRC=C7C98F8E 42145DDE Players=2 SaveType=None Mempak=Yes Rumble=Yes [50091668743D2DE7CAA253420D32C2D8] GoodName=Hot Wheels Turbo Racing (U) [f1] (PAL) CRC=14DE709E F882947D RefMD5=4311A1AEF1898678331F7E3486055307 [7D32A665027ABB585BD4FB7194752B34] GoodName=Hot Wheels Turbo Racing (U) [t1] CRC=1FDFCBDC FCD77D11 RefMD5=4311A1AEF1898678331F7E3486055307 [97E706ED9CC6F30708FFDC187C85D59F] GoodName=Human Grand Prix - New Generation (J) [!] CRC=5535972E BD8E3295 Players=1 SaveType=None Mempak=Yes [F9A6FFD35D478A8E2B369460BFAB2CC8] GoodName=Human Grand Prix - New Generation (J) [b1] CRC=5535972E BD8E3295 RefMD5=97E706ED9CC6F30708FFDC187C85D59F [7BD3F10D47DB6D062280D8AE750A1ACB] GoodName=Human Grand Prix - New Generation (J) [o1] CRC=5535972E BD8E3295 RefMD5=97E706ED9CC6F30708FFDC187C85D59F [DA861C4D9202F661575466450A27C412] GoodName=Hybrid Heaven (E) (M3) [!] CRC=641D3A7F 86820466 Players=2 SaveType=None Mempak=Yes Rumble=Yes [24B023696975D27EAE8319EF40001348] GoodName=Hybrid Heaven (E) (M3) [b1] CRC=641D3A7F 86820466 RefMD5=DA861C4D9202F661575466450A27C412 [E6F18336406EF3BFC990483BBF184ACD] GoodName=Hybrid Heaven (E) (M3) [f1] (NTSC) CRC=DCCEDB8F BA79BEDE RefMD5=DA861C4D9202F661575466450A27C412 [9946EFF915FC947A226407AC1F7B35C4] GoodName=Hybrid Heaven (J) [!] CRC=0DE2CE36 D41D29E6 Players=2 SaveType=SRAM Mempak=Yes Rumble=Yes [94B284286A090B5980B7F18A4FA77853] GoodName=Hybrid Heaven (J) [b1] CRC=0DE2CE36 D41D29E6 RefMD5=9946EFF915FC947A226407AC1F7B35C4 [151E92F5E3EE294BAFF5D4C3E4E95D77] GoodName=Hybrid Heaven (J) [f1] (PAL) CRC=DE4E5E2E DCD0615D RefMD5=9946EFF915FC947A226407AC1F7B35C4 [C47E95BB32AB132C41D67BD243F9E02A] GoodName=Hybrid Heaven (U) [!] CRC=102888BF 434888CA Players=2 SaveType=None Mempak=Yes Rumble=Yes [115521BAC11608FEBCE874F243ACC66E] GoodName=Hybrid Heaven (U) [f1] (PAL) CRC=FB610592 898A9705 RefMD5=C47E95BB32AB132C41D67BD243F9E02A [0A44393E1C97E4F91303029E27F28AF4] GoodName=Hybrid Heaven (U) [t1] CRC=E8DBC96A DAC9E2EE RefMD5=C47E95BB32AB132C41D67BD243F9E02A [434BB8DE49011573AC38E893224C5623] GoodName=Hydro Thunder (E) [!] CRC=B58988E9 B1FC4BE8 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [1F57194EA272CF5DB500D228E9C94D75] GoodName=Hydro Thunder (E) [f1] (NTSC) CRC=EDFB6B01 8893F62C RefMD5=434BB8DE49011573AC38E893224C5623 [4B4C85D9DD2D460ADAFABAE8DB48B4FA] GoodName=Hydro Thunder (F) [!] CRC=29A045CE ABA9060E Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [54F43E6B68782E98CAABEA5E7976B2BE] GoodName=Hydro Thunder (U) [!] CRC=C8DC65EB 3D8C8904 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [22AAD544C062FB8A2DC6B2DEB32DE188] GoodName=Hydro Thunder (U) [b1] CRC=C8DC65EB 3D8C8904 RefMD5=54F43E6B68782E98CAABEA5E7976B2BE [71DCDBE9F4B37A251E2877900CDBF406] GoodName=Hydro Thunder (U) [b1][f1] (PAL) CRC=63CCD041 F12A8BC0 RefMD5=54F43E6B68782E98CAABEA5E7976B2BE [A5B6E5D7B689216BA5C8F6360BF89B67] GoodName=Hydro Thunder (U) [b1][t1] CRC=B6DB2595 BC45273B RefMD5=54F43E6B68782E98CAABEA5E7976B2BE [85ACEBC851A407630D7464CCB63408BE] GoodName=Hydro Thunder (U) [b2] CRC=C8DC65EB 3D8C8904 RefMD5=54F43E6B68782E98CAABEA5E7976B2BE [F47575C35C7352E685B848CDAFF96B80] GoodName=Hydro Thunder (U) [b3] CRC=C8DC65EB 3D8C8904 RefMD5=54F43E6B68782E98CAABEA5E7976B2BE [D2F7B3ACE75A2CE7A06BEAC929711D94] GoodName=Hyper Olympics in Nagano 64 (J) [!] CRC=2FC5C34C 7A05CC9D Players=4 SaveType=None Mempak=Yes [3B6FF1829CBBEAE87704F53950791D64] GoodName=Hyper Olympics in Nagano 64 (J) [b1] CRC=2FC5C34C 7A05CC9D RefMD5=D2F7B3ACE75A2CE7A06BEAC929711D94 [F4D2BE1C47486AB3A6FCCCD2E7532C67] GoodName=Hyper Olympics in Nagano 64 (J) [b2] CRC=2FC5C34C 7A05CC9D RefMD5=D2F7B3ACE75A2CE7A06BEAC929711D94 [BAC8634F10F286E6A0DB889FCD12B25E] GoodName=Hyper Olympics in Nagano 64 (J) [b3] CRC=2FC5C34C 7A05CC9D RefMD5=D2F7B3ACE75A2CE7A06BEAC929711D94 [20AE0BA68601EB0A49D61BC7A00FEADD] GoodName=Hyper Olympics in Nagano 64 (J) [o1] CRC=2FC5C34C 7A05CC9D RefMD5=D2F7B3ACE75A2CE7A06BEAC929711D94 [92A6FFA1C8D537C7A97C5C613CAE05C6] GoodName=Ide Yousuke no Mahjong Juku (J) [!] CRC=77DA3B8D 162B0D7C Players=1 SaveType=Eeprom 16KB [DC577D70E9308F94E5F3CE03F3508539] GoodName=Ide Yousuke no Mahjong Juku (J) [b1] CRC=77DA3B8D 162B0D7C RefMD5=92A6FFA1C8D537C7A97C5C613CAE05C6 [25B297143E9E5CCBB4B80A7FB6AF399B] GoodName=Iggy's Reckin' Balls (E) [!] CRC=D692CC5E EC58D072 Players=2 SaveType=None Mempak=Yes Rumble=Yes DisableExtraMem=1 [26CEC7A56ABB81F3468CFA26D8F16B67] GoodName=Iggy's Reckin' Balls (E) [o1] CRC=D692CC5E EC58D072 RefMD5=25B297143E9E5CCBB4B80A7FB6AF399B [464211ABB602EE1005974D2D835A3BCF] GoodName=Iggy's Reckin' Balls (U) [!] CRC=E616B5BC C9658B88 Players=2 SaveType=None Mempak=Yes Rumble=Yes DisableExtraMem=1 [8BF0EAFB7014B7B5CE8E7D778B6B4B99] GoodName=Iggy's Reckin' Balls (U) [o1] CRC=E616B5BC C9658B88 RefMD5=464211ABB602EE1005974D2D835A3BCF [C70B0B680807F2B8C2C3D5DC495FA8C2] GoodName=Iggy-kun no Bura Bura Poyon (J) [!] CRC=69458B9E FC95F936 Players=2 SaveType=None Mempak=Yes Rumble=Yes DisableExtraMem=1 [827106236756DC5B585C4226184835FA] GoodName=Iggy-kun no Bura Bura Poyon (J) [o1] CRC=69458B9E FC95F936 RefMD5=C70B0B680807F2B8C2C3D5DC495FA8C2 [C605F40BF669E00A5E51BAF0D00621EA] GoodName=In-Fisherman Bass Hunter 64 (U) [!] CRC=8C138BE0 95700E46 SaveType=Eeprom 4KB Players=1 Rumble=Yes CountPerOp=1 [1AF93922A67085AB2C777B1F08AF365B] GoodName=In-Fisherman Bass Hunter 64 (U) [f1] (PAL) CRC=F050D644 B5A5CED1 RefMD5=C605F40BF669E00A5E51BAF0D00621EA [70DE1EAB508596B6BBEFD168B5D07194] GoodName=Indiana Jones and the Infernal Machine (U) [!] CRC=AF9DCC15 1A723D88 Players=1 SaveType=Eeprom 4KB Rumble=Yes [63D7AB29BA3DFC5D5B12C1D9C5832355] GoodName=Indiana Jones and the Infernal Machine (E) (Unreleased) CRC=3A6F8C6B 2897BAEB Players=1 SaveType=Eeprom 4KB Rumble=Yes [A7781D441AF55C4FF8AFC68AB3A59313] GoodName=Indy Racing 2000 (U) [!] CRC=E436467A 82DE8F9B SaveType=Eeprom 4KB Players=2 Rumble=Yes [34489365B550F32C97337D86D52D8C84] GoodName=International Superstar Soccer '98 (E) [!] CRC=F41B6343 C10661E6 Players=4 SaveType=None Mempak=Yes [7DCC05B98E2FA690B478808EBBAD5D1A] GoodName=International Superstar Soccer '98 (U) [!] CRC=7F0FDA09 6061CE0B Players=4 SaveType=None Mempak=Yes [43B326B27B89288F2D17D22EA49F86BD] GoodName=International Superstar Soccer '98 (U) [o1] CRC=7F0FDA09 6061CE0B RefMD5=7DCC05B98E2FA690B478808EBBAD5D1A [9F101B6F6BEF4F267DEB5C6C37A24B97] GoodName=International Superstar Soccer 2000 (E) (M2) (Eng-Ger) [!] CRC=336364A0 06C8D5BF Players=4 SaveType=None Mempak=Yes Rumble=Yes [CC2BE97A16744860FAE8A94611479C4C] GoodName=International Superstar Soccer 2000 (E) (M2) (Fre-Ita) [!] CRC=BAE8E871 35FF944E Players=4 SaveType=None Mempak=Yes Rumble=Yes [23A4ED8D79882594206173B1D476F0E9] GoodName=International Superstar Soccer 2000 (U) (M2) [!] CRC=8E835437 CD5748B4 Players=4 SaveType=None Mempak=Yes Rumble=Yes [ACF18822457A451B09BD88E15A70505C] GoodName=International Superstar Soccer 2000 (U) (M2) [f1] (PAL) CRC=30B6A6AB 319EFD09 RefMD5=23A4ED8D79882594206173B1D476F0E9 [DE9498BE76134BD066AA714CE2C71A16] GoodName=International Superstar Soccer 2000 (U) (V1.1) (M2) [!] CRC=96816CCD 272EA8C Players=4 SaveType=None Mempak=Yes Rumble=Yes [376803F28CA8B2133671783419933CA2] GoodName=International Superstar Soccer 64 (E) [!] CRC=E2D37CF0 F57E4EAE Players=4 SaveType=None Mempak=Yes CountPerOp=1 [7FCC22F4BF1FC82F886C455981D2A420] GoodName=International Superstar Soccer 64 (E) [b1] CRC=E2D37CF0 F57E4EAE RefMD5=376803F28CA8B2133671783419933CA2 [FD0102D535BC3BBB22DD823A636DC757] GoodName=International Superstar Soccer 64 (E) [b2] CRC=E2D37CF0 F57E4EAE RefMD5=376803F28CA8B2133671783419933CA2 [65B9CAC3900435ED6893B9D489F1655F] GoodName=International Superstar Soccer 64 (E) [h1C] CRC=E2D37CF0 F57E4EAE RefMD5=376803F28CA8B2133671783419933CA2 [70D480A73DB5751EED9E826108005834] GoodName=International Superstar Soccer 64 (E) [h2C] CRC=E2D37CF0 F57E4EAE RefMD5=376803F28CA8B2133671783419933CA2 [6A345402AE1DB5CE1041365E36126BCE] GoodName=International Superstar Soccer 64 (U) [!] CRC=5F2763C4 62412AE5 Players=4 SaveType=None Mempak=Yes CountPerOp=1 [C0969E1C141BE6E144E651CAB1AEA3D8] GoodName=International Superstar Soccer 64 (U) [b1] CRC=5F2763C4 62412AE5 RefMD5=6A345402AE1DB5CE1041365E36126BCE [0321FCDCD35E6DC0D3F4DC1251919997] GoodName=International Superstar Soccer 64 (U) [h1C] CRC=5F2763C4 62412AE5 RefMD5=6A345402AE1DB5CE1041365E36126BCE [37A4F634CADB89DC3E43D389ED050925] GoodName=International Superstar Soccer 64 (U) [h2C] CRC=5F2763C4 62412AE5 RefMD5=6A345402AE1DB5CE1041365E36126BCE [35662CFD07FD6AF4BAB90CA23F7C98E6] GoodName=International Track & Field 2000 (U) [!] CRC=20073BC7 5E3B0111 Players=4 SaveType=None Mempak=Yes Rumble=Yes [970488FB7D9C5C25BD924E6F898B84A0] GoodName=International Track & Field Summer Games (E) (M3) [!] CRC=6712C779 3B72781D Players=4 SaveType=None Mempak=Yes Rumble=Yes [F9190DBAF547D6D3F5F3569ACCF26061] GoodName=iQue Club (Ch) (V3) (iQue) [!] [1247B093E0FD6CCFD50D15DE59301076] GoodName=J.League Dynamite Soccer 64 (J) [!] CRC=87766747 91C27165 Players=4 Mempak=Yes [849DA5F1790A386B1CD9118CA1398E9D] GoodName=J.League Dynamite Soccer 64 (J) [b1] CRC=87766747 91C27165 RefMD5=1247B093E0FD6CCFD50D15DE59301076 [F3A1B04E1F3436E183932B54212B75B5] GoodName=J.League Dynamite Soccer 64 (J) [b2] CRC=87766747 91C27165 RefMD5=1247B093E0FD6CCFD50D15DE59301076 [20FBBA5FCCB7454367E071A744D6BB2F] GoodName=J.League Dynamite Soccer 64 (J) [b3] CRC=87766747 91C27165 RefMD5=1247B093E0FD6CCFD50D15DE59301076 [2085FBD994D3597A8A520F695E336382] GoodName=J.League Dynamite Soccer 64 (J) [b4] CRC=87766747 91C27165 RefMD5=1247B093E0FD6CCFD50D15DE59301076 [E0071B3CE2E29597DC4C73D83402723C] GoodName=J.League Dynamite Soccer 64 (J) [h1C] CRC=87766747 91C27165 RefMD5=1247B093E0FD6CCFD50D15DE59301076 [F7544B9DF78D3CDB1C1B31006372C531] GoodName=J.League Dynamite Soccer 64 (J) [h2C] CRC=87766747 91C27165 RefMD5=1247B093E0FD6CCFD50D15DE59301076 [F848E34DC2918C708D2D0C02E082B06B] GoodName=J.League Dynamite Soccer 64 (J) [h3C] CRC=87766747 91C27165 RefMD5=1247B093E0FD6CCFD50D15DE59301076 [30E23D3DE446E37E5E7FBEF6794A6FC9] GoodName=J.League Eleven Beat 1997 (J) [!] CRC=4FBFA429 6920BB15 Players=4 Mempak=Yes [E3CE4ADB8A7C0CF39E11A2846E00178A] GoodName=J.League Eleven Beat 1997 (J) [b1][h1C] CRC=4FBFA429 6920BB15 RefMD5=30E23D3DE446E37E5E7FBEF6794A6FC9 [BEF0F36513F6FA8B01638319252B2B99] GoodName=J.League Eleven Beat 1997 (J) [b2][h1C] CRC=4FBFA429 6920BB15 RefMD5=30E23D3DE446E37E5E7FBEF6794A6FC9 [476FDC0554BD3B4746FC871FDD02F4B2] GoodName=J.League Eleven Beat 1997 (J) [h1C] CRC=4FBFA429 6920BB15 RefMD5=30E23D3DE446E37E5E7FBEF6794A6FC9 [209DB8333EEB526AE9A91209175348CE] GoodName=J.League Live 64 (J) [!] CRC=54554A42 E4985FFB Players=4 Mempak=Yes [46F584DBFA1E292F0ECA74CA1B12009C] GoodName=J.League Live 64 (J) [b1] CRC=54554A42 E4985FFB RefMD5=209DB8333EEB526AE9A91209175348CE [800ACC7D609ECDB3E09E68CBD05F5FA0] GoodName=J.League Tactics Soccer (J) (V1.0) [!] CRC=E8D29DA0 15E61D94 Players=4 [F604701C59C7D2BBA2492D0073E928F2] GoodName=J.League Tactics Soccer (J) (V1.0) [b1] CRC=E8D29DA0 15E61D94 RefMD5=800ACC7D609ECDB3E09E68CBD05F5FA0 [7D5AFCD953BB15EC204B175761CA28C2] GoodName=J.League Tactics Soccer (J) (V1.0) [f1] (PAL) CRC=E8D2A500 5AA8DBCA RefMD5=800ACC7D609ECDB3E09E68CBD05F5FA0 [793DBF504E20C92F6B73B4E8A25A220C] GoodName=J.League Tactics Soccer (J) (V1.1) [!] CRC=C6CE0AAA D117F019 Players=4 [45F6B7EAF40E8445205904934EE365A6] GoodName=JPEG Slideshow Viewer by Garth Elgar (PD) CRC=A957851C 535A5667 [8EE01DE7DA2E9AD08D7ED913A5EE8632] GoodName=Jangou Simulation Mahjong Do 64 (J) [!] CRC=C73AD016 48C5537D Players=1 Mempak=Yes [82388A4B44EF74F9C250C8152AB93669] GoodName=Jangou Simulation Mahjong Do 64 (J) [b1] CRC=C73AD016 48C5537D RefMD5=8EE01DE7DA2E9AD08D7ED913A5EE8632 [014464F2AC70FBBB94B08B9762E65A72] GoodName=Jangou Simulation Mahjong Do 64 (J) [b2] CRC=C73AD016 48C5537D RefMD5=8EE01DE7DA2E9AD08D7ED913A5EE8632 [304F496CE0858959700C7F71E55C55B7] GoodName=Jangou Simulation Mahjong Do 64 (J) [b3] CRC=C73AD016 48C5537D RefMD5=8EE01DE7DA2E9AD08D7ED913A5EE8632 [E3706865241D2BCA4F397B4567CF2C2E] GoodName=Japan Pro Golf Tour 64 (J) [CART HACK] CRC=C99936D1 23D1D65D [A45F7200537C0D928A88CBBA2DFEB680] GoodName=Jeopardy! (U) [!] CRC=69256460 B9A3F586 Players=3 SaveType=None [05318721C273CB65CFBDF78AC2724BF2] GoodName=Jeopardy! (U) [h1C] CRC=69256460 B9A3F586 RefMD5=A45F7200537C0D928A88CBBA2DFEB680 [190584D9C0DC2875183FB84C5072B8F1] GoodName=Jeopardy! (U) [o1] CRC=69256460 B9A3F586 RefMD5=A45F7200537C0D928A88CBBA2DFEB680 [79BDD4467E102A1CBB4CC74DFC96BF7D] GoodName=Jeopardy! (U) [o1][h1C] CRC=69256460 B9A3F586 RefMD5=A45F7200537C0D928A88CBBA2DFEB680 [4C5BE1BFC1CCCFF501EBA2A685226962] GoodName=Jeremy McGrath Supercross 2000 (E) [!] CRC=21F7ABFB 6A8AA7E8 Players=4 SaveType=None Mempak=Yes Rumble=Yes [8046A4B8ABD4353B2AB9696106CCF8D2] GoodName=Jeremy McGrath Supercross 2000 (U) [!] CRC=BB30B1A5 FCF712CE Players=4 SaveType=None Mempak=Yes Rumble=Yes [29E0AB31B3FC6A6B1EFC11FBDB82CB97] GoodName=Jeremy McGrath Supercross 2000 (U) [f1] CRC=46C6F185 E13841C8 RefMD5=8046A4B8ABD4353B2AB9696106CCF8D2 [BAAF237E71AA7526C9B2F01C08B68A53] GoodName=Jet Force Gemini (E) (M4) [!] CRC=68D7A1DE 0079834A Players=4 SaveType=Flash RAM Rumble=Yes [821E7F74880BBD04AA9501D3BB25138E] GoodName=Jet Force Gemini (E) (M4) [T+Ita0.9beta_Rulesless] CRC=68D7A1DE 0079834A RefMD5=BAAF237E71AA7526C9B2F01C08B68A53 [76996A6CC868AC0E2BB2506A3C4DB606] GoodName=Jet Force Gemini (E) (M4) [f1] CRC=B66E0F7C 2709C22F RefMD5=BAAF237E71AA7526C9B2F01C08B68A53 [5BBE9ADE7171F2E1DAAA7C48FAD38728] GoodName=Jet Force Gemini (U) (Kiosk Demo) [!] CRC=DFD8AB47 3CDBEB89 Players=4 Rumble=Yes [E423A21C971B8A91C3E8980E2605B840] GoodName=Jet Force Gemini (U) (Kiosk Demo) [b1] CRC=DFD8AB47 3CDBEB89 RefMD5=5BBE9ADE7171F2E1DAAA7C48FAD38728 [2525E3734B921E662903E94BAB119C32] GoodName=Jet Force Gemini (U) (Kiosk Demo) [b1][f1] (Save) CRC=9C660FA0 C06A610D RefMD5=5BBE9ADE7171F2E1DAAA7C48FAD38728 [B4E3489F9B655439F9902F7A466CF973] GoodName=Jet Force Gemini (U) (Kiosk Demo) [b1][f2] CRC=8547FED3 C4945FAF RefMD5=5BBE9ADE7171F2E1DAAA7C48FAD38728 [69144CEED3F4D7B208D81A3DC3F57AD0] GoodName=Jet Force Gemini (U) (Kiosk Demo) [b2] CRC=DFD8AB47 3CDBEB89 RefMD5=5BBE9ADE7171F2E1DAAA7C48FAD38728 [772CC6EAB2620D2D3CDC17BBC26C4F68] GoodName=Jet Force Gemini (U) [!] CRC=8A6009B6 94ACE150 Players=4 SaveType=Flash RAM Rumble=Yes [92E6117285EC6A2D836B1C6839DDFD9B] GoodName=Jet Force Gemini (U) [b1] CRC=75CAA990 9FFDC9BD RefMD5=772CC6EAB2620D2D3CDC17BBC26C4F68 [745FCD72A921ED178AF6C319B09DF1F3] GoodName=Jet Force Gemini (U) [b2] CRC=CDB8B4D0 8832352D RefMD5=772CC6EAB2620D2D3CDC17BBC26C4F68 [878D8A26FD02FDB08200464CB6F566EF] GoodName=Jikkyou G1 Stable (J) (V1.0) [!] CRC=AF19D9F5 B70223CC Players=4 Mempak=Yes [4BBAF03594C6DCECB135AC8C57CB4CD7] GoodName=Jikkyou G1 Stable (J) (V1.0) [b1] CRC=AF19D9F5 B70223CC RefMD5=878D8A26FD02FDB08200464CB6F566EF [482BDD39AD2574B943DB780B12A9BDFB] GoodName=Jikkyou G1 Stable (J) (V1.1) [!] CRC=575F340B 9F1398B2 Players=4 Mempak=Yes [1FB40EE386B58FEAB6CF29DDB33BCCCC] GoodName=Jikkyou J.League 1999 - Perfect Striker 2 (J) (V1.0) [!] CRC=63112A53 A29FA88F Players=4 Mempak=Yes Rumble=Yes [3D2CCA1B2E3BDE267769812219EDB864] GoodName=Jikkyou J.League 1999 - Perfect Striker 2 (J) (V1.0) [b1] CRC=63112A53 A29FA88F RefMD5=1FB40EE386B58FEAB6CF29DDB33BCCCC [84B1421F658D5185812D861E23437520] GoodName=Jikkyou J.League 1999 - Perfect Striker 2 (J) (V1.0) [b2] CRC=63112A53 A29FA88F RefMD5=1FB40EE386B58FEAB6CF29DDB33BCCCC [B141C46C0FB2918D59933107EA8C1B7A] GoodName=Jikkyou J.League 1999 - Perfect Striker 2 (J) (V1.0) [f1] (PAL) CRC=3DBD5E85 EA9A328A RefMD5=1FB40EE386B58FEAB6CF29DDB33BCCCC [476203B64E2204306B591D5D3AFC7183] GoodName=Jikkyou J.League 1999 - Perfect Striker 2 (J) (V1.0) [f2] (PAL) CRC=22CA2C52 CA62736F RefMD5=1FB40EE386B58FEAB6CF29DDB33BCCCC [D9F8B84FD6FD21F0B1D750062AC86EFC] GoodName=Jikkyou J.League 1999 - Perfect Striker 2 (J) (V1.1) [!] CRC=6309FC17 1D4F5EF3 Players=4 Mempak=Yes Rumble=Yes [58153AC5C4030D1BFD3C15CF57FB02E7] GoodName=Jikkyou J.League Perfect Striker (J) [!] CRC=146C4366 72A6DEB3 Players=4 Mempak=Yes [759B8749E55113526E8C1C468E244CA8] GoodName=Jikkyou J.League Perfect Striker (J) [b1] CRC=146C4366 72A6DEB3 RefMD5=58153AC5C4030D1BFD3C15CF57FB02E7 [F012DC3C0CAA38618A1FAD27C73FCBD5] GoodName=Jikkyou J.League Perfect Striker (J) [b2] CRC=146C4366 72A6DEB3 RefMD5=58153AC5C4030D1BFD3C15CF57FB02E7 [6D1D465EBAACD3747B1362037ABED9EF] GoodName=Jikkyou J.League Perfect Striker (J) [b3] CRC=146C4366 72A6DEB3 RefMD5=58153AC5C4030D1BFD3C15CF57FB02E7 [C7152167915E8EB928C0CBBF9AF9886E] GoodName=Jikkyou J.League Perfect Striker (J) [f1] (PAL) CRC=3BCCA16E 0AF6D30F RefMD5=58153AC5C4030D1BFD3C15CF57FB02E7 [7FC933A64884A382AA07605EA7204FF5] GoodName=Jikkyou Powerful Pro Yakyuu - Basic Ban 2001 (J) (V1.0) [!] CRC=6EDD4766 A93E9BA8 Players=4 Mempak=Yes CountPerOp=3 [F13D0803885B73B4A6B35EDDD40B9253] GoodName=Jikkyou Powerful Pro Yakyuu - Basic Ban 2001 (J) (V1.1) [!] CRC=B00E3829 29F232D1 Players=4 Mempak=Yes CountPerOp=3 [23409668A6E6C4ECE7B5FB0B7D0E8F2C] GoodName=Jikkyou Powerful Pro Yakyuu 2000 (J) (V1.0) [!] CRC=0AC244D1 1F0EC605 Players=4 Mempak=Yes Transferpak=Yes [B653C963ED8D3A749676810F07CFE4E5] GoodName=Jikkyou Powerful Pro Yakyuu 2000 (J) (V1.1) [!] CRC=4264DF23 BE28BDF7 Players=4 Mempak=Yes Transferpak=Yes [FDA57F65EB159278223EB9D03267C27F] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.0) [!] CRC=34495BAD 502E9D26 Players=4 Mempak=Yes [7CC328FFAA5B77CD6247124DD0AF8899] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.0) [b1] CRC=34495BAD 502E9D26 RefMD5=FDA57F65EB159278223EB9D03267C27F [924E6553AEDE5EA66E2E14D29E48D929] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.0) [b2] CRC=34495BAD 502E9D26 RefMD5=FDA57F65EB159278223EB9D03267C27F [D9BA9FC609BFCDAC0081B7C568311BE1] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.0) [b3] CRC=34495BAD 502E9D26 RefMD5=FDA57F65EB159278223EB9D03267C27F [2BBD484BFA0F16C09C7F13FBDC2637C6] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.0) [b4] CRC=34495BAD 502E9D26 RefMD5=FDA57F65EB159278223EB9D03267C27F [1480E755E96B392490F606A75BC306C6] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.0) [b5] CRC=34495BAD 502E9D26 RefMD5=FDA57F65EB159278223EB9D03267C27F [950B88955933F42514A3F4284F5A285C] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.0) [o1] CRC=34495BAD 502E9D26 RefMD5=FDA57F65EB159278223EB9D03267C27F [B454490EB44F0978F009FA41DE8C478E] GoodName=Jikkyou Powerful Pro Yakyuu 4 (J) (V1.1) [!] CRC=D7891F1C C3E43788 Players=4 Mempak=Yes [E9F989E09E3F1519AEFE619889A4F710] GoodName=Jikkyou Powerful Pro Yakyuu 5 (J) (V1.0) [!] CRC=D22943DA AC2B77C0 Players=4 Mempak=Yes [CAFF2DAC142F169EE76965CA00518B26] GoodName=Jikkyou Powerful Pro Yakyuu 5 (J) (V1.0) [b1] CRC=D22943DA AC2B77C0 RefMD5=E9F989E09E3F1519AEFE619889A4F710 [4AC1589C067AC573FD63912A5C6C47A5] GoodName=Jikkyou Powerful Pro Yakyuu 5 (J) (V1.0) [f1] CRC=95854656 C8A24DC5 RefMD5=E9F989E09E3F1519AEFE619889A4F710 [8AF9D04DBA1313D1F5F4BA51D9592FBB] GoodName=Jikkyou Powerful Pro Yakyuu 5 (J) (V1.0) [f2] (PAL) CRC=38D637C1 5F05D28F RefMD5=E9F989E09E3F1519AEFE619889A4F710 [6EF19BF8D8D6196390745F1B858AC16A] GoodName=Jikkyou Powerful Pro Yakyuu 5 (J) (V1.1) [!] CRC=1C8CDF74 F761051F Players=4 Mempak=Yes [68A27FBAB060857C267A639931D2C3D6] GoodName=Jikkyou Powerful Pro Yakyuu 5 (J) (V1.2) [!] CRC=AC173077 5A14C012 Players=4 Mempak=Yes [060D0313E23B660180441FCC7D24D7DB] GoodName=Jikkyou Powerful Pro Yakyuu 6 (J) (V1.0) [!] CRC=B75E20B7 B3FEFDFD Mempak=Yes Transferpak=Yes [E6129460E23170FFD4EC4B09D5E0CC56] GoodName=Jikkyou Powerful Pro Yakyuu 6 (J) (V1.0) [b1] CRC=B75E20B7 B3FEFDFD RefMD5=060D0313E23B660180441FCC7D24D7DB [23EE24FABA0EDFB04B5B0407E174496B] GoodName=Jikkyou Powerful Pro Yakyuu 6 (J) (V1.1) [!] CRC=3C084040 081B060C Mempak=Yes Transferpak=Yes [03BD8E5CA2B1B7D74398DB4739979282] GoodName=Jikkyou Powerful Pro Yakyuu 6 (J) (V1.2) [!] CRC=438E6026 3BA24E07 Mempak=Yes Transferpak=Yes [A05E7DB2409DEECCA36E48E9D931CACB] GoodName=Jikkyou World Soccer - World Cup France '98 (J) (V1.0) [!] CRC=3FEA5620 7456DB40 Players=4 Mempak=Yes [538B54C2AAEA73FAA3A021D42A3225BE] GoodName=Jikkyou World Soccer - World Cup France '98 (J) (V1.1) [!] CRC=C954B38C 6F62BEB3 Players=4 Mempak=Yes [2E5FD9303138E8F558BF67BB9E799960] GoodName=Jikkyou World Soccer - World Cup France '98 (J) (V1.2) [!] CRC=E1C7ABD6 4E707F28 Players=4 Mempak=Yes [EF0F425689586850A6F5796124B0C85B] GoodName=Jikkyou World Soccer 3 (J) [!] CRC=E0A79F8C 32CC97FA Players=4 Mempak=Yes CountPerOp=1 [68230D510015FF6817EF898C0B8B636C] GoodName=Jinsei Game 64 (J) [!] CRC=4AAAF6ED 376428AD Players=4 Rumble=Yes [FBB0F6AF0A931EE4FEAEE4F3CC7DBE03] GoodName=Jinsei Game 64 (J) [f1] (PAL) CRC=7B016055 F8AC6092 RefMD5=68230D510015FF6817EF898C0B8B636C [7AB29C6AD2D8F4007D8213EB3411E0BD] GoodName=John Romero's Daikatana (E) (M3) [!] CRC=0F743195 D8A6DB95 Players=4 SaveType=None Mempak=Yes Rumble=Yes [2B417AD282DB321C9C67EDA7131A7F06] GoodName=John Romero's Daikatana (E) (M3) [f1] (NTSC) CRC=B6835E54 04A4A0D0 RefMD5=7AB29C6AD2D8F4007D8213EB3411E0BD [164050084561ECB691A51B6D1E5BF4AE] GoodName=John Romero's Daikatana (E) (M3) [h1C] CRC=0F743195 D8A6DB95 RefMD5=7AB29C6AD2D8F4007D8213EB3411E0BD [57D31EA7121DD5A05B547225EFA5CFD7] GoodName=John Romero's Daikatana (J) [!] CRC=9D7E3C4B E60F4A6C Players=4 SaveType=None Mempak=Yes Rumble=Yes [5B4C268422469F50B94779E655F2B798] GoodName=John Romero's Daikatana (U) [!] CRC=D0151AB0 FE5CA14B Players=4 SaveType=None Mempak=Yes Rumble=Yes [DFF0EFE2B35FCDE506D21B0C0BD373A5] GoodName=Kakutou Denshou - F-Cup Maniax (J) [!] CRC=4F29474F 30CB707A Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [9A70D30114F440B5240C10260AB2C8ED] GoodName=Kakutou Denshou - F-Cup Maniax (J) [f1] (PAL) CRC=F6E3494A E4EC8933 RefMD5=DFF0EFE2B35FCDE506D21B0C0BD373A5 [EEC0FAB75AF59E9C23E6DE2132DE89FF] GoodName=Ken Griffey Jr.'s Slugfest (U) [!] CRC=36281F23 009756CF SaveType=Flash RAM Players=2 Rumble=Yes [040A9EA84FA3C73A8F318358E3250AA4] GoodName=Ken Griffey Jr.'s Slugfest (U) [b1] CRC=76A8C9F4 3391893D RefMD5=EEC0FAB75AF59E9C23E6DE2132DE89FF [D9160E48CE1F06B9B749B43A38367A28] GoodName=Ken Griffey Jr.'s Slugfest (U) [b2] CRC=36281F23 009756CF RefMD5=EEC0FAB75AF59E9C23E6DE2132DE89FF [BF07DE5816FFEC94AF30CB9B9B35909F] GoodName=Ken Griffey Jr.'s Slugfest (U) [f1] CRC=76A8C9F4 3391893D RefMD5=EEC0FAB75AF59E9C23E6DE2132DE89FF [47B0348020C4200608B7EBD512028788] GoodName=Ken Griffey Jr.'s Slugfest (U) [f2] (PAL) CRC=76A8C9F4 3391893D RefMD5=EEC0FAB75AF59E9C23E6DE2132DE89FF [57C6B3E6309AC2F4BB64B5161E4ED8EF] GoodName=Ken Griffey Jr.'s Slugfest (U) [f3] (Nosave) CRC=730D25F4 4A37A36E RefMD5=EEC0FAB75AF59E9C23E6DE2132DE89FF [3E003A77F044F0C97748BE6861C55038] GoodName=Ken Griffey Jr.'s Slugfest (U) [f4] (Nosave-Z64) CRC=EAC07419 0F9F72A0 RefMD5=EEC0FAB75AF59E9C23E6DE2132DE89FF [9362C5AC8CA78C12FF553CB7F12A7FF1] GoodName=Ken Griffey Jr.'s Slugfest (U) [f5] CRC=76A8C9F4 3391893D RefMD5=EEC0FAB75AF59E9C23E6DE2132DE89FF [69F3D2580CB4C91C91C2E238C72B4403] GoodName=Kid Stardust Intro with Sound by Kid Stardust (PD) CRC=64709212 699BCF3B [68EB1713156605D5B05CFB838C214EF2] GoodName=Kid Stardust Intro with Sound by Kid Stardust (PD) [a1] CRC=64709212 699BCF3B RefMD5=69F3D2580CB4C91C91C2E238C72B4403 [C93D92F10A1A97D2BA87386BE7D178FD] GoodName=Killer Instinct Gold (E) [!] CRC=979B263E F8470004 Players=2 SaveType=Eeprom 4KB Mempak=Yes [A63F43CC53D9E57A045E1E20A5B12592] GoodName=Killer Instinct Gold (E) [o1] CRC=979B263E F8470004 RefMD5=C93D92F10A1A97D2BA87386BE7D178FD [8E33AD20C31FEB61D7230FAD28846C5C] GoodName=Killer Instinct Gold (U) (V1.0) [!] CRC=9E8FE2BA 8B270770 Players=2 SaveType=Eeprom 4KB Mempak=Yes [F73EA6171B04CD9FF05B76274E824194] GoodName=Killer Instinct Gold (U) (V1.0) [b1] CRC=9E8FE2BA 8B270770 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [F871B07C700F5BB373E648FC64D99D2E] GoodName=Killer Instinct Gold (U) (V1.0) [b1][t1] CRC=06CB44B7 3163DB94 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [D4CD4F6A5029048B44C8B420982E664E] GoodName=Killer Instinct Gold (U) (V1.0) [b2] CRC=06CB44B7 3163DB94 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [3EE5EF09471ED2ADF02E6E1BA8D17963] GoodName=Killer Instinct Gold (U) (V1.0) [b3] CRC=06CB44B7 3163DB94 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [DD44E1D799FB9000983C5291D9D34306] GoodName=Killer Instinct Gold (U) (V1.0) [b4] CRC=06CB44B7 3163DB94 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [C0B6DEEF900B63A5E4624804B14A1BA6] GoodName=Killer Instinct Gold (U) (V1.0) [b5] CRC=9E8FE2BA 8B270770 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [4C58608F3879627886051B7C035E3C23] GoodName=Killer Instinct Gold (U) (V1.0) [o1] CRC=9E8FE2BA 8B270770 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [DF607E79B1539F7D6F9AD34C31F42296] GoodName=Killer Instinct Gold (U) (V1.0) [o2] CRC=9E8FE2BA 8B270770 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [7496F1814AFBD1FC85FE76D6EBE9EA03] GoodName=Killer Instinct Gold (U) (V1.0) [t1] CRC=06CB44B7 3163DB94 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [1C3B29CC7F362CA63AC1C26456737BB3] GoodName=Killer Instinct Gold (U) (V1.0) [t2] CRC=06CB44B7 3163DB94 RefMD5=8E33AD20C31FEB61D7230FAD28846C5C [4C9B419DC583C0DF4AB908ADF83BFC65] GoodName=Killer Instinct Gold (U) (V1.1) [!] CRC=9E8FCDFA 49F5652B Players=2 SaveType=Eeprom 4KB Mempak=Yes [0CFF6A7C1B1334E07585F0C5CDB53B40] GoodName=Killer Instinct Gold (U) (V1.1) [o1] CRC=9E8FCDFA 49F5652B RefMD5=4C9B419DC583C0DF4AB908ADF83BFC65 [DD0A82FCC10397AFB37F12BB7F94E67A] GoodName=Killer Instinct Gold (U) (V1.2) [!] CRC=F908CA4C 36464327 Players=2 SaveType=Eeprom 4KB Mempak=Yes [2D79C395765A601F967CD3EF7CBF439E] GoodName=Killer Instinct Gold (U) (V1.2) [b1] CRC=06CB44B7 3163DB94 RefMD5=DD0A82FCC10397AFB37F12BB7F94E67A [3166BE5787BC30526E71277ECA3091DF] GoodName=Killer Instinct Gold (U) (V1.2) [o1] CRC=F908CA4C 36464327 RefMD5=DD0A82FCC10397AFB37F12BB7F94E67A [CCA4E87EC206B5B65AEAB9531C0F275B] GoodName=King Hill 64 - Extreme Snowboarding (J) [!] CRC=519EA4E1 EB7584E8 Players=2 SaveType=None Mempak=Yes Rumble=Yes [CE9AE0AA6DBBF965B1F72BC3AA6A7CEF] GoodName=King Hill 64 - Extreme Snowboarding (J) [b1] CRC=519EA4E1 EB7584E8 RefMD5=CCA4E87EC206B5B65AEAB9531C0F275B [18E741AAC72ECA5A9FEFEFE6F7A3E57A] GoodName=King Hill 64 - Extreme Snowboarding (J) [b2] CRC=519EA4E1 EB7584E8 RefMD5=CCA4E87EC206B5B65AEAB9531C0F275B [32257BFFFD9B2D680F582E148E9B0611] GoodName=Kira to Kaiketsu! 64 Tanteidan (J) [!] CRC=75BC6AD6 78552BC9 Players=4 Mempak=Yes Rumble=Yes [A44B7A612964A6D6139D0426E569D9C9] GoodName=Kirby 64 - The Crystal Shards (E) [!] CRC=0D93BA11 683868A6 Players=4 SaveType=Eeprom 16KB Rumble=Yes [E3BFAF1AD4A58A3AB7FD7310C1F45D81] GoodName=Kirby 64 - The Crystal Shards (E) [b1] CRC=0D93BA11 683868A6 RefMD5=A44B7A612964A6D6139D0426E569D9C9 [E32385ECE93DF2228FBEFE3113220A20] GoodName=Kirby 64 - The Crystal Shards (E) [f1] CRC=94593D97 846A278C RefMD5=A44B7A612964A6D6139D0426E569D9C9 [D33E4254336383A17FF4728360562ADA] GoodName=Kirby 64 - The Crystal Shards (U) [!] CRC=46039FB4 0337822C Players=4 SaveType=Eeprom 16KB Rumble=Yes [329C0A564D3B4477E2887097389AB7D6] GoodName=Kirby 64 - The Crystal Shards (U) [b1] CRC=80A2BBB5 828DFD3E RefMD5=D33E4254336383A17FF4728360562ADA [0CBA02D6EA55809A1E8D9BA02D199B7D] GoodName=Kirby 64 - The Crystal Shards (U) [b2] CRC=22F301B6 D0A03C3C RefMD5=D33E4254336383A17FF4728360562ADA [0A010DFFB20B9A4FB7BA2F962788F54F] GoodName=Kirby 64 - The Crystal Shards (U) [f1] CRC=D3F52BA5 1258EDFE RefMD5=D33E4254336383A17FF4728360562ADA [99F4652FEFF7373576ED440E1D33DB24] GoodName=Kirby 64 - The Crystal Shards (U) [t1] CRC=CBF72BBD 5D1587B2 RefMD5=D33E4254336383A17FF4728360562ADA [D31A94A5685A21A932CC886D64CC9B21] GoodName=Knife Edge - Nose Gunner (E) [!] CRC=4A997C74 E2087F99 Players=4 SaveType=None Rumble=Yes [436BA873E9466AAB237D9429348A5F70] GoodName=Knife Edge - Nose Gunner (J) [!] CRC=931AEF3F EF196B90 Players=4 SaveType=None Rumble=Yes [8043D829FCD4F8F72DD81E5C6DDE916F] GoodName=Knife Edge - Nose Gunner (U) [!] CRC=FCE0D799 65316C54 Players=4 SaveType=None Rumble=Yes [ABFDAA35C995C839D0773D3601D59E67] GoodName=Knife Edge - Nose Gunner (U) [b1][t1] CRC=84F5C897 A870AC11 RefMD5=8043D829FCD4F8F72DD81E5C6DDE916F [FCFBFD04A56400DE8B84297CF37CEE3D] GoodName=Knife Edge - Nose Gunner (U) [hI] CRC=84F5CF63 08EE7EDC RefMD5=8043D829FCD4F8F72DD81E5C6DDE916F [760110BC5733A4AC31EE680A06F4F2A1] GoodName=Knife Edge - Nose Gunner (U) [hI][t1] CRC=84F5C897 A870AC11 RefMD5=8043D829FCD4F8F72DD81E5C6DDE916F [2CA82F82284D2B3FE381999889350855] GoodName=Knife Edge - Nose Gunner (U) [t1] CRC=84F5C897 A870AC11 RefMD5=8043D829FCD4F8F72DD81E5C6DDE916F [E95D73FF55FBB63E79AA9EAB14608584] GoodName=Knockout Kings 2000 (E) [!] CRC=E3D6A795 2A1C5D3C Players=2 SaveType=None Mempak=Yes Rumble=Yes [008B473841CE4D9AC050D55F99B4B5D4] GoodName=Knockout Kings 2000 (U) [!] CRC=0894909C DAD4D82D Players=2 SaveType=None Mempak=Yes Rumble=Yes [630400D4E2DCED3DDE56DFCCF39A512A] GoodName=Knockout Kings 2000 (U) [f1] (PAL) CRC=8D6F5219 D43B163C RefMD5=008B473841CE4D9AC050D55F99B4B5D4 [C6B01C020FDFD2E5C037C5A330B161AD] GoodName=Kobe Bryant in NBA Courtside (E) [!] CRC=1739EFBA D0B43A68 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes [54FD2659FCCE58FCC6EE544F95F8F7A3] GoodName=Kobe Bryant in NBA Courtside (E) [f1] CRC=D03F0CCB 11F19CDD RefMD5=C6B01C020FDFD2E5C037C5A330B161AD [D37C79E4E4EABCB5DC6A07BD76688223] GoodName=Kobe Bryant's NBA Courtside (U) [!] CRC=616B8494 8A509210 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes [EF9A84FBF0B4C31E581648F256E8ED81] GoodName=Kobe Bryant's NBA Courtside (U) [f1] CRC=5BC51145 D3A29FE7 RefMD5=D37C79E4E4EABCB5DC6A07BD76688223 [AA0727F8F2B2C233F7BFD202194D41BC] GoodName=Kobe Bryant's NBA Courtside (U) [h1C] CRC=616B8494 8A509210 RefMD5=D37C79E4E4EABCB5DC6A07BD76688223 [3E2AD600BD89B21531F59A84839FE732] GoodName=Kuru Kuru Fever (Aleck64) CRC=4248BA87 99BE605D SaveType=Eeprom 4KB [6B53B94B64DD8ACAE1B43BDA2CAF23FC] GoodName=Kyojin no Doshin 1 (J) [CART HACK] CRC=0837F87A D1436FF8 [73FFACDB7F649154984A5957ED451257] GoodName=Kyojin no Doshin 1 (J) (Kiosk Demo) [CART HACK] CRC=E7BDA0BE ADA09CAC [C57C4DD678748C6ED7CBF498445DE247] GoodName=Kyojin no Doshin: Kaihou Sensen Chibikko Chikko Daishuugou (J) [CART HACK] CRC=8C47CE8B 06019FEF Players=1 Rumble=Yes [28803DC0D1CD120E5C0285F7291626B8] GoodName=LCARS Demo by WT Riker (PD) CRC=F828DF21 C5E83F66 [E7432C73FE47991B52EB4A44156A8D9D] GoodName=LCARS Demo by WT Riker (PD) [b1] CRC=F828DF21 C5E83F66 RefMD5=28803DC0D1CD120E5C0285F7291626B8 [6310C7173385ED2B06020F3B90158E9E] GoodName=LEGO Racers (E) (M10) [!] CRC=F478D8B3 9716DD6D Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=3 [26B5EAA13DC5B5E35307FE8C0CF5B6BA] GoodName=LEGO Racers (U) (M10) [!] CRC=096A40EA 8ABE0A10 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=3 [97C4CAE584F427EC44266E9B98FBF7B6] GoodName=LEGO Racers (U) (M10) [b1] CRC=096A40EA 8ABE0A10 RefMD5=26B5EAA13DC5B5E35307FE8C0CF5B6BA [E74404ED5A7076855CDE3832474751B6] GoodName=LEGO Racers (U) (M10) [b1][f1] (PAL) CRC=BB53C809 269594C6 RefMD5=26B5EAA13DC5B5E35307FE8C0CF5B6BA [1221C67C46C77487D35F03D3D13A3022] GoodName=LEGO Racers (U) (M10) [b1][t1] CRC=B0AC4321 3F4DA1AF RefMD5=26B5EAA13DC5B5E35307FE8C0CF5B6BA [050531139C082E35B101E0929B6E07EA] GoodName=LaC's MOD Player - The Temple Gates (PD) CRC=8E97A4A6 D1F31B33 Status=3 SaveType=None Players=0 Rumble=No [9602768EA88F4F5B53237E1AA20DE68A] GoodName=LaC's Universal Bootemu V1.0 (PD) CRC=EF623F50 ECBB509B [EB712F2E8A6A893141B82607B11DA8A2] GoodName=LaC's Universal Bootemu V1.1 (PD) CRC=BB752DA7 30D8BEF4 [15C2C37D4FFA1E2C5BC4D1029BC225AC] GoodName=LaC's Universal Bootemu V1.2 (PD) CRC=FF0AC362 F4EC09B3 [EB11FC0797AE1107201C4601FEE5471A] GoodName=Last Legion UX (J) [!] CRC=7F304099 52CF5276 Players=2 Rumble=Yes [8E55FD6990472A08568324309C2FD31F] GoodName=Last Legion UX (J) [a1] CRC=7F304099 52CF5276 RefMD5=EB11FC0797AE1107201C4601FEE5471A [7B5988138A8ADCA592DE616260B2700D] GoodName=Last Legion UX (J) [b1] CRC=7F304099 52CF5276 RefMD5=EB11FC0797AE1107201C4601FEE5471A [F8D705AD5EFF0DB9E3E17A7ECB6D2123] GoodName=Last Legion UX (J) [b2] CRC=7F304099 52CF5276 RefMD5=EB11FC0797AE1107201C4601FEE5471A [0C13E0449A28EA5B925CDB8AF8D29768] GoodName=Zelda no Densetsu - Toki no Ocarina - Zelda Collection Version (J) (GC) [!] CRC=F7F52DB8 2195E636 SaveType=SRAM Status=4 Rumble=Yes Players=1 ; End Credits Fix Cheat0=D109A814 0320,8109A814 0000,D109A816 F809,8109A816 0000 [33FB7852C180B18EA0B9620B630F413F] GoodName=Zelda no Densetsu - Toki no Ocarina GC (J) (GC) [!] CRC=F611F4BA C584135C SaveType=SRAM Status=4 Rumble=Yes Players=1 ; End Credits Fix Cheat0=D109A834 0320,8109A834 0000,D109A836 F809,8109A836 0000 [69895C5C78442260F6EAFB2506DC482A] GoodName=Zelda no Densetsu - Toki no Ocarina GC URA (J) (GC) [!] CRC=F43B45BA 2F0E9B6F SaveType=SRAM Status=4 Rumble=Yes Players=1 ; End Credits Fix Cheat0=D109A814 0320,8109A814 0000,D109A816 F809,8109A816 0000 [13FAB67E603B002CEAF0EEA84130E973] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [!] CRC=E97955C6 BC338D38 SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [5798E844953662880C5EB4134F886909] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [T+Ita1.0Beta_Vampire] CRC=E97955C6 BC338D38 RefMD5=13FAB67E603B002CEAF0EEA84130E973 [36759C85694A4CF5A1F089A4136DAE2B] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [T-Ita0.9M_Vampire] CRC=E97955C6 BC338D38 RefMD5=13FAB67E603B002CEAF0EEA84130E973 [6CBAC6E5B13A4A92347488DE1C806BC0] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [T-Ita0.9P1+G_Vampire] CRC=E97955C6 BC338D38 RefMD5=13FAB67E603B002CEAF0EEA84130E973 [44494CD5D6E3332F79465DE51C2EC636] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [T-Ita0.9Z3_Vampire] CRC=E97955C6 BC338D38 RefMD5=13FAB67E603B002CEAF0EEA84130E973 [585AA96CBB44DF3BBB3B294538B0605A] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [T-Ita0.9e_Vampire] CRC=E97955C6 BC338D38 RefMD5=13FAB67E603B002CEAF0EEA84130E973 [5FD0F1EE3F6E0C1E0BA9A91ED797A8B9] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [T-Ita0.9f_Vampire] CRC=E97955C6 BC338D38 RefMD5=13FAB67E603B002CEAF0EEA84130E973 [035239281994E1E254D7AFC79F5570FB] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.0) [f1] CRC=E7428718 97751A86 RefMD5=13FAB67E603B002CEAF0EEA84130E973 [BECCFDED43A2F159D03555027462A950] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.1) [!] CRC=0A5D8F83 98C5371A SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [71FBAE5D2B27926EA54E92CE2FC91622] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.1) (Debug Version) CRC=9FC385E5 3ECC05C7 RefMD5=BECCFDED43A2F159D03555027462A950 [609B47B79DA21F3DF9B31D06C95C09A1] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (VC) [!] CRC=0A5D8F83 98C5371A SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [6DC88503DF78FE4FAA16BCF7AEC4D1E7] GoodName=Legend of Zelda, The - Majora's Mask (E) (M4) (V1.1) [T+Ita1.0Beta_Vampire] CRC=0A5D8F83 98C5371A RefMD5=BECCFDED43A2F159D03555027462A950 [2A0A8ACB61538235BC1094D297FB6556] GoodName=Legend of Zelda, The - Majora's Mask (U) [!] CRC=5354631C 03A2DEF0 SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [A9BA7523591C975AC00309ED516FD248] GoodName=Legend of Zelda, The - Majora's Mask (U) [T+Ita2.0_Rulesless] CRC=5242DFBC 2FDE6D42 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [9C7D1B51ECBC9AC333D00273F96758B1] GoodName=Legend of Zelda, The - Majora's Mask (U) [T+Pol1.0] CRC=5354631C 03A2DEF0 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [B90B728E0643ABC582793B451444733E] GoodName=Legend of Zelda, The - Majora's Mask (U) [T+Rus0.85_Alex] CRC=5354631C 03A2DEF0 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [04150A63D1574673BEAB036E4EB5A249] GoodName=Legend of Zelda, The - Majora's Mask (U) [T+RusPreAlpha_Alex&gottax] CRC=5354631C 03A2DEF0 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [5D5DD380115ABF43958A710C7B597771] GoodName=Legend of Zelda, The - Majora's Mask (U) [T-Rus0.1_Alex] CRC=5354631C 03A2DEF0 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [7863ED3EE54F72BD59CF970C5C402FA2] GoodName=Legend of Zelda, The - Majora's Mask (U) [T-Rus0.2_Alex] CRC=5354631C 03A2DEF0 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [E684C672C2BF64717A10F1D104108998] GoodName=Legend of Zelda, The - Majora's Mask (U) [T-Rus0.36Alex] CRC=5354631C 03A2DEF0 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [BD26BC90750D6388972C7E29441039DF] GoodName=Legend of Zelda, The - Majora's Mask (U) [T-Rus0.50_Alex] CRC=5354631C 03A2DEF0 RefMD5=2A0A8ACB61538235BC1094D297FB6556 [3DF7F2AF3E7B1F2FD55C2C02125F0130] GoodName=Legend of Zelda, The - Majora's Mask (U) [f1] CRC=696F2896 764F6D3F RefMD5=2A0A8ACB61538235BC1094D297FB6556 [8F281800FBA5DDCB1D2B377731FC0215] GoodName=Legend of Zelda, The - Majora's Mask - Preview Demo (U) [!] CRC=BF799345 39FF7A02 [AC0751DBC23AB2EC0C3144203ACA0003] GoodName=Legend of Zelda, The - Majora's Mask (U) (GC) CRC=B443EB08 4DB31193 SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [DBE9AF0DB46256E42B5C67902B696549] GoodName=Legend of Zelda, The - Majora's Mask - Collector's Edition (E) (M4) (GC) [!] CRC=6AECEC4F F0924814 SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [9F04C8E68534B870F707C247FA4B50FC] GoodName=Zelda no Densetsu - Toki no Ocarina (J) (V1.0) [!] CRC=EC7011B7 7616D72B SaveType=SRAM Status=4 Rumble=Yes Players=1 [A04EBD753276C52E95E25AF7683DA32D] GoodName=Zelda no Densetsu - Toki no Ocarina (J) (V1.0) [T+Chi.02_madcell] CRC=EC7011B7 7616D72B RefMD5=9F04C8E68534B870F707C247FA4B50FC [D48CFE3FBF77D5335731509BFDE10D47] GoodName=Zelda no Densetsu - Toki no Ocarina (J) (V1.0) [T+Chi] CRC=EC7011B7 7616D72B RefMD5=9F04C8E68534B870F707C247FA4B50FC [BF0622C4C479E8FF5983DB3786F84293] GoodName=Zelda no Densetsu - Toki no Ocarina (J) (V1.0) [f1] CRC=9FD0987D 7EAE10D8 RefMD5=9F04C8E68534B870F707C247FA4B50FC [1BF5F42B98C3E97948F01155F12E2D88] GoodName=Zelda no Densetsu - Toki no Ocarina (J) (V1.1) [!] CRC=D43DA81F 021E1E19 SaveType=SRAM Status=4 Rumble=Yes Players=1 [2258052847BDD056C8406A9EF6427F13] GoodName=Zelda no Densetsu - Toki no Ocarina (J) (V1.2) [!] CRC=693BA2AE B7F14E9F RefMD5=1BF5F42B98C3E97948F01155F12E2D88 [E040DE91A74B61E3201DB0E2323F768A] GoodName=Legend of Zelda, The - Ocarina of Time (E) (M3) (V1.0) [!] CRC=B044B569 373C1985 Status=4 Players=1 SaveType=SRAM Rumble=Yes [2B60EF777F759B4F0E19DDF3CB84D9AB] GoodName=Legend of Zelda, The - Ocarina of Time (E) (M3) (V1.0) [b1] CRC=B044B569 373C1985 RefMD5=E040DE91A74B61E3201DB0E2323F768A [20C68EAFDFCB1BA98B495E5BEED5E4B6] GoodName=Legend of Zelda, The - Ocarina of Time (E) (M3) (V1.0) [f1] (zpfc) CRC=EEE48FAF 6A92BAFF RefMD5=E040DE91A74B61E3201DB0E2323F768A [175EDAB7F1A3DFBB5D23C4AA1B9D647E] GoodName=Legend of Zelda, The - Ocarina of Time (E) (M3) (V1.0) [f2] (zpc1) CRC=96961E83 B5DE0894 RefMD5=E040DE91A74B61E3201DB0E2323F768A [D714580DD74C2C033F5E1B6DC0AEAC77] GoodName=Legend of Zelda, The - Ocarina of Time (E) (M3) (V1.1) [!] CRC=B2055FBD 0BAB4E0C Status=4 Players=1 SaveType=SRAM Rumble=Yes [5BD1FE107BF8106B2AB6650ABECD54D6] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [!] CRC=EC7011B7 7616D72B Status=4 SaveType=SRAM Players=1 Rumble=Yes [A43A350385FA814EC9793B7ACD9E18F4] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) (Room121 Hack) CRC=EBE8AA17 B1EF65E6 [640B928AD387B271094F64B9B93ABBFC] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Dut] CRC=C7C3086D 93826E6E RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [6B3DB6AAA348F5721AFAF892E9B274DE] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Ita100] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [48CA89956120E0522D4B6B7E2810D04C] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Pol1.3] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [77BF20D3ECA19EBCFC5FED35F5CF65DC] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Por1.0] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [7FD3BA9B095C244367E84A6E4493349B] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Por1.5BetaFinal] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [7037DF7E0050A6D8B9B338C774A1CEB0] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Rus1.0beta2_Sergey Anton] CRC=F8B1C7C7 1EFCA431 RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [B0BB6CAB395C93C966F1CA485FC1BFBC] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Rus101b2] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [10A2E08708E25195E063D2E05231AB66] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Spa01b_toruzz] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [BBCCE848679F3D0722CBA622505FB206] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Spa097b2] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [51778E50CE70466796F8D51C686224C4] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Spa1.0] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [44E6921A257E913977088B9B6BA9D25B] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Spa2.0_eduardo_a2j] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [86A9550AD8CDDACA13813765045A00EE] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T+Spa2.2_eduardo_a2j] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [AAEB5ACA09291E8F5FEDFA1F576D9F0A] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Pol1.2] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [1746D1CC38C42F08F0CD12D170C046B8] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.09] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [0D6331C2FA062F20272CC1A7F80F7271] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.14] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [FF7C6D9909D36D3A11D4C9052EAFB2E8] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.22] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [D4718E7EA75847646025D07626A1DF69] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.26] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [E784353B07DAFCB66690193B03CC3E1F] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.28] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [E6A5B9A18BB8D0508FBB703EB90703B7] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.30] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [79BE4EEEB2DD94E542516DFC189B099E] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.33] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [65AC7755CB41E937A1DC5C58902A4222] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.35] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [7B3AD8B6FE2D8F0602ED1006FD673970] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.37] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [F85FC5CE4451C1E9F3EE00B814489A51] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Por.42] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [92AED3D84A1AA0082B128E2CFD84C4AA] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Rus.01] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [5DF98AE5EAC2797555587D3391222FE4] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Rus.06] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [A1F18DE7D5570A502C7C93B7BF27E868] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Rus.82] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [A5A8A0249E14A052227B3ED71A98F0B4] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Rus099bfix] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [3FE076D5992C53DE6E095E53E53D9BC5] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Rus099wip] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [40F4A3A5FE703527E03C5747BC0A2FD6] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [T-Spa1.0_eduardo] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [EE38A903556C24520CD162FD046748A2] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [b1] CRC=EC7011B7 7616D72B RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [8C1348872D9AC31FF9D22C07D7186CCB] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [f1] CRC=9FD0987D 7EAE10D8 RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [DB2D737DE0F117D419B3A48442B6DB22] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [f2] CRC=9FD0987D 7EAE10D8 RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [4472B1F6B9D594B6361DFA396F8CFB2C] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.0) [f3] CRC=9FD0987D 7EAE10D8 RefMD5=5BD1FE107BF8106B2AB6650ABECD54D6 [721FDCC6F5F34BE55C43A807F2A16AF4] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [!] CRC=D43DA81F 021E1E19 Status=4 SaveType=SRAM Players=1 Rumble=Yes [92C842FC8CF706FF290044D40A64D346] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [T+Ita100] CRC=D43DA81F 021E1E19 RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [F5B33DC7DC76BB308801CB518B1515F3] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [T+Por1.0] CRC=D43DA81F 021E1E19 RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [C949E4929A001B339DAE000A3DA9E0A8] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [T+Por100%] CRC=D43DA81F 021E1E19 RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [53E09E6B72F114440B389FA8549E8F97] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [T+Spa01b_toruzz] CRC=D43DA81F 021E1E19 RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [EA4FA94072849F88CAC96E60C1EDD41D] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [T-Spa1.0_eduardo] CRC=D43DA81F 021E1E19 RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [B3E1D1B92626BA86E5BDF0F18409A25B] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [T-Spa1.0_eduardo][b1] CRC=D43DA81F 021E1E19 RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [468F7EAA4B94B831AEED8B83C062B5CB] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [b1] CRC=D43DA81F 021E1E19 RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [DD824A8E1A6778FA5229433109AFAEFF] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.1) [b2] CRC=CF8EC901 7EC2C48D RefMD5=721FDCC6F5F34BE55C43A807F2A16AF4 [57A9719AD547C516342E1A15D5C28C3D] GoodName=Legend of Zelda, The - Ocarina of Time (U) (V1.2) [!] CRC=693BA2AE B7F14E9F Players=1 SaveType=SRAM Rumble=Yes [CD09029EDCFB7C097AC01986A0F83D3F] GoodName=Legend of Zelda, The - Ocarina of Time (U) (GC) [!] CRC=F3DD35BA 4152E075 Status=4 Players=1 SaveType=SRAM Rumble=Yes ; End Credits Fix Cheat0=D109A814 0320,8109A814 0000,D109A816 F809,8109A816 0000 [2C27B4E000E85FD78DBCA551F1B1C965] GoodName=Legend of Zelda, The - Ocarina of Time (E) (GC) [!] CRC=09465AC3 F8CB501B Status=4 Players=1 SaveType=SRAM Rumble=Yes ; End Credits Fix Cheat0=D109A8E4 0320,8109A8E4 0000,D109A8E6 F809,8109A8E6 0000 [77314FE3C3EDD472D0554C12FEDB38F4] GoodName=Legend of Zelda, The - Ocarina of Time (E) (GC) [f1] CRC=A3271D83 05B533A5 RefMD5=2C27B4E000E85FD78DBCA551F1B1C965 [1618403427E4344A57833043DB5CE3C3] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (E) (GC) [!] CRC=1D4136F3 AF63EEA9 Status=4 Players=1 SaveType=SRAM Rumble=Yes ; End Credits Fix Cheat0=D109A8C4 0320,8109A8C4 0000,D109A8C6 F809,8109A8C6 0000 [BC2ECBE96B04EDC56B08347DF7C7FECD] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (E) (GC) [T+Ita70%_Rulesless] CRC=1D4136F3 AF63EEA9 RefMD5=1618403427E4344A57833043DB5CE3C3 [83673D0A0EF4705C624043788EBF11EE] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (E) (GC) [T+Pol1.0] CRC=1D4136F3 AF63EEA9 RefMD5=1618403427E4344A57833043DB5CE3C3 [A34093AC2B038A92CCF525CAB4CE346E] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (E) (GC) [f1] (NTSC) CRC=27A3831D B505A533 RefMD5=1618403427E4344A57833043DB5CE3C3 [2DE4D0F0788871CC4BB6D30B60F72184] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (E) (GC) [h1C] CRC=1D4136F3 AF63EEA9 RefMD5=1618403427E4344A57833043DB5CE3C3 [DA35577FE54579F6A266931CC75F512D] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (U) (GC) [!] CRC=F034001A AE47ED06 Status=4 Players=1 SaveType=SRAM Rumble=Yes ; End Credits Fix Cheat0=D109A7F4 0320,8109A7F4 0000,D109A7F6 F809,8109A7F6 0000 [26A1616667EEC82288534C47B6927D45] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (U) (Debug Version) [f1] CRC=917D1B16 831F9BE1 RefMD5=DA35577FE54579F6A266931CC75F512D [8AD8D24EA38B68DFAB154C2585FB550C] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (U) (Debug Version) [f2] CRC=917D18F6 69BC5453 RefMD5=DA35577FE54579F6A266931CC75F512D [8CA71E87DE4CE5E9F6EC916202A623E9] GoodName=Legend of Zelda, The - Ocarina of Time - Master Quest (U) (Debug Version) CRC=917D18F6 69BC5453 RefMD5=DA35577FE54579F6A266931CC75F512D [0AB48B2D44A74B3BB2D384F6170C2742] GoodName=Legend of Zelda, The - Ocarina of Time (Ch) (iQue) [!] CRC=B1E1E07B 051269DD Players=1 [9729A68F40F197D4D040FA641FF099E7] GoodName=Legend of Zelda, The - Ocarina of Time (Ch) (V2) (iQue) (Manual) [!] [912628118E67FEA670ED2C63F7A7B003] GoodName=Legend of Zelda, The - Ocarina of Time (Ch) (V4) (iQue) (Manual) [!] [A475E9F8615513666A265C464708AE8F] GoodName=Legend of Zelda, The - Ocarina of Time (Ch) (Traditional) (iQue) [!] CRC=3D81FB3E BD843E34 Players=1 [55685D6324EFDE5BC9D26C98706B0B8A] GoodName=Les Razmoket - La Chasse Aux Tresors (F) [!] CRC=2B696CB4 7B93DCD8 Players=4 Rumble=Yes [AEE5016E6D60D12AD768E9F6D10ADDE8] GoodName=Let's Smash Tennis (J) [!] CRC=3D67C62B 31D03150 Players=4 Mempak=Yes [EF878DFACF5CD5C00BA3297B0DC888D2] GoodName=Light Force First N64 Demo by Fractal (PD) CRC=7D292963 D5277C1F [9656C4A5251F054704E35134006CFFC7] GoodName=Liner V1.00 by Colin Phillipps of Memir (PD) CRC=8A8E474B 6458BF2B Status=1 SaveType=None Players=4 [AF701EE852ECD13F5F9F3284EBE60561] GoodName=Liner V1.00 by Colin Phillipps of Memir (PD) [b1] CRC=8A8E474B 6458BF2B RefMD5=9656C4A5251F054704E35134006CFFC7 [500AFE6D6732E0888D108410D135B78E] GoodName=Liner V1.00 by Colin Phillipps of Memir (PD) [b2] CRC=8A8E474B 6458BF2B RefMD5=9656C4A5251F054704E35134006CFFC7 [99380A8ED84C89E54DE53E0B1FB423C9] GoodName=Liner V1.02 by Colin Phillipps of Memir (PD) CRC=F7B1C8E8 70536D3E Status=1 SaveType=None Players=4 [E62F4FDCC82C244BA9709E40756D9B62] GoodName=Lode Runner 3-D (E) (M5) [!] CRC=60460680 305F0E72 Players=1 SaveType=Eeprom 4KB Rumble=Yes Status=3 [6B1E294A9199E6F22DBC6ABC59BD7568] GoodName=Lode Runner 3-D (E) (M5) [b1] CRC=E378B28A 0CA18BCC RefMD5=E62F4FDCC82C244BA9709E40756D9B62 [D2BD8DD8C3BE1E8F0B8AE49206DBD7E5] GoodName=Lode Runner 3-D (J) [!] CRC=964ADD0B B29213DB Players=1 SaveType=Eeprom 4KB Rumble=Yes Status=3 [D038813541589F0B3F1F900F4FD22C9B] GoodName=Lode Runner 3-D (U) [!] CRC=255018DF 57D6AE3A Players=1 SaveType=Eeprom 4KB Rumble=Yes Status=3 [5FBA92D908B9962F26D389C85F6E88CF] GoodName=Lode Runner 3-D (U) [b1][f1] (PAL) CRC=275A4533 ACD94796 RefMD5=D038813541589F0B3F1F900F4FD22C9B [3F5CA81183EA0E69F35417F6BBD7C5AC] GoodName=Lode Runner 3-D (U) [f1] (PAL) CRC=275A4533 ACD94796 RefMD5=D038813541589F0B3F1F900F4FD22C9B [789482B7931419FCE7FC2472026E1C65] GoodName=Lode Runner 3-D (U) [t1] CRC=BD13F636 02079573 RefMD5=D038813541589F0B3F1F900F4FD22C9B [1408FCF68B60D845F090107EF355A7E5] GoodName=Looney Tunes - Duck Dodgers (E) (M6) [!] CRC=0AA0055B 7637DF65 Players=1 SaveType=Eeprom 4KB Rumble=Yes [4CCFF861AD2CFD65CC660F496C1D1664] GoodName=Lt. Duck Dodgers (Prototype) CRC=FBB9F1FA 6BF88689 Players=1 Rumble=Yes CountPerOp=1 [7A99628EDF0A6602D0C408F31B701435] GoodName=Lylat Wars (A) (M3) [!] CRC=2483F22B 136E025E Players=4 SaveType=Eeprom 4KB Rumble=Yes [B182BBBC8CE22BD3F44BB6ED91F6ACD4] GoodName=Lylat Wars (A) (M3) [f1] CRC=2483F22B 136E025E RefMD5=7A99628EDF0A6602D0C408F31B701435 [1E03884F7017230E96F741085E5817F8] GoodName=Lylat Wars (A) (M3) [t1] (Boost) CRC=AF13E2C2 2D502822 RefMD5=7A99628EDF0A6602D0C408F31B701435 [A2957C46E62CEC7B10EDE4547F70425F] GoodName=Lylat Wars (A) (M3) [t2] (No Damage-Unbreakable Wings) CRC=8B31F4AD F366CBFA RefMD5=7A99628EDF0A6602D0C408F31B701435 [884CCCA35CBEEDB8ED288326F9662100] GoodName=Lylat Wars (E) (M3) [!] CRC=F4CBE92C B392ED12 Players=4 SaveType=Eeprom 4KB Rumble=Yes [F0FF28B0D26CDEFC11F22FE73148A6DC] GoodName=Lylat Wars (E) (M3) [f1] CRC=F4CBE92C B392ED12 RefMD5=884CCCA35CBEEDB8ED288326F9662100 [37F7F2F2CFB488E48A2706FC8C4B2DD5] GoodName=Lylat Wars (E) (M3) [f1][h1C] CRC=F4CBE92C B392ED12 RefMD5=884CCCA35CBEEDB8ED288326F9662100 [499013DA36AD50C94B2CE6B794CC9983] GoodName=Lylat Wars (E) (M3) [f2] (NTSC) CRC=F667DC04 86510A81 RefMD5=884CCCA35CBEEDB8ED288326F9662100 [12F0671C66D25622C4C9CD71C678A1F6] GoodName=Lylat Wars (E) (M3) [t1] (Boost) CRC=834C19FF 8A93F7D4 RefMD5=884CCCA35CBEEDB8ED288326F9662100 [281E754123EC0CC688C4AA7C853DE303] GoodName=Lylat Wars (E) (M3) [t2] (No Damage-Unbreakable Wings) CRC=58B5EA62 27177133 RefMD5=884CCCA35CBEEDB8ED288326F9662100 [41FE06C68915666E5F8FEF81B8FFF59F] GoodName=MAME 64 Beta 3 (PD) CRC=D5CA46C2 F8555155 [3803F70982907C7C24713A7F9742B6CD] GoodName=MAME 64 Demo (PD) [b1] CRC=9CCE5B1D 6351E283 [0E2516C65B94214C891B2D07C3D92AEC] GoodName=MAME 64 Demo (PD) [b2] CRC=9CCE5B1D 6351E283 [42AC30399688F98E58BE6AD1D2217E56] GoodName=MAME 64 Demo (PD) CRC=9CCE5B1D 6351E283 [C9319D97DABE9E842401433A27E00DAC] GoodName=MAME 64 V1.0 (PD) [b1] CRC=9CCE5B1D 6351E283 [6591A5FCFFF8879382C966906C3186E0] GoodName=MAME 64 V1.0 (PD) CRC=9CCE5B1D 6351E283 [D63FAF99E7876C39A9ACA2659596342F] GoodName=MMR by Count0 (PD) [b1] CRC=9E6581AB 57CC8CED [65B71F404DC3CF9A135D3229FFEA3C15] GoodName=MMR by Count0 (PD) CRC=9E6581AB 57CC8CED [9C6CF9D3CB5852439DE4EF4A399253B9] GoodName=Mini Racers (U) (Prototype) CRC=21548CA9 9059F32C [0054B7FC0C2ACBED650EFE727CDBA472] GoodName=MRC - Multi Racing Championship (E) (M3) [!] CRC=B8F0BD03 4479189E Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [362D10C7D270AE48D83D1D7BB78BF527] GoodName=MRC - Multi Racing Championship (E) (M3) [b1] CRC=B8F0BD03 4479189E RefMD5=0054B7FC0C2ACBED650EFE727CDBA472 [25E39A8B45FDDFA1989CE6662F87EF23] GoodName=MRC - Multi Racing Championship (E) (M3) [b2] CRC=B8F0BD03 4479189E RefMD5=0054B7FC0C2ACBED650EFE727CDBA472 [F5723C4CCFB9A1CE28426962D59CC85F] GoodName=MRC - Multi Racing Championship (E) (M3) [b3] CRC=B8F0BD03 4479189E RefMD5=0054B7FC0C2ACBED650EFE727CDBA472 [FEA06F46F61DEB721CF905C785299994] GoodName=MRC - Multi Racing Championship (E) (M3) [h1C] CRC=B8F0BD03 4479189E RefMD5=0054B7FC0C2ACBED650EFE727CDBA472 [74904F302A25620D7F63C0CB5333D464] GoodName=MRC - Multi Racing Championship (E) (M3) [o1] CRC=B8F0BD03 4479189E RefMD5=0054B7FC0C2ACBED650EFE727CDBA472 [8E18064A2C4B3EC15A20C3D676644B3A] GoodName=MRC - Multi Racing Championship (J) [!] CRC=A6B6B413 15D113CC Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [C306C80A07743F75B0C69AF2B484E957] GoodName=MRC - Multi Racing Championship (J) [b1] CRC=A6B6B413 15D113CC RefMD5=8E18064A2C4B3EC15A20C3D676644B3A [CBA2CCCD3C3772B96CDA7128090C1FD7] GoodName=MRC - Multi Racing Championship (J) [b2] CRC=A6B6B413 15D113CC RefMD5=8E18064A2C4B3EC15A20C3D676644B3A [8F33FE36837198B3F21CC1F37FC67CC8] GoodName=MRC - Multi Racing Championship (J) [b3] CRC=A6B6B413 15D113CC RefMD5=8E18064A2C4B3EC15A20C3D676644B3A [6073174A8DA1305CF91B59369FAEFDDF] GoodName=MRC - Multi Racing Championship (J) [b4] CRC=A6B6B413 15D113CC RefMD5=8E18064A2C4B3EC15A20C3D676644B3A [BB82ADC51562F8CDDCDF4F6FAD2479BA] GoodName=MRC - Multi Racing Championship (J) [b5] CRC=A6B6B413 15D113CC RefMD5=8E18064A2C4B3EC15A20C3D676644B3A [FC61D60F2C6FE4610F70CE4949A7A062] GoodName=MRC - Multi Racing Championship (U) [!] CRC=2AF9B65C 85E2A2D7 Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [E38F1DAE2A2023A529B47A26E4666759] GoodName=MRC - Multi Racing Championship (U) [b1] CRC=2AF9B65C 85E2A2D7 RefMD5=FC61D60F2C6FE4610F70CE4949A7A062 [535995506105D0EABA796E371660CBF2] GoodName=MRC - Multi Racing Championship (U) [b2] CRC=2AF9B65C 85E2A2D7 RefMD5=FC61D60F2C6FE4610F70CE4949A7A062 [7E8F028411746CF816848384B788B624] GoodName=MRC - Multi Racing Championship (U) [b3] CRC=2AF9B65C 85E2A2D7 RefMD5=FC61D60F2C6FE4610F70CE4949A7A062 [677356691E55A9061772585CDDFD7F76] GoodName=MRC - Multi Racing Championship (U) [o1] CRC=2AF9B65C 85E2A2D7 RefMD5=FC61D60F2C6FE4610F70CE4949A7A062 [72F324B7E115618771C506AF3F604F8F] GoodName=MSFTUG Intro #1 by LaC (PD) CRC=94D3D5CB E8808606 [523883A766C662E8377CD256755B27B4] GoodName=Mace - The Dark Age (E) [!] CRC=1145443D 11610EDB Players=2 SaveType=None [9CF16783687686C8FE2ABE0B71316C3D] GoodName=Mace - The Dark Age (E) [b1] CRC=1145443D 11610EDB RefMD5=523883A766C662E8377CD256755B27B4 [2249D931B5D2D4544EEB75E5B4136709] GoodName=Mace - The Dark Age (E) [b2] CRC=1145443D 11610EDB RefMD5=523883A766C662E8377CD256755B27B4 [87BD533084ACB4DC6C3E01B32F26357C] GoodName=Mace - The Dark Age (E) [o1] CRC=1145443D 11610EDB RefMD5=523883A766C662E8377CD256755B27B4 [8E2B951678785DB1F54A31F778BFA491] GoodName=Mace - The Dark Age (E) [o2] CRC=1145443D 11610EDB RefMD5=523883A766C662E8377CD256755B27B4 [39A2BCA1C17CD4CF1A9F3AE2B725B5C6] GoodName=Mace - The Dark Age (U) [!] CRC=6B700750 29D621FE Players=2 SaveType=None [DF342B032ED1ED15C24448EC6BE9F34E] GoodName=Mace - The Dark Age (U) [b1] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [57CB2D2F6C87F520016AACF7E2785222] GoodName=Mace - The Dark Age (U) [b2] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [D1CE0FA3D46CA27F1C15E782ACEC49DA] GoodName=Mace - The Dark Age (U) [b3] CRC=022E6456 75BBB3C7 RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [243F8C4067D50D994C1E883968DE8C61] GoodName=Mace - The Dark Age (U) [b4] CRC=022E6456 75BBB3C7 RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [88B638825A16E46837FB521EDA328C5A] GoodName=Mace - The Dark Age (U) [b5] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [62A0CE9A58273811E34CC73BE8E6F8C4] GoodName=Mace - The Dark Age (U) [b6] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [B96ABFBD746BC25243D607613297D769] GoodName=Mace - The Dark Age (U) [b7] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [1D4BD885DB0C0C5365698526077E10F4] GoodName=Mace - The Dark Age (U) [b8] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [1C897EC059C6C34C8ED57E1965410F2E] GoodName=Mace - The Dark Age (U) [b9] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [64D508C5E0F1050048BE429E20EF4B07] GoodName=Mace - The Dark Age (U) [o1] CRC=6B700750 29D621FE RefMD5=39A2BCA1C17CD4CF1A9F3AE2B725B5C6 [67C96076459EB5F71733F39D7FCC76A3] GoodName=Madden Football 64 (E) [!] CRC=A197CB52 7520DE0E SaveType=None Players=4 Mempak=Yes Rumble=Yes [5CBF54627693F800524038127BBF46BF] GoodName=Madden Football 64 (E) [b1] CRC=A197CB52 7520DE0E RefMD5=67C96076459EB5F71733F39D7FCC76A3 [903B912CE88626900221731224E9DBE8] GoodName=Madden Football 64 (U) [!] CRC=13836389 265B3C76 SaveType=None Players=4 Mempak=Yes Rumble=Yes [5CA2A7F712B6C5737D0B46E67C8DDA44] GoodName=Madden Football 64 (U) [b1] CRC=13836389 265B3C76 RefMD5=903B912CE88626900221731224E9DBE8 [9AE941A12974B7B56CFA8B5EA1E670D7] GoodName=Madden Football 64 (U) [b2] CRC=13836389 265B3C76 RefMD5=903B912CE88626900221731224E9DBE8 [CA7161F298DF38BC8182B21BB754DB4B] GoodName=Madden Football 64 (U) [h1C] CRC=13836389 265B3C76 RefMD5=903B912CE88626900221731224E9DBE8 [732167D19C627CAF7384C780C64AB80A] GoodName=Madden Football 64 (U) [o1] CRC=13836389 265B3C76 RefMD5=903B912CE88626900221731224E9DBE8 [E979BF2E2B43CCB5E2E0A2798AD7770C] GoodName=Madden Football 64 (U) [o1][h1C] CRC=13836389 265B3C76 RefMD5=903B912CE88626900221731224E9DBE8 [0966CB688D6A5F1B22B4FAB5A393C0E2] GoodName=Madden Football 64 (U) [o2] CRC=13836389 265B3C76 RefMD5=903B912CE88626900221731224E9DBE8 [DB24A5DBA68F21D4513A37F7A7B0CF60] GoodName=Madden Football 64 (U) [o3] CRC=13836389 265B3C76 RefMD5=903B912CE88626900221731224E9DBE8 [955D19E26B4BA7CC941F86A54A0FC13D] GoodName=Madden NFL 2000 (U) [!] CRC=0CB81686 5FD85A81 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [441FA65FAA5C12339F89A0BB7DB43C8F] GoodName=Madden NFL 2001 (U) [!] CRC=EB38F792 190EA246 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [AD0F2EC565D7575FB37512BC8DF8A092] GoodName=Madden NFL 2002 (U) [!] CRC=D7134F8D C11A00B5 SaveType=None Mempak=Yes Rumble=Yes Players=4 CountPerOp=1 [E7BF80861A0AB2A788959463D953B5D5] GoodName=Madden NFL 99 (E) [!] CRC=3925D625 8C83C75E Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [9CB5F5CD6AB141454D645C92FD9BF67C] GoodName=Madden NFL 99 (E) [h1C] CRC=3925D625 8C83C75E RefMD5=E7BF80861A0AB2A788959463D953B5D5 [507CEAB72EF2A1BF145BF190F5CE1C80] GoodName=Madden NFL 99 (U) [!] CRC=DEB78BBA 52F6BD9D Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [C049FCD4CB185A553D8122CFE6C30139] GoodName=Madden NFL 99 (U) [o1] CRC=DEB78BBA 52F6BD9D RefMD5=507CEAB72EF2A1BF145BF190F5CE1C80 [5AD80A8EF44DEE1FDC456D66104165B4] GoodName=Madden NFL 99 (U) (V1.1) [!] CRC=DF09D625 1791C87D Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [5F3D42D5F96191F3CE50D70E0E42127A] GoodName=Madden NFL 99 (Beta) (1998-08-05) [!] CRC=76F8FB3 509A2054 RefMD5=507CEAB72EF2A1BF145BF190F5CE1C80 [20E51B27E8098A9D101B44689014C281] GoodName=Magical Tetris Challenge (E) [!] CRC=E4906679 9F243F05 Players=2 SaveType=None Rumble=Yes [20D02EECFA887DC5A31948B18B4BB18D] GoodName=Magical Tetris Challenge (E) [b1] CRC=E4906679 9F243F05 RefMD5=20E51B27E8098A9D101B44689014C281 [5BDE53960AD95F4C25C76C0F70C35244] GoodName=Magical Tetris Challenge (E) [f1] (NTSC) CRC=70BF6C4C 6F365E21 RefMD5=20E51B27E8098A9D101B44689014C281 [E0992A90191BE4F1B2BA02258599334E] GoodName=Magical Tetris Challenge (G) [!] CRC=E1EF93F7 14908B0B Players=2 SaveType=None Rumble=Yes [79FCC98002D1F4C79DEAF55784222DF8] GoodName=Magical Tetris Challenge (U) [!] CRC=75B61647 7ADABF78 Players=2 SaveType=None Rumble=Yes [BD5BB4CE1FACE911F9D8C777E2594998] GoodName=Magical Tetris Challenge (U) [b1][hI] CRC=CDCCFF87 1D76A49E RefMD5=79FCC98002D1F4C79DEAF55784222DF8 [36BEDFD15CB70478916BAA469491D80D] GoodName=Magical Tetris Challenge (U) [hI] CRC=CDCCFF87 1D76A49E RefMD5=79FCC98002D1F4C79DEAF55784222DF8 [F1FF1F364C459701F42BEB8989675D44] GoodName=Magical Tetris Challenge Featuring Mickey (J) [!] CRC=80C8564A 929C65AB Players=2 SaveType=None Rumble=Yes [9F6DB67262220C62536CEBE0AF3C8E73] GoodName=Magical Tetris Challenge Featuring Mickey (J) [b1] CRC=E6FCB468 CFAC7528 RefMD5=F1FF1F364C459701F42BEB8989675D44 [8AE2E8F0C356FEE638C8D908DCBB3381] GoodName=Mahjong 64 (J) [!] CRC=C53EDC41 ECE19359 Players=1 Mempak=Yes [E67651E58A4B864765A752E3BEB5F4E4] GoodName=Mahjong 64 (J) [o1] CRC=C53EDC41 ECE19359 RefMD5=8AE2E8F0C356FEE638C8D908DCBB3381 [F931E1DF9524BACEF6B731D50D7DC10F] GoodName=Mahjong 64 (J) [o2] CRC=C53EDC41 ECE19359 RefMD5=8AE2E8F0C356FEE638C8D908DCBB3381 [E942A3EEB1EB572BADD6F705EB12A22C] GoodName=Mahjong Hourouki Classic (J) [!] CRC=CCCC821E 96E88A83 Players=1 [50A8B47E5F8FE5BF955AFA70FE3893AC] GoodName=Mahjong Hourouki Classic (J) [b1] CRC=CCCC821E 96E88A83 RefMD5=E942A3EEB1EB572BADD6F705EB12A22C [D2CB04B88E565170D820E3CF78B54863] GoodName=Mahjong Hourouki Classic (J) [b2] CRC=CCCC821E 96E88A83 RefMD5=E942A3EEB1EB572BADD6F705EB12A22C [D1855B19BA0D65C103FE9318F14F5D7D] GoodName=Mahjong Hourouki Classic (J) [b3] CRC=CCCC821E 96E88A83 RefMD5=E942A3EEB1EB572BADD6F705EB12A22C [CF0D228E8EFDF823A227979BB352DD5B] GoodName=Mahjong Master (J) [!] CRC=0FC42C70 8754F1CD Players=1 Mempak=Yes [AD1AD9FE15C4565FF88B9B48AF6F300C] GoodName=Mahjong Master (J) [b1] CRC=0FC42C70 8754F1CD RefMD5=CF0D228E8EFDF823A227979BB352DD5B [E0D1170D521B49E3A5EDACA3A6F579AB] GoodName=Mahjong Master (J) [b2] CRC=0FC42C70 8754F1CD RefMD5=CF0D228E8EFDF823A227979BB352DD5B [3BD16F3DDB0DD890412BFE1E59CA5463] GoodName=Mahjong Master (J) [o1] CRC=0FC42C70 8754F1CD RefMD5=CF0D228E8EFDF823A227979BB352DD5B [152B9939A5F50734D5401980028856B4] GoodName=Major League Baseball Featuring Ken Griffey Jr. (E) [!] CRC=CDB998BE 1024A5C8 Players=2 SaveType=SRAM Mempak=Yes Rumble=Yes [62CD83FC8FC8E8CF8899320BF25474CE] GoodName=Major League Baseball Featuring Ken Griffey Jr. (E) [b1] CRC=59F34558 0C3130E4 RefMD5=152B9939A5F50734D5401980028856B4 [D5696CB5A4F2185BD8469DF018B7856B] GoodName=Major League Baseball Featuring Ken Griffey Jr. (E) [f1] CRC=59F34558 0C3130E4 RefMD5=152B9939A5F50734D5401980028856B4 [764F22AD3D0F59667A7F083D2F789B31] GoodName=Major League Baseball Featuring Ken Griffey Jr. (U) [!] CRC=80C1C05C EA065EF4 Players=2 SaveType=SRAM Mempak=Yes Rumble=Yes [97FE61E8719CF0A4747301E97C759CBF] GoodName=Major League Baseball Featuring Ken Griffey Jr. (U) [b1] CRC=B1CF1114 5E59B81D RefMD5=764F22AD3D0F59667A7F083D2F789B31 [E1BD016961EDEB895F12676AD4B77FB5] GoodName=Major League Baseball Featuring Ken Griffey Jr. (U) [b2] CRC=0BFC12D9 1B377DA7 RefMD5=764F22AD3D0F59667A7F083D2F789B31 [16F2644156AC9DD15CA8CC01DEAE5E7E] GoodName=Major League Baseball Featuring Ken Griffey Jr. (U) [b3] CRC=80C1C05C EA065EF4 RefMD5=764F22AD3D0F59667A7F083D2F789B31 [257057553D60C1DD1B7FDC5814CB21D9] GoodName=Major League Baseball Featuring Ken Griffey Jr. (U) [f1] CRC=B1CF1114 5E59B81D RefMD5=764F22AD3D0F59667A7F083D2F789B31 [30B2E1F7F3AFDC5D8E6A42C8885AAD93] GoodName=Mandelbrot Zoomer by RedBox (PD) CRC=30E6FE79 3EEA5386 Status=3 Players=0 SaveType=None [4E054610A872E1313228637C815E514C] GoodName=Manic Miner - Hidden Levels by RedboX (PD) CRC=A47D4AD4 F5B0C6CB Players=1 SaveType=None Status=1 Rumble=No [B18BC60EA6B9C72048FD84A2B8F182D4] GoodName=Manic Miner by RedboX (PD) CRC=A47D4AD4 8BFA81F9 Players=1 SaveType=None Status=1 Rumble=No [59F0839CAE935F8B06BAEC434CB29318] GoodName=Mario Artist: Communication Kit (J) [CART HACK] CRC=AB9EB27D 5F05605F [6A2B060606CFC20E0EE0A26759FE001B] GoodName=Mario Artist: Polygon Studio (J) [CART HACK] CRC=2D5EFCC5 98CF79D2 [9C1E3D607B1CC5FB90AD62D3F02A50ED] GoodName=Mario Artist: Paint Studio (J) [CART HACK] CRC=3A3EB7FB 0DDD515C Players=4 Transferpak=Yes [E811554E6C6A61BE750A1ED315909840] GoodName=Mario Artist: Paint Studio (J) [CART HACK] [T+Eng0.2_LuigiBlood] CRC=DD16F47C A8B748C7 Players=4 Transferpak=Yes [ED1CBFC5D3756A1520CD2D57F6998BDF] GoodName=Mario Artist: Talent Studio (J) [CART HACK] CRC=4CBC3B56 FDB69B1C Players=1 Transferpak=Yes [336AE63BD1EBACC64D9D92370B555537] GoodName=Mario Artist: Talent Studio (J) [CART HACK] [T+Eng0.1_LuigiBlood] CRC=73C0403D E821D951 Players=1 Transferpak=Yes [55634FF90EE997790781F79A5B0097EE] GoodName=Mario Golf (E) [!] CRC=62E957D0 7FC15A5D Players=4 SaveType=SRAM Rumble=Yes Transferpak=Yes [4D010AE1AF4B04D6B70B799C56F05993] GoodName=Mario Golf (E) [b1] CRC=62E957D0 7FC15A5D RefMD5=55634FF90EE997790781F79A5B0097EE [CF6BD6E20B40635B0E6DED5BB5114875] GoodName=Mario Golf (E) [f1] (Z64-Save) CRC=1D82BE21 7EF19C9A RefMD5=55634FF90EE997790781F79A5B0097EE [02C8E8FD7EB19BFEB325E2DB0380506A] GoodName=Mario Golf (E) [f2] (Z64-Save) CRC=1D82BE21 7EF19C9A RefMD5=55634FF90EE997790781F79A5B0097EE [18E09C0650FA3F83A90089DADD96A213] GoodName=Mario Golf (E) [h1C] CRC=62E957D0 7FC15A5D RefMD5=55634FF90EE997790781F79A5B0097EE [78BB5B9A279156BD61BE132817A9B2C8] GoodName=Mario Golf (E) [o1][h1C] CRC=62E957D0 7FC15A5D RefMD5=55634FF90EE997790781F79A5B0097EE [903E6929666531D72D05D1E4C522E305] GoodName=Mario Golf (U) [!] CRC=664BA3D4 678A80B7 Players=4 SaveType=SRAM Rumble=Yes Transferpak=Yes [D31466B4B14B03387FE52FBBBCD25A5C] GoodName=Mario Golf (U) [b1] CRC=E8761702 26AD5DBE RefMD5=903E6929666531D72D05D1E4C522E305 [11FED930D4C4DD0CA7CB03B5F1BF0A12] GoodName=Mario Golf (U) [b1][f1] (PAL) CRC=84CDFB72 9CA8D544 RefMD5=903E6929666531D72D05D1E4C522E305 [374FD81C3E8E858EEB2226501659B333] GoodName=Mario Golf (U) [b2] CRC=84CDFB72 9CA8D544 RefMD5=903E6929666531D72D05D1E4C522E305 [7A5D0D77A462B5A7C372FB19EFDE1A5F] GoodName=Mario Golf (U) [b3] CRC=664BA3D4 678A80B7 RefMD5=903E6929666531D72D05D1E4C522E305 [BE28EF71E1EE0092EEC4AA395ACFEEFF] GoodName=Mario Golf (U) [f1] (PAL) CRC=84CDFB72 9CA8D544 RefMD5=903E6929666531D72D05D1E4C522E305 [2FACDF2F3E52EE8A603DE79348E441E6] GoodName=Mario Golf (U) [f2] (Z64-Save) CRC=A19FA3D0 E06B2D11 RefMD5=903E6929666531D72D05D1E4C522E305 [12569B4FA5239A3AD53DE5D2E0243488] GoodName=Mario Golf (U) [t1] CRC=26647A17 8D3980C3 RefMD5=903E6929666531D72D05D1E4C522E305 [CD87BA2998D63C13B4366EB2C54E1EB6] GoodName=Mario Golf 64 (J) (V1.0) [!] CRC=D48944D1 B0D93A0E Players=4 SaveType=SRAM Rumble=Yes Transferpak=Yes [B5A98CED4B9A10682988CCB219A5C9A7] GoodName=Mario Golf 64 (J) (V1.0) [b1] CRC=D48944D1 B0D93A0E RefMD5=CD87BA2998D63C13B4366EB2C54E1EB6 [334D4E8443A67E964649B28428C8F1AE] GoodName=Mario Golf 64 (J) (V1.0) [b1][f1] (PAL) CRC=B771E0A9 7B4A96E6 RefMD5=CD87BA2998D63C13B4366EB2C54E1EB6 [6D84657C9A145E67B2A8A61CD31A7218] GoodName=Mario Golf 64 (J) (V1.0) [b2] CRC=D48944D1 B0D93A0E RefMD5=CD87BA2998D63C13B4366EB2C54E1EB6 [E5A041B1B7C8E3B4C2E8178E5A138E2D] GoodName=Mario Golf 64 (J) (V1.0) [b3] CRC=D48944D1 B0D93A0E RefMD5=CD87BA2998D63C13B4366EB2C54E1EB6 [C14090CD5CF313A471B5CD3D55EC0B53] GoodName=Mario Golf 64 (J) (V1.0) [f1] (PAL) CRC=B771E0A9 7B4A96E6 RefMD5=CD87BA2998D63C13B4366EB2C54E1EB6 [570B4F55A3005B709E6ED5D625981B90] GoodName=Mario Golf 64 (J) (V1.1) [!] CRC=734F816B C6A6EB67 Players=4 SaveType=SRAM Rumble=Yes Transferpak=Yes [78771BEB349D481E69BAA9225B36D63A] GoodName=Mario Kart 64 (Ch) (V4) (iQue) [!] [5EA0ED74CF1DDAAA964D728A129E7CF9] GoodName=Mario Kart 64 (Ch) (V5) (iQue) [!] [C70AF6197E67B310F316C34CCED64C19] GoodName=Mario Kart 64 (Ch) (V2) (iQue) (Manual) [!] [76176B237D4F60E59F98D247283D9365] GoodName=Mario Kart 64 (Ch) (V6) (iQue) (Manual) [!] [8FAD1E4FA7BAF1443B7F21AD1947B429] GoodName=Mario Kart 64 (E) (V1.0) [!] CRC=C3B6DE9D 65D2DE76 Status=3 SaveType=Eeprom 4KB Players=4 Mempak=Yes ; Multiplayer Timing Fix Cheat0=81001A1C 2409,81001A1E 0002,81001C74 240A,81001C76 0002 [EC0FAE8002AC6356E0470CE21BFEFA4F] GoodName=Mario Kart 64 (E) (V1.0) (Super W00ting Hack) CRC=E470469D E105C984 RefMD5=8FAD1E4FA7BAF1443B7F21AD1947B429 [B97FC8B1D00B9D673C229CA7FAE453D4] GoodName=Mario Kart 64 (E) (V1.0) [T+Ita_Cattivik66] CRC=C3B6DE9D 65D2DE76 RefMD5=8FAD1E4FA7BAF1443B7F21AD1947B429 [E292551471766D7F51907F2BC65079AA] GoodName=Mario Kart 64 (E) (V1.0) [b1] CRC=C3B6DE9D 65D2DE76 RefMD5=8FAD1E4FA7BAF1443B7F21AD1947B429 [8E632F2AFF9AEF3F5C1AE2FEBD482D9D] GoodName=Mario Kart 64 (E) (V1.0) [b2] CRC=C3B6DE9D 65D2DE76 RefMD5=8FAD1E4FA7BAF1443B7F21AD1947B429 [2BB149A583FDEFEA96805F628FE42FD9] GoodName=Mario Kart 64 (E) (V1.1) [!] CRC=2577C7D4 D18FAAAE Status=3 SaveType=Eeprom 4KB Players=4 Mempak=Yes ; Multiplayer Timing Fix Cheat0=81001A1C 2409,81001A1E 0002,81001C74 240A,81001C76 0002 [2A64632C71FFB90DF3AE83836DEDD7A6] GoodName=Mario Kart 64 (E) (V1.1) [T+Ita_Cattivik66][b1] CRC=2577C7D4 D18FAAAE RefMD5=2BB149A583FDEFEA96805F628FE42FD9 [A30CFA60CCCE25F1324D4AD98C26AF5D] GoodName=Mario Kart 64 (E) (V1.1) [o1] CRC=2577C7D4 D18FAAAE RefMD5=2BB149A583FDEFEA96805F628FE42FD9 [BF964CECA78A13A82055EBDA80B95CCA] GoodName=Mario Kart 64 (J) (V1.0) [!] CRC=6BFF4758 E5FF5D5E Status=3 SaveType=Eeprom 4KB Players=4 Mempak=Yes ; Multiplayer Timing Fix Cheat0=81001A1C 2409,81001A1E 0002,81001C74 240A,81001C76 0002 [8FD3C06ED13CD27BB3D664C92A455AA8] GoodName=Mario Kart 64 (J) (V1.0) [T+Ita_Cattivik66][b1] CRC=6BFF4758 E5FF5D5E RefMD5=BF964CECA78A13A82055EBDA80B95CCA [37AA3A354FBE508F5449E0C515083128] GoodName=Mario Kart 64 (J) (V1.0) [b1] CRC=6BFF4758 E5FF5D5E RefMD5=BF964CECA78A13A82055EBDA80B95CCA [80B4F92970CBB13344F57E827C60959B] GoodName=Mario Kart 64 (J) (V1.0) [b2] CRC=6BFF4758 E5FF5D5E RefMD5=BF964CECA78A13A82055EBDA80B95CCA [36295982651A9974EB7342B1DD5245E1] GoodName=Mario Kart 64 (J) (V1.0) [o1] CRC=6BFF4758 E5FF5D5E RefMD5=BF964CECA78A13A82055EBDA80B95CCA [60535265BAE43DDFCBDB0D71594B1693] GoodName=Mario Kart 64 (J) (V1.1) [!] CRC=C9C3A987 5810344C Status=3 SaveType=Eeprom 4KB Players=4 Mempak=Yes ; Multiplayer Timing Fix Cheat0=81001A1C 2409,81001A1E 0002,81001C74 240A,81001C76 0002 [231F0134D2899C08930F6E34682D2C0B] GoodName=Mario Kart 64 (J) (V1.1) [b1] CRC=C9C3A987 5810344C RefMD5=60535265BAE43DDFCBDB0D71594B1693 [84F11CACB9608E2E595FA5FBB8C91CE9] GoodName=Mario Kart 64 (J) (V1.1) [b1][T+Ita_Cattivik66] CRC=C9C3A987 5810344C RefMD5=60535265BAE43DDFCBDB0D71594B1693 [B5D68FF8E5A982400556C530409263DB] GoodName=Mario Kart 64 (J) (V1.1) [b1][f1] (PAL) CRC=B6F68615 F4E26039 RefMD5=60535265BAE43DDFCBDB0D71594B1693 [3A67D9986F54EB282924FCA4CD5F6DFF] GoodName=Mario Kart 64 (U) [!] CRC=3E5055B6 2E92DA52 Status=3 SaveType=Eeprom 4KB Players=4 Mempak=Yes ; Multiplayer Timing Fix Cheat0=81001A38 2409,81001A3A 0002,81001A3C 2409,81001A3E 0002,81001C90 240A,81001C92 0002,81001C94 240A,81001C96 0002 [B63346465FE70DA3B1E7493CE5A15A31] GoodName=Mario Kart 64 (U) (Super W00ting Hack) CRC=4D9C55B6 85E58D87 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [D1958141566ECC4942C71D1E97171639] GoodName=Mario Kart 64 (U) [T+Ita0.01_Cattivik66] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [22FACED432B0A9A4EC69A79452D16049] GoodName=Mario Kart 64 (U) [T+Ita1.0_Rulesless] CRC=4578A055 3F31815D RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [65CBD8DCEC6B7CE61E1CB233EFA4A317] GoodName=Mario Kart 64 (U) [T+Por1.0_Dr_X] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [79743743904EEA727CB82725BE765EC6] GoodName=Mario Kart 64 (U) [T+Spa1.1_Blade133bo] CRC=40CA1EC9 8CC292D4 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [4A5E85A3E7118A742E3678F8F7E82B0E] GoodName=Mario Kart 64 (U) [b1] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [ABDB8D8C53E1F938853EC80742C8AF77] GoodName=Mario Kart 64 (U) [b2] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [FE75ABB3934F88429E138019146E8393] GoodName=Mario Kart 64 (U) [b3] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [C3565B1C983B83C6C965BB88E24135B2] GoodName=Mario Kart 64 (U) [b4] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [7D54D888964A3B0D058EB80886C44C88] GoodName=Mario Kart 64 (U) [h1C] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [7C5E794E856311403FEF548DAE98A183] GoodName=Mario Kart 64 (U) [o1] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [6C634D0CE7CD99CCCBB4CE8EB837EDB4] GoodName=Mario Kart 64 (U) [o2] CRC=3E5055B6 2E92DA52 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [3AA8C8C023F6AB8384CBDD412DECF977] GoodName=Mario Kart 64 (U) [t1] CRC=465035CA C6DE1A09 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [22E183BD8AF57A79DEB6679CA919B61E] GoodName=Mario Kart 64 (U) [t2] (Course Cheat) CRC=085055B6 5346ED7B RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [9F85F64C6DD30CA67EB355EF0332F102] GoodName=Mario Kart 64 (U) [t3] (Star Cheat) CRC=0B623F24 F8D4F434 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [0B2B6CC62CFEEB7C4642A3643A3ED3C8] GoodName=Mario Kart 64 (U) [t4] CRC=465035CA C6DE1A09 RefMD5=3A67D9986F54EB282924FCA4CD5F6DFF [9773150709BD804B8E57E35F1D6B0EED] GoodName=Mario Party (E) (M3) [!] CRC=9C663069 80F24A80 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [1EAC55826A435FD1C0E0FEEFE89FAC15] GoodName=Mario Party (E) (M3) [T+Spa1.0_PacoChan] CRC=45C59BC3 D4C62468 RefMD5=9773150709BD804B8E57E35F1D6B0EED [2608A4D7A695D0B1A1BBC47695EACE0E] GoodName=Mario Party (E) (M3) [b1] CRC=9C663069 80F24A80 RefMD5=9773150709BD804B8E57E35F1D6B0EED [37EB3D60A2E85BE5077F73A5DF651F05] GoodName=Mario Party (E) (M3) [h1C] CRC=9C663069 80F24A80 RefMD5=9773150709BD804B8E57E35F1D6B0EED [3F556CC3B3A996CD2F471FA0D992D529] GoodName=Mario Party (J) [!] CRC=ADA815BE 6028622F Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [8BC2712139FBF0C56C8EA835802C52DC] GoodName=Mario Party (U) [!] CRC=2829657E A0621877 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [D072DDBCC5961AE85E6FA9BF50241370] GoodName=Mario Party (U) [f1] (PAL) CRC=5B904BAE 4CA06CC9 RefMD5=8BC2712139FBF0C56C8EA835802C52DC [F70112B652B0EE4856AF83F4E8005C31] GoodName=Mario Party 2 (E) (M5) [!] CRC=82380387 DFC744D9 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [F23E4CD437465F3E725262253CF3EA59] GoodName=Mario Party 2 (J) [!] CRC=ED567D0F 38B08915 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [04840612A35ECE222AFDB2DFBF926409] GoodName=Mario Party 2 (U) [!] CRC=9EA95858 AF72B618 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [F253C5A0FB69AB56A1548D435AF84D0F] GoodName=Mario Party 2 (U) [f1] (PAL) CRC=C6C71B88 6422C633 RefMD5=04840612A35ECE222AFDB2DFBF926409 [CD75CCD32EB435713EA54DFF313FA50C] GoodName=Mario Party 2 (U) [f2] (PAL) CRC=C63B1ADA 9CEAEB08 RefMD5=04840612A35ECE222AFDB2DFBF926409 [8E62EC6FBE3CC9FF6284191C9C88E68F] GoodName=Mario Party 3 (E) (M4) [!] CRC=C5674160 0F5F453C SaveType=Eeprom 16KB Players=4 Rumble=Yes CountPerOp=1 [ED99F330CE7A2638AB13351012EEB86B] GoodName=Mario Party 3 (J) [!] CRC=0B0AB4CD 7B158937 SaveType=Eeprom 16KB Players=4 Rumble=Yes CountPerOp=1 [76A8BBC81BC2060EC99C9645867237CC] GoodName=Mario Party 3 (U) [!] CRC=7C3829D9 6E8247CE SaveType=Eeprom 16KB Players=4 Rumble=Yes CountPerOp=1 [BDD79F498F37D01B8958F56EC6FFA097] GoodName=Mario Party 3 (U) [f1] CRC=65DB63E3 64357A65 RefMD5=76A8BBC81BC2060EC99C9645867237CC [F8F9116279FBAFD511748542994598B2] GoodName=Mario Party 3 (U) [f2] (PAL) CRC=822E0915 0338FD50 RefMD5=76A8BBC81BC2060EC99C9645867237CC [5C3D2699C01EBD30D42C6F52491EA7F0] GoodName=Mario Party 3 (U) [f3] CRC=DF0C666A 1F52B368 RefMD5=76A8BBC81BC2060EC99C9645867237CC [DF54F17FB84FB5B5BCF6AA9AF65B0942] GoodName=Mario Story (J) [!] CRC=3BA7CDDC 464E52A0 Status=2 Players=1 SaveType=Flash RAM Rumble=Yes CountPerOp=1 [FFF9B3E22ABB9B60215DAFB13AD5A4DE] GoodName=Mario Tennis (E) [!] CRC=839F3AD5 406D15FA SaveType=Eeprom 16KB Players=4 Rumble=Yes Transferpak=Yes [759358FAD1ED5AE31DCB2001A07F2FE5] GoodName=Mario Tennis (U) [!] CRC=5001CF4F F30CB3BD SaveType=Eeprom 16KB Players=4 Rumble=Yes Transferpak=Yes [7FB25633FDB226F35A222B4EA17BD2DC] GoodName=Mario Tennis (U) [f1] (Save) CRC=BC47A8BF 5529DE0F RefMD5=759358FAD1ED5AE31DCB2001A07F2FE5 [8EB1C2443D0B2E6EDA52A4EEA66D6C35] GoodName=Mario Tennis 64 (J) [!] CRC=3A6C42B5 1ACADA1B SaveType=Eeprom 16KB Players=4 Rumble=Yes Transferpak=Yes [DD4A580E27D82BCCA6A229BA17C69368] GoodName=Mario Tennis 64 (J) [f1] (Country Check) CRC=3A3FA519 9595CD82 RefMD5=8EB1C2443D0B2E6EDA52A4EEA66D6C35 [7F4ED2AAF94A2197B0AD63C6ECE9DEA9] GoodName=Mario no Photopie (J) [!] CRC=9A9890AC F0C313DF Players=1 [6BAB5F2A62A4BABAF456D5DA2976871D] GoodName=Mario no Photopie (J) [a1] CRC=9A9890AC F0C313DF RefMD5=7F4ED2AAF94A2197B0AD63C6ECE9DEA9 [DD65E5F4B192A12966BBDD6718B694E6] GoodName=MeeTING Demo by Renderman (PD) CRC=A806749B 1F521F45 [2202B39B9017BB061822552AF83FD331] GoodName=MeeTING Demo by Renderman (PD) [b1] CRC=A806749B 1F521F45 RefMD5=DD65E5F4B192A12966BBDD6718B694E6 [3620674ACB51E436D5150738AC1C0969] GoodName=Mega Man 64 (U) [!] CRC=0EC158F5 FB3E6896 Players=1 SaveType=Flash RAM Rumble=Yes [CD0824E9405185AF434837BA1C8C0CD5] GoodName=Mega Man 64 (U) (Beta) [!] CRC=27C985A8 ED7CE5C6 [01A1304D98A58E2D5069079A4F4441F9] GoodName=Mega Man 64 (U) [t1][f1] (PAL-NTSC) CRC=B63200D4 E36CF5AA RefMD5=3620674ACB51E436D5150738AC1C0969 [2F4C29DD26B6D5311F3D46063A393687] GoodName=Memory Manager V1.0b by R. Bubba Magillicutty (PD) CRC=4DEC9986 A8904450 [C77AC9BC65EEEA761FC8B081AF728CDB] GoodName=Mempack Manager for Jr 0.9 by deas (PD) CRC=81A3F478 B6965E3E [E1A9CBDB3C066E4BC0A4FB71ADA70CB2] GoodName=Mempack Manager for Jr 0.9b by deas (PD) CRC=1EC6C03C B0954ADA [9CF33B5F0D677C7BCE85CB877B0942CD] GoodName=Mempack Manager for Jr 0.9c by deas (PD) CRC=D2015E56 A9FE0CE6 [BAD7C9731029AD4880FF4B92E5569065] GoodName=Mempack to N64 Uploader by Destop V1.0 (PD) CRC=6A097D8B F999048C [A4039368E0472C68E3072C02C7A80F94] GoodName=Mia Hamm Soccer 64 (U) (M2) [!] CRC=1001F10C 3D51D8C1 Players=4 SaveType=None Mempak=Yes Rumble=Yes [892222CC4BAF9958405D20BC492175BF] GoodName=Michael Owens WLS 2000 (E) [!] CRC=E36166C2 8613A2E5 Players=4 SaveType=None Mempak=Yes Rumble=Yes [6A814E33BB6D449BE23FBBCAC7606C0B] GoodName=Michael Owens WLS 2000 (E) [b1] CRC=E36166C2 8613A2E5 RefMD5=892222CC4BAF9958405D20BC492175BF [EC700909D09C081DA0E4BAE454C657F0] GoodName=Michael Owens WLS 2000 (E) [b2] CRC=9ABC592A 2AA5DEE2 RefMD5=892222CC4BAF9958405D20BC492175BF [BD5D214BED53C4682E9FF8B8E9919CD4] GoodName=Michael Owens WLS 2000 (E) [f1] (NTSC) CRC=9ABC592A 2AA5DEE2 RefMD5=892222CC4BAF9958405D20BC492175BF [288A514E98972BF9D329167AA29E66B6] GoodName=Mickey no Racing Challenge USA (J) [!] CRC=736AE6AF 4117E9C7 Players=4 SaveType=Eeprom 4KB Rumble=Yes [5BA3DC37860C08A209F24286B8DFEC8C] GoodName=Mickey's Speedway USA (E) (M5) [!] CRC=DED0DD9A E78225A7 Players=4 SaveType=Eeprom 4KB Rumble=Yes Transferpak=Yes [0BF64427CF68E49C70E9EC2C9D815209] GoodName=Mickey's Speedway USA (U) [!] CRC=FA8C4571 BBE7F9C0 Players=4 SaveType=Eeprom 4KB Rumble=Yes Transferpak=Yes [B025F0E20FB41A0AAE280847329CB919] GoodName=Mickey's Speedway USA (U) [t1] CRC=38112EC7 E91410C3 RefMD5=0BF64427CF68E49C70E9EC2C9D815209 [9A8465E302263D635557A14AA197FE3C] GoodName=Micro Machines 64 Turbo (E) (M5) [!] CRC=2A49018D D0034A02 SaveType=None Mempak=Yes Rumble=Yes [68246CF0AB9DE7B6F84751FCC86A959A] GoodName=Micro Machines 64 Turbo (E) (M5) [b1] CRC=2A49018D D0034A02 RefMD5=9A8465E302263D635557A14AA197FE3C [7D61BB9D25BAF9A608139592DC4E28DC] GoodName=Micro Machines 64 Turbo (E) (M5) [b1][f1] (NTSC) CRC=700F6DD9 E2EB805F RefMD5=9A8465E302263D635557A14AA197FE3C [E48559E990DE24458F8A3ACDF3AEE901] GoodName=Micro Machines 64 Turbo (E) (M5) [t1] CRC=ADCDEC69 D0179F38 RefMD5=9A8465E302263D635557A14AA197FE3C [74EB415E16C333B252847A8E09432FD9] GoodName=Micro Machines 64 Turbo (U) [!] CRC=F1850C35 ACE07912 SaveType=None Mempak=Yes Rumble=Yes [BB9F2E48015D9DFB347B4BE4C2DFB334] GoodName=Micro Machines 64 Turbo (U) [a1][!] CRC=F1850C35 ACE07912 RefMD5=74EB415E16C333B252847A8E09432FD9 [656B1442015CF95D4D1E01713309F71D] GoodName=Micro Machines 64 Turbo (U) [b1] CRC=F1850C35 ACE07912 RefMD5=74EB415E16C333B252847A8E09432FD9 [C44D99D0437142211DACA4826F8ECB88] GoodName=Micro Machines 64 Turbo (U) [t1] CRC=A986ECC1 50AC924B RefMD5=74EB415E16C333B252847A8E09432FD9 [2B86775EA4D848202E4F4A39C33571CA] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [!] CRC=E4B35E4C 1AC45CC9 SaveType=None Mempak=Yes Players=2 [47EA6F037B093381CA88A41FBB6C4199] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [b1] CRC=E4B35E4C 1AC45CC9 RefMD5=2B86775EA4D848202E4F4A39C33571CA [1FE59964EC1A5899F3C7D97590F676EB] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [b2] CRC=3F462D42 93AE9238 RefMD5=2B86775EA4D848202E4F4A39C33571CA [B07FF4F972B269F2BDC69713B4B701A7] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [o1] CRC=E4B35E4C 1AC45CC9 RefMD5=2B86775EA4D848202E4F4A39C33571CA [24467B76A192DFB67069C5A87B8606D0] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [o1][t1] CRC=3F462D42 93AE9238 RefMD5=2B86775EA4D848202E4F4A39C33571CA [D30A4723E266D57D86BDC52F932D0DF1] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [t1] CRC=3F462D42 93AE9238 RefMD5=2B86775EA4D848202E4F4A39C33571CA [EB357505EFC9D17A08ADBA5590896C4D] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [t2] CRC=3F462D42 93AE9238 RefMD5=2B86775EA4D848202E4F4A39C33571CA [9D401FA1A1DDDF5C8995278E09E2210D] GoodName=Midway's Greatest Arcade Hits Volume 1 (U) [t2][b1] CRC=3F462D42 93AE9238 RefMD5=2B86775EA4D848202E4F4A39C33571CA [EB1908E51C8D10AF8B9CAF77797BFE00] GoodName=Mike Piazza's Strike Zone (U) [!] CRC=09D53E16 3AB268B9 Players=2 SaveType=None Mempak=Yes Rumble=Yes [F5978A54BB22E3BC4D46C0C3E9597B12] GoodName=Mike Piazza's Strike Zone (U) [h1C] CRC=09D53E16 3AB268B9 RefMD5=EB1908E51C8D10AF8B9CAF77797BFE00 [1B41A885CBAA693714575383DB4C05BE] GoodName=Mike Piazza's Strike Zone (U) [h2C] CRC=09D53E16 3AB268B9 RefMD5=EB1908E51C8D10AF8B9CAF77797BFE00 [83C51E3CD82A0D86CACE6D852990814F] GoodName=Mike Piazza's Strike Zone (U) [h3C] CRC=09D53E16 3AB268B9 RefMD5=EB1908E51C8D10AF8B9CAF77797BFE00 [43B02AF2789990A14F77CE020E6F135C] GoodName=Milo's Astro Lanes (E) [!] CRC=9A490D9D 8F013ADC Players=4 SaveType=None Mempak=Yes Rumble=Yes [988B490C2AEBF7DE3C274B7EAEEF0999] GoodName=Milo's Astro Lanes (E) [o1] CRC=9A490D9D 8F013ADC RefMD5=43B02AF2789990A14F77CE020E6F135C [F152C4A90B33D0D2BFAF782F56B202DF] GoodName=Milo's Astro Lanes (E) [o2] CRC=9A490D9D 8F013ADC RefMD5=43B02AF2789990A14F77CE020E6F135C [4F256146BAC4A3DDE5AD0D5F9C909251] GoodName=Milo's Astro Lanes (U) [!] CRC=2E955ECD F3000884 Players=4 SaveType=None Mempak=Yes Rumble=Yes [AC004667AB4578BAA9A1C0A7771E8B17] GoodName=Milo's Astro Lanes (U) [b1] CRC=2E955ECD F3000884 RefMD5=4F256146BAC4A3DDE5AD0D5F9C909251 [BE83566E7C7B9249FAC73DD2F1121424] GoodName=Milo's Astro Lanes (U) [h1C] CRC=2E955ECD F3000884 RefMD5=4F256146BAC4A3DDE5AD0D5F9C909251 [0FE31A113EF389F8F95460D340C7D922] GoodName=Milo's Astro Lanes (U) [h2C] CRC=2E955ECD F3000884 RefMD5=4F256146BAC4A3DDE5AD0D5F9C909251 [3D5F017D75679CEFCE2127CACC46C9F2] GoodName=Milo's Astro Lanes (U) [o1] CRC=2E955ECD F3000884 RefMD5=4F256146BAC4A3DDE5AD0D5F9C909251 [FD85E6B20A9099F670C3CFBD13AEE719] GoodName=Milo's Astro Lanes (U) [o1][b1] CRC=2E955ECD F3000884 RefMD5=4F256146BAC4A3DDE5AD0D5F9C909251 [C0513AE9494462433CDC83870320DA4E] GoodName=Mind Present Demo 0 by Widget and Immortal (POM '98) (PD) [b1] CRC=C811CBB1 8FB7617C [589DD744C7B07EC4DA91568CFBAC09EF] GoodName=Mind Present Demo 0 by Widget and Immortal (POM '98) (PD) CRC=C811CBB1 8FB7617C [4D1243D71F5536A416F3664A02FDF8E2] GoodName=Mind Present Demo Readme by Widget and Immortal (POM '98) (PD) CRC=139A06BC 416B0055 [EB3B078A74D4DC827E1E79791004DFBB] GoodName=Mischief Makers (E) [!] CRC=418BDA98 248A0F58 Players=1 SaveType=Eeprom 4KB CountPerOp=1 [5690D74157C6623E2928A6F0353EF4AF] GoodName=Mischief Makers (E) [b1] CRC=418BDA98 248A0F58 RefMD5=EB3B078A74D4DC827E1E79791004DFBB [495A9BFFD6620BE43225DB7133373FC5] GoodName=Mischief Makers (U) (V1.0) [!] CRC=0B93051B 603D81F9 Players=1 SaveType=Eeprom 4KB CountPerOp=1 [CCF012DF82022D4797CE4CC5405E084F] GoodName=Mischief Makers (U) (V1.0) [b1] CRC=0B93051B 603D81F9 RefMD5=495A9BFFD6620BE43225DB7133373FC5 [B3A172FE81F7BB47519D8E19E5F08154] GoodName=Mischief Makers (U) (V1.0) [o1] CRC=0B93051B 603D81F9 RefMD5=495A9BFFD6620BE43225DB7133373FC5 [2EE917366F64A06472D7622A2A05990E] GoodName=Mischief Makers (U) (V1.1) [!] CRC=BFA526B4 0691E430 Players=1 SaveType=Eeprom 4KB CountPerOp=1 [599B5D40B51F53C2C9A909E0139702FC] GoodName=Mission Impossible (E) [!] CRC=2256ECDA 71AB1B9C Players=1 SaveType=Eeprom 4KB Rumble=Yes [5CDC052C88A5CADCC3C73B165163E8C7] GoodName=Mission Impossible (E) [b1] CRC=2256ECDA 71AB1B9C RefMD5=599B5D40B51F53C2C9A909E0139702FC [FD0C0E8C523437F9B6B630E369FDFC69] GoodName=Mission Impossible (F) [!] CRC=20095B34 343D9E87 Players=1 SaveType=Eeprom 4KB Rumble=Yes [FF9CC9E03993DD15F1436AF3874F94CF] GoodName=Mission Impossible (F) [b1] CRC=20095B34 343D9E87 RefMD5=FD0C0E8C523437F9B6B630E369FDFC69 [D2442969E039254CF1B9B059DBB6311C] GoodName=Mission Impossible (F) [b2] CRC=20095B34 343D9E87 RefMD5=FD0C0E8C523437F9B6B630E369FDFC69 [4111482C92EE806484AAA2C210893A52] GoodName=Mission Impossible (G) [!] CRC=93EB3F7E 81675E44 Players=1 SaveType=Eeprom 4KB Rumble=Yes [66C7EB8148E0714B5A71F5717DFF8642] GoodName=Mission Impossible (I) [!] CRC=EBA949DC 39BAECBD Players=1 SaveType=Eeprom 4KB Rumble=Yes [CA60967822CCCEFE22299691B453D893] GoodName=Mission Impossible (I) [f1] (NTSC) CRC=C76B18F6 AAB1BDF3 RefMD5=66C7EB8148E0714B5A71F5717DFF8642 [D1BA3B1899576A4B67908ABB6544D75A] GoodName=Mission Impossible (S) [!] CRC=5F6A04E2 D4FA070D Players=1 SaveType=Eeprom 4KB Rumble=Yes [217B0E4723DBACDA40B70B26E610F5F9] GoodName=Mission Impossible (S) [f1] (NTSC) CRC=635CB5C6 E9192BFF RefMD5=D1BA3B1899576A4B67908ABB6544D75A [16A3143DC0E5FE6639F49DB7A51D24D4] GoodName=Mission Impossible (S) (V1.1) [!] CRC=5F6DDEA2 4DD9E759 Players=1 SaveType=Eeprom 4KB Rumble=Yes [EEBDFBD7CB57202D70CFFFCAAF55E93E] GoodName=Mission Impossible (U) [!] CRC=26035CF8 802B9135 Players=1 SaveType=Eeprom 4KB Rumble=Yes [550F4C177942FC0DF00B646C42EB4A90] GoodName=Mission Impossible (U) [b1] CRC=26035CF8 802B9135 RefMD5=EEBDFBD7CB57202D70CFFFCAAF55E93E [0D97158C3408F8E3E6D38A17223AC881] GoodName=Mission Impossible (U) [b2] CRC=09D4D757 F2775DBD RefMD5=EEBDFBD7CB57202D70CFFFCAAF55E93E [FA31743C3FC0236D6CEC0BD514DFB053] GoodName=Mission Impossible (U) [f1] (PAL) CRC=09D4D757 F2775DBD RefMD5=EEBDFBD7CB57202D70CFFFCAAF55E93E [5320608C729C9F5B32581F81604D75E6] GoodName=Mission Impossible (U) [t1] CRC=B0105C85 6E5094B9 RefMD5=EEBDFBD7CB57202D70CFFFCAAF55E93E [4FF9589A3224AAA46E9877D6B25E68E3] GoodName=Monaco Grand Prix (U) [!] CRC=28768D6D B379976C Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [9BF4D7FBE8157C9D6866A90269DCA7CB] GoodName=Monaco Grand Prix (U) [f1] (PAL) CRC=DA233397 FF46DF64 RefMD5=4FF9589A3224AAA46E9877D6B25E68E3 [C93A17D130B96FBA27A0E959CAB2A450] GoodName=Monaco Grand Prix - Racing Simulation 2 (E) (M4) [!] CRC=28705FA5 B509690E Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [F81580C9C480DDF1B8F7E6A56D1B9CD5] GoodName=Money Creates Taste Demo by Count0 (POM '99) (PD) [f1] CRC=97E57686 F271C12F [A74DBAA3BF59DE13B6A191A6675C85D7] GoodName=Money Creates Taste Demo by Count0 (POM '99) (PD) CRC=282A4262 58B47E76 [D51506EDB0A941A00EB45850703B32CB] GoodName=Monopoly (U) [!] CRC=5AC383E1 D712E387 Players=4 SaveType=Eeprom 4KB CountPerOp=1 [26C3654D20B8718A75B5FE8DA5B3284A] GoodName=Monopoly (U) [f1] (PAL) CRC=B9D36858 559A8241 RefMD5=D51506EDB0A941A00EB45850703B32CB [E3B408997D7DB91F8219F168C6D57D26] GoodName=Monster Truck Madness 64 (E) (M5) [!] CRC=D3D806FC B43AA2A8 Players=4 SaveType=None Rumble=Yes CountPerOp=3 [12534DAB32DBFC6CA4F66D05729102E6] GoodName=Monster Truck Madness 64 (E) (M5) [f1] (NTSC) CRC=AE5E467C D7194A71 RefMD5=E3B408997D7DB91F8219F168C6D57D26 [514D61D3B3D5E6326869783EB2E84A00] GoodName=Monster Truck Madness 64 (U) [!] CRC=B19AD999 7E585118 Players=4 SaveType=None Rumble=Yes CountPerOp=3 [3C9F329D5E0C7FE57355B8DC68F79331] GoodName=Monster Truck Madness 64 (U) [t1] CRC=29A9E7F6 1B90CFCE RefMD5=514D61D3B3D5E6326869783EB2E84A00 [462B9C4F38758C2E558312AC60DF2B91] GoodName=Morita Shougi 64 (J) [!] CRC=E8E8DD70 415DD198 Players=4 Mempak=Yes [264B82F0FC2431D6EEFDE9C9F3ED7596] GoodName=Mortal Kombat 4 (E) [!] CRC=73036F3B CE0D69E9 Players=2 SaveType=None Mempak=Yes Rumble=Yes [58EFAF3D7D0985BC426245EFA5418CC2] GoodName=Mortal Kombat 4 (E) [h1C] CRC=73036F3B CE0D69E9 RefMD5=264B82F0FC2431D6EEFDE9C9F3ED7596 [619B1F196B70260DCE89B21E66D10934] GoodName=Mortal Kombat 4 (E) [t1] (Hit Anywhere) CRC=72836ECB 75D15FAE RefMD5=264B82F0FC2431D6EEFDE9C9F3ED7596 [C70B91430866300CE38B49098019EF9D] GoodName=Mortal Kombat 4 (U) [!] CRC=417DD4F4 1B482FE2 Players=2 SaveType=None Mempak=Yes Rumble=Yes [CCD5A3B82976D65B3B42E8E2B2B43B48] GoodName=Mortal Kombat 4 (U) [b1] CRC=F96E28F7 421A4285 RefMD5=C70B91430866300CE38B49098019EF9D [4C7092585CF64BBE7F26ECA720AE8941] GoodName=Mortal Kombat 4 (U) [b2] CRC=DB6E353B 205B0C53 RefMD5=C70B91430866300CE38B49098019EF9D [480855E2348D6B85721C620AE9FEF138] GoodName=Mortal Kombat 4 (U) [b3] CRC=417DD4F4 1B482FE2 RefMD5=C70B91430866300CE38B49098019EF9D [F972B634F638CC54AD6DCBFDC661CC02] GoodName=Mortal Kombat 4 (U) [h1C] CRC=417DD4F4 1B482FE2 RefMD5=C70B91430866300CE38B49098019EF9D [A5F7C9F5B711ECA7C2A2923EEA6CF762] GoodName=Mortal Kombat 4 (U) [t1] CRC=DB6E353B 205B0C53 RefMD5=C70B91430866300CE38B49098019EF9D [24E39D47A0D1AFA138B1F39AA2DAA648] GoodName=Mortal Kombat 4 (U) [t1][f1] (PAL) CRC=DB6E353B 205B0C53 RefMD5=C70B91430866300CE38B49098019EF9D [18E1CA4BE7D8E56AC940852EC5E3ED22] GoodName=Mortal Kombat 4 (U) [t2] (Hit Anywhere) CRC=417DD7F4 C95B6E9E RefMD5=C70B91430866300CE38B49098019EF9D [38A82A56AE61A4D354C6A26E64D25E1C] GoodName=Mortal Kombat Mythologies - Sub-Zero (E) [!] CRC=FF44EDC4 1AAE9213 Players=1 SaveType=None Mempak=Yes Rumble=Yes [DAFEE0C1FC99882A2C6A340BF0E58A08] GoodName=Mortal Kombat Mythologies - Sub-Zero (E) [h1C] CRC=FF44EDC4 1AAE9213 RefMD5=38A82A56AE61A4D354C6A26E64D25E1C [528445FB76D0F060DF5CBE71AEEDA20F] GoodName=Mortal Kombat Mythologies - Sub-Zero (E) [t1] (Endless Ice) CRC=6DF2CB25 4D4821F8 RefMD5=38A82A56AE61A4D354C6A26E64D25E1C [DEEC4FAEC416F4E02D934C2E42C0CAAD] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [!] CRC=C34304AC 2D79C021 Players=1 SaveType=None Mempak=Yes Rumble=Yes [8F2544F095EF7D9A5096E3D52472D699] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [b1] CRC=834304AE 5845CD3A RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [1793B45C4797D9418685946A002B5D15] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [b2] CRC=C34304AC 2D79C021 RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [5443BFB72D91D0DFD72FC1C6FA03A113] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [b3] CRC=C34304AC 2D79C021 RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [7CCC138882A64267AD58449F309FC1D1] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [f1] CRC=834304AE 5845CD3A RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [A6C51954EE5DF373E159E0E55DEAE239] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [f3] (PAL) CRC=834304AE 5845CD3A RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [FFF4E1455C03F71272063C309D9F9102] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [h1C] CRC=C34304AC 2D79C021 RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [FCD0BFF90306B13EB8E5007E5B4C2CB7] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [h2C] CRC=834304AE 5845CD3A RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [5583527ED4AA49CF713FAE400E77F9A2] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [o1] CRC=C34304AC 2D79C021 RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [AB06E6D777AE710F9B5A4DC4E7A295C8] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [t1] CRC=5972E751 228381B3 RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [85B99F3D09C4070EEA7669A09D20243F] GoodName=Mortal Kombat Mythologies - Sub-Zero (U) [t2] (Endless Ice) CRC=ADDD6241 AA79B2F2 RefMD5=DEEC4FAEC416F4E02D934C2E42C0CAAD [B278DDD3FB63F70B8B6EFEF445D81595] GoodName=Mortal Kombat SRAM Loader (PD) CRC=947A4B47 90BFECA6 [7A558BBAD8CE8828414A9CF3B044A87D] GoodName=Mortal Kombat Trilogy (E) [!] CRC=8C3D1192 BEF172E1 SaveType=None Players=2 [1C6FE6A40AAC4BD515373B6ED8D25DBF] GoodName=Mortal Kombat Trilogy (E) [b1] CRC=8C3D1192 BEF172E1 RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [0F9B89C903BEFEDCFD107E5B5ADE687F] GoodName=Mortal Kombat Trilogy (E) [h1C] CRC=8C3D1192 BEF172E1 RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [B05DEC10CDEFACF4153E345940410477] GoodName=Mortal Kombat Trilogy (E) [o1] CRC=8C3D1192 BEF172E1 RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [AB72CB8971FA37176D3219B5F49AF442] GoodName=Mortal Kombat Trilogy (E) [t1] (Hit Anywhere) CRC=8C3D1192 B5096A18 RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [CFC196103E355B12A50605AB268992FA] GoodName=Mortal Kombat Trilogy (E) [t2] (All Attacks Hurt P1) CRC=833D11B6 1848E72B RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [9CC60D046372D2C9A529ED225E3CDB08] GoodName=Mortal Kombat Trilogy (E) [t3] (All Attacks Hurt P2) CRC=833D1192 D3C58762 RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [EBF2AC190EBB2FE6D75AD0ACAA2A82CD] GoodName=Mortal Kombat Trilogy (E) [t4] (Hyper Mode) CRC=93ED1192 2B2C6244 RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [ED7773988BCC03D06E2330A8E77BEC6F] GoodName=Mortal Kombat Trilogy (E) [t5] (2x Aggressor) CRC=8C352E50 6B93F13B RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [DF00C698E2B18A6CA94C09CCD82CACEB] GoodName=Mortal Kombat Trilogy (E) [t6] (P1 Invincible) CRC=8C3511AE 57115A86 RefMD5=7A558BBAD8CE8828414A9CF3B044A87D [9B7F29AAB911D6753F2011C48DA752BF] GoodName=Mortal Kombat Trilogy (U) (V1.0) [!] CRC=D9F75C12 A8859B59 Players=2 SaveType=None [7CD386C8D2E69DBBF55F02A564BD6A9A] GoodName=Mortal Kombat Trilogy (U) (V1.0) [b1] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [77CE01C32E172C7DD812C4F1179FBA2E] GoodName=Mortal Kombat Trilogy (U) (V1.0) [b2] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [9DA1E143FF580834FE485D08C21B6D01] GoodName=Mortal Kombat Trilogy (U) (V1.0) [b3] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [ED4414B512CF22DA64B080D34B5E2F4F] GoodName=Mortal Kombat Trilogy (U) (V1.0) [b4] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [57464801A058B97E056766DDFCF93A69] GoodName=Mortal Kombat Trilogy (U) (V1.0) [b5] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [8CE0A41CB29C14300B482E0E9897EBBF] GoodName=Mortal Kombat Trilogy (U) (V1.0) [h1C] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [4DBAD6B0E2F30A63F974A85513B668E0] GoodName=Mortal Kombat Trilogy (U) (V1.0) [h2C] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [976825DAB07E6F5D69BFD5B46337DE85] GoodName=Mortal Kombat Trilogy (U) (V1.0) [o1] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [EE052C69FFA67DB3544872AB0E745DDF] GoodName=Mortal Kombat Trilogy (U) (V1.0) [o1][h1C] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [10774BFBC9D815194AD904F898CBE96F] GoodName=Mortal Kombat Trilogy (U) (V1.0) [o1][h2C] CRC=D9F75C12 A8859B59 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [04A3F6D2A30FEDE6CADC5C2FCBCFBD12] GoodName=Mortal Kombat Trilogy (U) (V1.0) [t1] (Hit Anywhere) CRC=F9F75B92 AFEC042B RefMD5=9B7F29AAB911D6753F2011C48DA752BF [CCD0BA9C220D1EE91B39747A6E5065EE] GoodName=Mortal Kombat Trilogy (U) (V1.0) [t2] (All Attacks Hurt P1) CRC=F2F75C36 36637257 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [548C444FB604CA179EAD4115FFB070FC] GoodName=Mortal Kombat Trilogy (U) (V1.0) [t3] (All Attacks Hurt P2) CRC=D2F75C12 E89EB415 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [4DED9381CD0D396AE6C9634D575DD93C] GoodName=Mortal Kombat Trilogy (U) (V1.0) [t4] (Hyper Mode) CRC=A2015C11 C317ECAB RefMD5=9B7F29AAB911D6753F2011C48DA752BF [F5509B1EA83A49D01E5E4EF475B87278] GoodName=Mortal Kombat Trilogy (U) (V1.0) [t5] (2x Aggressor) CRC=D9FECC50 D3AA8423 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [D68FC4D8568B7D02EFD47F32B9C091D7] GoodName=Mortal Kombat Trilogy (U) (V1.0) [t6] (P1 Invincible) CRC=A1815C2E C6806731 RefMD5=9B7F29AAB911D6753F2011C48DA752BF [26129419799DB01BFE79F279EC43B334] GoodName=Mortal Kombat Trilogy (U) (V1.1) [!] CRC=19F55D46 73A27B34 Players=2 SaveType=None [3DCB15043063BD656A0223C519218CFB] GoodName=Mortal Kombat Trilogy (U) (V1.2) [!] CRC=83F33AA9 A901D40D Players=2 SaveType=None [27F761B7DD73E12BB311772780D6B9F4] GoodName=Mortal Kombat Trilogy (U) (V1.2) [t1] (Hit Anywhere) CRC=83F33AA9 2649847A RefMD5=3DCB15043063BD656A0223C519218CFB [8A7B5A6AB0E815DBDFFD1FC99939CE9F] GoodName=Mortal Kombat Trilogy (U) (V1.2) [t2] (All Attacks Hurt P1) CRC=BCF33AAD BF3C37EC RefMD5=3DCB15043063BD656A0223C519218CFB [37FEB7178712980DD0953D195187C35D] GoodName=Mortal Kombat Trilogy (U) (V1.2) [t3] (All Attacks Hurt P2) CRC=9CF33AA9 3F05381F RefMD5=3DCB15043063BD656A0223C519218CFB [D3B28E1E154C5B58A40E3D71D8599CE2] GoodName=Mortal Kombat Trilogy (U) (V1.2) [t4] (Hyper Mode) CRC=9C013AA8 EB3267A7 RefMD5=3DCB15043063BD656A0223C519218CFB [0D708DDE7EC6B67E705F1D865D70AFDA] GoodName=Mortal Kombat Trilogy (U) (V1.2) [t5] (2x Aggressor) CRC=83FB2B69 7A5D2980 RefMD5=3DCB15043063BD656A0223C519218CFB [68EBC8C849459FE30E7162D48EBAC0BD] GoodName=Mortal Kombat Trilogy (U) (V1.2) [t6] (P1 Invincible) CRC=83F33AA9 A901D40D RefMD5=3DCB15043063BD656A0223C519218CFB [B6A7B85C123DF4E0B9CC118578DBC9A2] GoodName=Mortal Kombat Trilogy (U) (Beta) (1996-05-13) [!] RefMD5=9B7F29AAB911D6753F2011C48DA752BF [08BEA3310E778A6584EB64CD3F15F86E] GoodName=Ms. Pac-Man - Maze Madness (U) [!] CRC=1938525C 586E9656 Players=4 SaveType=None Mempak=Yes Rumble=Yes [F905CA22CC030BBED516F3D1B6C2153A] GoodName=My Angel Demo (PD) CRC=9865799F 006F908C [E6B5C17B7BBBB7C432B3506C085D16C4] GoodName=Mystical Ninja 2 Starring Goemon (E) (M3) [!] CRC=7F9345D3 841ECADE Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [75AD771425CBE2B1E8C7B4D94E67B1CA] GoodName=Mystical Ninja 2 Starring Goemon (E) (M3) [hI] CRC=C27F7CEC 85E0806F RefMD5=E6B5C17B7BBBB7C432B3506C085D16C4 [004EA34EE12CBABDC053419714E66DD4] GoodName=Mystical Ninja 2 Starring Goemon (E) (M3) [t1] CRC=C27F7CEC 85E0806F RefMD5=E6B5C17B7BBBB7C432B3506C085D16C4 [698930C7CCD844673D77FFECCB3DD66E] GoodName=Mystical Ninja Starring Goemon (E) [!] CRC=F5360FBE 2BF1691D Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [DBD2BC43FCDADACD234AEFC8130A5413] GoodName=Mystical Ninja Starring Goemon (E) [b1] CRC=F5360FBE 2BF1691D RefMD5=698930C7CCD844673D77FFECCB3DD66E [8F1C1FEAAF0D053E230361E3F81B0269] GoodName=Mystical Ninja Starring Goemon (E) [h1C] CRC=F5360FBE 2BF1691D RefMD5=698930C7CCD844673D77FFECCB3DD66E [1FFBDAB727C9D634D4F4DDBD9F358445] GoodName=Mystical Ninja Starring Goemon (E) [t1] CRC=835B97A2 FF6C0060 RefMD5=698930C7CCD844673D77FFECCB3DD66E [643CCE1AB06F97E9590241D27E5C2363] GoodName=Mystical Ninja Starring Goemon (U) [!] CRC=FCBCCB21 72903C6B Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [42E282A3F208C4BDE50A4A4301181B16] GoodName=Mystical Ninja Starring Goemon (U) [h1C] CRC=FCBCCB21 72903C6B RefMD5=643CCE1AB06F97E9590241D27E5C2363 [07A7D3DB5B64A6CCF9D44B321472CC21] GoodName=Mystical Ninja Starring Goemon (U) [t1] CRC=7AADA8DD 94DAB468 RefMD5=643CCE1AB06F97E9590241D27E5C2363 [55F99A3F3402491E9517980BE636E3FE] GoodName=Mystical Ninja Starring Goemon (U) [t1][h2C] CRC=7AADA8DD 94DAB468 RefMD5=643CCE1AB06F97E9590241D27E5C2363 [4D1821886352EAA2F663CFF63ED17DD8] GoodName=Mystical Ninja Starring Goemon (U) [t2] CRC=7AADA8DD 94DAB468 RefMD5=643CCE1AB06F97E9590241D27E5C2363 [17B839B8E72A6287A5BB3CEFCBC035E9] GoodName=N64 Scene Gallery by CALi (PD) CRC=6D2C07F1 C884F0D0 [882B30625B722B5C29D0D94E70D9302E] GoodName=N64 Seminar Demo - CPU by ZoRAXE (PD) CRC=FD61BB45 FBB51EB2 [8B7816E975DB27B4BF591BFC73C43944] GoodName=N64 Seminar Demo - RSP by ZoRAXE (PD) CRC=6D03673A 1D63C191 [023175B6C809704F00A317ABCD25A8F9] GoodName=N64 Stars Demo (PD) [b1] CRC=71255651 C6AE0EA6 [67836FE63901319874E0754BC918AF7D] GoodName=N64 Stars Demo (PD) CRC=71255651 C6AE0EA6 [F4B5863F550BC83C7924E423B01E1C5A] GoodName=N64probe (Button Test) by MooglyGuy (PD) CRC=44410533 0C61FA96 [45FEB0FBBEC6CB48FF21DEAE176E9B6B] GoodName=NASCAR 2000 (U) [!] CRC=DF331A18 5FD4E044 Players=2 SaveType=None Mempak=Yes Rumble=Yes [DB3A918FA61E1FB3110CFE6E9DA33E97] GoodName=NASCAR 2000 (U) [f1] (PAL) CRC=651F2792 E40CC56B RefMD5=45FEB0FBBEC6CB48FF21DEAE176E9B6B [15A87A6D01DBA1A7C4375FFBC1214BB8] GoodName=NASCAR 99 (E) (M3) [!] CRC=AE4992C9 9253B253 Players=2 SaveType=None Mempak=Yes Rumble=Yes [A31AD7E7E6177BED7345635FDA563FCA] GoodName=NASCAR 99 (E) (M3) [h1C] CRC=AE4992C9 9253B253 RefMD5=15A87A6D01DBA1A7C4375FFBC1214BB8 [DC5F1A814C8423B4B43F71C229D65A84] GoodName=NASCAR 99 (U) [!] CRC=23749578 80DC58FD Players=2 SaveType=None Mempak=Yes Rumble=Yes [AC88A7D81FF0B712EA3A302419F3A927] GoodName=NASCAR 99 (U) [b1] CRC=23749578 80DC58FD RefMD5=DC5F1A814C8423B4B43F71C229D65A84 [DA77C8AB76E6209550D56FED1817AFBD] GoodName=NASCAR 99 (U) [b2] CRC=FCB2955B B302626D RefMD5=DC5F1A814C8423B4B43F71C229D65A84 [A267D8C94031678DD395FE4667C4A76A] GoodName=NASCAR 99 (U) [b3] CRC=23E39896 73AB48DC RefMD5=DC5F1A814C8423B4B43F71C229D65A84 [71BE7A48778737FDDD3CDE7849502C5B] GoodName=NASCAR 99 (U) [f1] (PAL) CRC=FCB2955B B302626D RefMD5=DC5F1A814C8423B4B43F71C229D65A84 [DB644859C4DCE5418010A2427E3904C0] GoodName=NASCAR 99 (U) [o1] CRC=23749578 80DC58FD RefMD5=DC5F1A814C8423B4B43F71C229D65A84 [73BB54FFD3C0FC71F941D9A8CC57E2A1] GoodName=NBA Courtside 2 - Featuring Kobe Bryant (U) [!] CRC=916852D8 73DBEAEF Players=4 SaveType=Flash RAM Rumble=Yes [EE4DCAED6759CE013BC7B5E8E815B343] GoodName=NBA Courtside 2 - Featuring Kobe Bryant (U) [f1] (PAL) CRC=3F16568F 37D93603 RefMD5=73BB54FFD3C0FC71F941D9A8CC57E2A1 [F734667EF21DA97092F54D2547E11E51] GoodName=NBA Courtside 2 - Featuring Kobe Bryant (U) [f2] CRC=2816D957 A59FF70A RefMD5=73BB54FFD3C0FC71F941D9A8CC57E2A1 [032ADEEF1C2D0B4387FAC099334F72E3] GoodName=NBA Courtside 2 - Featuring Kobe Bryant (U) [hI] CRC=24F7EB57 74B3F9F4 RefMD5=73BB54FFD3C0FC71F941D9A8CC57E2A1 [94E3F2ACE3EB74150F036B217FF50370] GoodName=NBA Courtside 2 - Featuring Kobe Bryant (U) [hI][f1] (PAL) CRC=26211297 97DB4DFC RefMD5=73BB54FFD3C0FC71F941D9A8CC57E2A1 [62365463743857CFC823978E0E590D84] GoodName=NBA Hangtime (E) [!] CRC=C788DCAE BD03000A Players=4 SaveType=None Mempak=Yes [0057A561D7034392D4267A4134DA41B0] GoodName=NBA Hangtime (E) [h1C] CRC=C788DCAE BD03000A RefMD5=62365463743857CFC823978E0E590D84 [DC15FCBEAE0F1FEF7BEE141D77BB25A0] GoodName=NBA Hangtime (U) [!] CRC=4E69B487 FE18E290 Players=4 SaveType=None Mempak=Yes [9C595E5A5F027385A340ADDF609852DD] GoodName=NBA Hangtime (U) [b1] CRC=4E69B487 FE18E290 RefMD5=DC15FCBEAE0F1FEF7BEE141D77BB25A0 [4955DEA9356D1506D6DE8BD8DA10E938] GoodName=NBA Hangtime (U) [b2] CRC=4E69B487 FE18E290 RefMD5=DC15FCBEAE0F1FEF7BEE141D77BB25A0 [C8D6A414505595C13C7DA4D07A172343] GoodName=NBA Hangtime (U) [b3] CRC=4E69B487 FE18E290 RefMD5=DC15FCBEAE0F1FEF7BEE141D77BB25A0 [C2D094778DA53C7A84466130EC5C65B0] GoodName=NBA Hangtime (U) [f1] (PAL) CRC=4E69B487 FE18E290 RefMD5=DC15FCBEAE0F1FEF7BEE141D77BB25A0 [80F918D90DF42C9841AE998A89223C1E] GoodName=NBA Hangtime (U) [o1] CRC=4E69B487 FE18E290 RefMD5=DC15FCBEAE0F1FEF7BEE141D77BB25A0 [62E182D019DCE0C0EEAA3BE2023A327A] GoodName=NBA Hangtime (U) [o1][f1] CRC=4E69B487 FE18E290 RefMD5=DC15FCBEAE0F1FEF7BEE141D77BB25A0 [4C7A2F4881EACA75DC2FC36673AE2A20] GoodName=NBA In the Zone '98 (J) [!] CRC=36ACBA9B F28D4D94 Players=4 SaveType=None Mempak=Yes Rumble=Yes [4151ED80568EFCCA34F8831D957EB7A6] GoodName=NBA In the Zone '98 (J) [o1] CRC=36ACBA9B F28D4D94 RefMD5=4C7A2F4881EACA75DC2FC36673AE2A20 [23215642F5FAAAD0761166EA018963F0] GoodName=NBA In the Zone '98 (J) [o2] CRC=36ACBA9B F28D4D94 RefMD5=4C7A2F4881EACA75DC2FC36673AE2A20 [BBB48BE198089A26050C84FE5B7B8BD5] GoodName=NBA In the Zone '98 (U) [!] CRC=6A121930 665CC274 Players=4 SaveType=None Mempak=Yes Rumble=Yes [EE43F010F2E87BC68535D333FE64C516] GoodName=NBA In the Zone '98 (U) [b1] CRC=6A121930 665CC274 RefMD5=BBB48BE198089A26050C84FE5B7B8BD5 [49B49E6DD528E896DE9BCE3DCCF3442E] GoodName=NBA In the Zone '98 (U) [b2] CRC=6A121930 665CC274 RefMD5=BBB48BE198089A26050C84FE5B7B8BD5 [42F3A177F54C86F2C8EE6AFDB892A5A9] GoodName=NBA In the Zone '98 (U) [b3] CRC=36ACBA9B F28D4D94 RefMD5=BBB48BE198089A26050C84FE5B7B8BD5 [BF33C371BF396A5F6E72627A34AEDAF5] GoodName=NBA In the Zone '98 (U) [h1C] CRC=6A121930 665CC274 RefMD5=BBB48BE198089A26050C84FE5B7B8BD5 [62DFA8A5906E973A2C923A165EBE00A1] GoodName=NBA In the Zone '98 (U) [h2C] CRC=6A121930 665CC274 RefMD5=BBB48BE198089A26050C84FE5B7B8BD5 [92D2BD868B17B3CA8A19116ADDB963B0] GoodName=NBA In the Zone '98 (U) [o1] CRC=6A121930 665CC274 RefMD5=BBB48BE198089A26050C84FE5B7B8BD5 [6CBF4014C053E16852A3DB80AEB4C853] GoodName=NBA In the Zone '99 (U) [!] CRC=A292524F 3D6C2A49 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [F8F87AEB2C537C9CB2E9913050BFC928] GoodName=NBA In the Zone 2 (J) [!] CRC=AAE11F01 2625A045 Players=4 SaveType=None Mempak=Yes Rumble=Yes [4244CC48674C26BD848718C05688F821] GoodName=NBA In the Zone 2000 (E) [!] CRC=B3054F9F 96B69EB5 Players=4 SaveType=None Mempak=Yes Rumble=Yes [AF6521E33FDE918B9A2298FA0BD3AA90] GoodName=NBA In the Zone 2000 (E) [h1C] CRC=B3054F9F 96B69EB5 RefMD5=4244CC48674C26BD848718C05688F821 [1942833AC1A71BE8BAE74BBDFD6DE278] GoodName=NBA In the Zone 2000 (U) [!] CRC=8DF95B18 ECDA497B Players=4 SaveType=None Mempak=Yes Rumble=Yes [F4401BCC9DD25254503E32B482EB3FAA] GoodName=NBA In the Zone 2000 (U) [f1] (PAL) CRC=4F8AA5EC 1E6E72DE RefMD5=1942833AC1A71BE8BAE74BBDFD6DE278 [604FEB17258044A3E6C3AA9D2C5B62F9] GoodName=NBA Jam 2000 (E) [!] CRC=B6D0CAA0 E3F493C8 Players=4 SaveType=None Mempak=Yes Rumble=Yes [AFECC9A2DF7B1A66A6B7AB3AA8B4BD2E] GoodName=NBA Jam 2000 (U) [!] CRC=EBEEA8DB F2ECB23C Players=4 SaveType=None Mempak=Yes Rumble=Yes [E25F3A1136C9C81702E0827040C5A115] GoodName=NBA Jam 2000 (U) [f1] (PAL) CRC=F3996B67 3A3030FA RefMD5=AFECC9A2DF7B1A66A6B7AB3AA8B4BD2E [BE72BE370BC0A76D403FF2B9ED2A9173] GoodName=NBA Jam 99 (E) [!] CRC=E600831E 59F422A8 Players=4 SaveType=None Mempak=Yes [0A9D53EF71A0C6F2AE3A0435E3D58747] GoodName=NBA Jam 99 (E) [h1C] CRC=E600831E 59F422A8 RefMD5=BE72BE370BC0A76D403FF2B9ED2A9173 [ADBE5CA10F659AF2BE712038E8522704] GoodName=NBA Jam 99 (U) [!] CRC=810729F6 E03FCFC1 Players=4 SaveType=None Mempak=Yes [7344483130995CA211B5B9FF9891A9DE] GoodName=NBA Jam 99 (U) [b1] CRC=810729F6 E03FCFC1 RefMD5=ADBE5CA10F659AF2BE712038E8522704 [5382AD48844A3473D4CBA87C85F2BAC2] GoodName=NBA Jam 99 (U) [f1] (PAL) CRC=61079876 32DB765E RefMD5=ADBE5CA10F659AF2BE712038E8522704 [7FEC099D1A989D5222D3F9E1A7770404] GoodName=NBA Live 2000 (E) (M4) [!] CRC=EB499C8F CD4567B6 Players=4 SaveType=None Mempak=Yes Rumble=Yes [FC47F85CC501C8C5BD9D0CA4DB48258F] GoodName=NBA Live 2000 (U) (M4) [!] CRC=5F25B0EE 6227C1DB Players=4 SaveType=None Mempak=Yes Rumble=Yes [226C19C8759314AC740420DDC3A34EB4] GoodName=NBA Live 99 (E) (M5) [!] CRC=CF84F45F 00E4F6EB Players=4 SaveType=None Mempak=Yes Rumble=Yes [DBE79AE6531B491B8F8EE8B2B814D665] GoodName=NBA Live 99 (U) (M5) [!] CRC=57F81C9B 1133FA35 Players=4 SaveType=None Mempak=Yes Rumble=Yes [7044E135E702B32DFCF13E688461967F] GoodName=NBA Live 99 (U) (M5) [b1] CRC=57F81C9B 1133FA35 RefMD5=DBE79AE6531B491B8F8EE8B2B814D665 [4DD6A2CF6091A92C43CE1B4A1B6F1556] GoodName=NBA Live 99 (U) (M5) [b2] CRC=57F81C9B 1133FA35 RefMD5=DBE79AE6531B491B8F8EE8B2B814D665 [5F46FC3780A50D5BB8FCB0F1C95686B0] GoodName=NBA Live 99 (U) (M5) [b3] CRC=57F81C9B 1133FA35 RefMD5=DBE79AE6531B491B8F8EE8B2B814D665 [A4111A6CDDBDE0A45489106F0DF0CA2B] GoodName=NBA Pro 98 (E) [!] CRC=ACDE962F B2CBF87F Players=4 SaveType=None Mempak=Yes Rumble=Yes [C5EBBDD41EAEA8BD02CF520640CCCCDF] GoodName=NBA Pro 99 (E) [!] CRC=8D1780B6 57B3B976 Players=4 SaveType=None Mempak=Yes Rumble=Yes [9A203506DB213F97FE28210AAF56F820] GoodName=NBA Pro 99 (E) [f1] (NTSC) CRC=356130AD 29367E56 RefMD5=C5EBBDD41EAEA8BD02CF520640CCCCDF [881E98B47F32093C330A8B0DAD6BB65D] GoodName=NBA Showtime - NBA on NBC (U) [!] CRC=3FFE80F4 A7C15F7E Players=4 SaveType=None Mempak=Yes CountPerOp=1 [76DB89759121710C416ECFB1736B5E39] GoodName=NBA Showtime - NBA on NBC (U) [f1] (Country Check) CRC=E78F66E6 754ABDF5 RefMD5=881E98B47F32093C330A8B0DAD6BB65D [760D5F0A578D65E68F5B4E8F64271C88] GoodName=NBA Showtime - NBA on NBC (U) [f1] (PAL) CRC=9CEED5BA 62A146D5 RefMD5=881E98B47F32093C330A8B0DAD6BB65D [A05D4FF483AF3F1C55BEDC455E7EDBBE] GoodName=NBC First Intro by CALi (PD) CRC=15DB95D4 77BC52D8 [325B9DCD5D23F269017C16E2BA62DEA3] GoodName=NBC-LFC Kings of Porn Vol 01 (PD) [a1] CRC=DD95F49D 2A9B8893 [88095C9BD22232383AF82235F03B2658] GoodName=NBC-LFC Kings of Porn Vol 01 (PD) CRC=AB9F8D97 95EAA766 RefMD5=325B9DCD5D23F269017C16E2BA62DEA3 [CE915D72FEA86AA99D9C015661A3D768] GoodName=NBCG Special Edition (PD) CRC=011F98B2 1E1C8263 [8CE55DA21D0FA7B41646A1F3F45F57A1] GoodName=NBCG's Kings of Porn Demo (PD) CRC=61A5FCEE B59FD8D3 [C0ABE398CBC45EC90D03C5ADC26C1065] GoodName=NBCG's Tag Gallery 01 by CALi (PD) CRC=15AA9AF2 FF33D333 [F27300E1883EA849A69567D3AEDC5F56] GoodName=NBCrew 2 Demo (PD) CRC=84067BAC 87FBA623 [4CF0249345388BB098F79DDCD7A00798] GoodName=NEO Myth N64 Menu Demo V0.1 (PD) CRC=6539E529 1FE8CE01 [7F6C5E71711DEC81E77CCF71060F67CA] GoodName=NFL Blitz (U) [!] CRC=D094B170 D7C4B5CC Players=2 SaveType=None Mempak=Yes Rumble=Yes [F0A1CC3D1D99A60F35D37DDCCF43CABB] GoodName=NFL Blitz (U) [f1] (PAL) CRC=3D6044AB 46768D77 RefMD5=7F6C5E71711DEC81E77CCF71060F67CA [7E856FA8F743900FEBA5A4E28C234AF7] GoodName=NFL Blitz - Special Edition (U) [!] CRC=30EAD54F 31620BF6 Players=4 SaveType=None Mempak=Yes Rumble=Yes [BA49514441023722F02D41C62612F6C3] GoodName=NFL Blitz 2000 (U) (V1.0) [!] CRC=15A00969 34E5A285 Players=4 SaveType=None Mempak=Yes Rumble=Yes [DDBE4248EA34E11C091A975776042670] GoodName=NFL Blitz 2000 (U) (V1.0) [f1] (PAL) CRC=FEB72E1D 5BD2C925 RefMD5=BA49514441023722F02D41C62612F6C3 [DD96BB80E652CD1CF23CA4B8294BA7B5] GoodName=NFL Blitz 2000 (U) (V1.1) [!] CRC=5B755842 6CA39C7A RefMD5=BA49514441023722F02D41C62612F6C3 [E4EDD73CB036C6B143CEE9AEEED60341] GoodName=NFL Blitz 2001 (U) [!] CRC=36FA35EB E85E2E36 Players=4 SaveType=None Mempak=Yes Rumble=Yes [D13A38B9639CF1944FE7024E4C58739D] GoodName=NFL Blitz 2001 (U) [f1] (PAL-NTSC) CRC=EB7709E2 27A91031 RefMD5=E4EDD73CB036C6B143CEE9AEEED60341 [75C0121D84915BF5C1FBD389CF9F9C17] GoodName=NFL Quarterback Club 2000 (E) [!] CRC=88BD5A9E E81FDFBF Players=4 SaveType=None Mempak=Yes Rumble=Yes [EC18E3131040842E32EBAB66C7496EBD] GoodName=NFL Quarterback Club 2000 (U) [!] CRC=E3AB4ED0 83040DD2 Players=4 SaveType=None Mempak=Yes Rumble=Yes [55224F1148F873A689604F2DC6432682] GoodName=NFL Quarterback Club 2000 (U) [b1] CRC=E3AB4ED0 83040DD2 RefMD5=EC18E3131040842E32EBAB66C7496EBD [604E2FB5AC9A26A81883A4C19037862A] GoodName=NFL Quarterback Club 2000 (U) [b2] CRC=E3AB4ED0 83040DD2 RefMD5=EC18E3131040842E32EBAB66C7496EBD [FD2CBDEA0992452B52E2803224232D12] GoodName=NFL Quarterback Club 2001 (U) [!] CRC=28784622 FFB22985 Players=4 SaveType=None Mempak=Yes Rumble=Yes [A18CA5DBC85668667AA467ADD6A62B39] GoodName=NFL Quarterback Club 98 (E) [!] CRC=4B629EF4 99B21D9B Players=4 SaveType=None Mempak=Yes Rumble=Yes [37954BA9067840FAFF851092043F0435] GoodName=NFL Quarterback Club 98 (E) [o1] CRC=4B629EF4 99B21D9B RefMD5=A18CA5DBC85668667AA467ADD6A62B39 [709F966C30CE6DF1833E95740A5A2AB2] GoodName=NFL Quarterback Club 98 (U) [!] CRC=D89BE2F8 99C97ADF Players=4 SaveType=None Mempak=Yes Rumble=Yes [B39D12910D12498605A9F793C29866BE] GoodName=NFL Quarterback Club 98 (U) [b1] CRC=D89BE2F8 99C97ADF RefMD5=709F966C30CE6DF1833E95740A5A2AB2 [8A47091F443117BFA629B0B29D4450C6] GoodName=NFL Quarterback Club 98 (U) [o1] CRC=D89BE2F8 99C97ADF RefMD5=709F966C30CE6DF1833E95740A5A2AB2 [7EC0484C2BA6AA9F0A45D7AC1F4117DA] GoodName=NFL Quarterback Club 99 (E) [!] CRC=52A3CF47 4EC13BFC Players=4 SaveType=None Mempak=Yes Rumble=Yes [EBDC155D7462F8C73DB4730C6BF4010D] GoodName=NFL Quarterback Club 99 (E) [b1] CRC=52A3CF47 4EC13BFC RefMD5=7EC0484C2BA6AA9F0A45D7AC1F4117DA [928869D1CE001B813BA908DFE18D7F94] GoodName=NFL Quarterback Club 99 (U) [!] CRC=BE76EDFF 20452D09 Players=4 SaveType=None Mempak=Yes Rumble=Yes [B7E41D34D209B6CFA92E3D622F911C4E] GoodName=NHL 99 (E) [!] CRC=287D601E ABF4F8AE Players=4 SaveType=None Mempak=Yes Rumble=Yes [A62FA044BCB5507D358424ABDA6419DB] GoodName=NHL 99 (U) [!] CRC=591A806E A5E6921D Players=4 SaveType=None Mempak=Yes Rumble=Yes [349F61F9747F2D2098F305924C97A1BF] GoodName=NHL Blades of Steel '99 (U) [!] CRC=82EFDC30 806A2461 Players=4 SaveType=None Mempak=Yes Rumble=Yes [9FF8AFF664781384A5FC01449DC5AD8D] GoodName=NHL Blades of Steel '99 (U) [f1] (PAL) CRC=82EFDC30 806A2461 RefMD5=349F61F9747F2D2098F305924C97A1BF [46476A5626CD99B3749AC1EE1E234FAC] GoodName=NHL Breakaway 98 (E) [!] CRC=29CE7692 71C58579 Players=4 SaveType=None Mempak=Yes Rumble=Yes [43D788E7CAEA1146228B763C13E8E740] GoodName=NHL Breakaway 98 (E) [f1] (NTSC) CRC=C5F020F3 27B2CA73 RefMD5=46476A5626CD99B3749AC1EE1E234FAC [5CB521B928FB94E84F4E0E49B6E25CD4] GoodName=NHL Breakaway 98 (E) [h1C] CRC=29CE7692 71C58579 RefMD5=46476A5626CD99B3749AC1EE1E234FAC [75F197DEF1D084534857493582D84E73] GoodName=NHL Breakaway 98 (E) [o1] CRC=29CE7692 71C58579 RefMD5=46476A5626CD99B3749AC1EE1E234FAC [9EA99ED5E27E35976E8266FACF5064CD] GoodName=NHL Breakaway 98 (E) [o1][h1C] CRC=29CE7692 71C58579 RefMD5=46476A5626CD99B3749AC1EE1E234FAC [B62076FA1421B8E7FDEC2B4F8A910EA3] GoodName=NHL Breakaway 98 (U) [!] CRC=6DFDCDC3 4DE701C8 Players=4 SaveType=None Mempak=Yes Rumble=Yes [1D178B74A163711CA9C06327F3B709CF] GoodName=NHL Breakaway 98 (U) [h1C] CRC=6DFDCDC3 4DE701C8 RefMD5=B62076FA1421B8E7FDEC2B4F8A910EA3 [BA863554222E503BAC7F01FA4888BE8A] GoodName=NHL Breakaway 98 (U) [o1] CRC=6DFDCDC3 4DE701C8 RefMD5=B62076FA1421B8E7FDEC2B4F8A910EA3 [5DFB0200B6698CEF2BA2A1775BA252A8] GoodName=NHL Breakaway 98 (U) [o1][h1C] CRC=6DFDCDC3 4DE701C8 RefMD5=B62076FA1421B8E7FDEC2B4F8A910EA3 [4BA95AA97ECFEE36051EBE0A9024EEE8] GoodName=NHL Breakaway 99 (E) [!] CRC=874621CB 0031C127 Players=4 SaveType=None Mempak=Yes Rumble=Yes [417AFE49BF73F3663C5F5F0AF897FC79] GoodName=NHL Breakaway 99 (E) [b1] CRC=874621CB 0031C127 RefMD5=4BA95AA97ECFEE36051EBE0A9024EEE8 [AF1D07679014760B88923A4827658CAF] GoodName=NHL Breakaway 99 (U) [!] CRC=441768D0 7D73F24F Players=4 SaveType=None Mempak=Yes Rumble=Yes [07C102E1ADF6190E05EF3C897090DFD3] GoodName=NHL Breakaway 99 (U) [b1] CRC=441768D0 7D73F24F RefMD5=AF1D07679014760B88923A4827658CAF [1614E1C0BEBFAA0855DA9990EF859A68] GoodName=NHL Breakaway 99 (U) [b2] CRC=F0C5F320 B22773CA RefMD5=AF1D07679014760B88923A4827658CAF [A61854CF27E536C8513174FAEF08DFCB] GoodName=NHL Pro 99 (E) [!] CRC=A9895CD9 7020016C Players=4 SaveType=None Mempak=Yes Rumble=Yes [BCEE33DC37C872A188A72EEAF41369F4] GoodName=NHL Pro 99 (E) [o1] CRC=A9895CD9 7020016C RefMD5=A61854CF27E536C8513174FAEF08DFCB [3E217E9C70608E56DA20FEAC9A458EFC] GoodName=NUTS - Nintendo Ultra64 Test Suite by MooglyGuy (PD) CRC=EFDAFEA4 E38D6A80 [B935B87F3DCCA8AEEB6A9365124846DC] GoodName=Nagano Winter Olympics '98 (E) [!] CRC=6D452016 713C09EE Players=4 SaveType=None Mempak=Yes [D5CE3A477104213499FFEA3A0BCB1555] GoodName=Nagano Winter Olympics '98 (E) [h1C] CRC=6D452016 713C09EE RefMD5=B935B87F3DCCA8AEEB6A9365124846DC [D4D046F74BE40E067875701751647178] GoodName=Nagano Winter Olympics '98 (E) [o1] CRC=6D452016 713C09EE RefMD5=B935B87F3DCCA8AEEB6A9365124846DC [C17F78A103D99B21533F0C1566378EF6] GoodName=Nagano Winter Olympics '98 (U) [!] CRC=8D2BAE98 D73725BF Players=4 SaveType=None Mempak=Yes [48782BC5728F38099B21E8B281ADC1CA] GoodName=Nagano Winter Olympics '98 (U) [T+Ita_HRG] CRC=8D2BAE98 D73725BF RefMD5=C17F78A103D99B21533F0C1566378EF6 [63C2A327F7195FF43229738D315CF51C] GoodName=Nagano Winter Olympics '98 (U) [b1] CRC=8D2BAE98 D73725BF RefMD5=C17F78A103D99B21533F0C1566378EF6 [2131A0AE317D243618A1E90E2153215C] GoodName=Nagano Winter Olympics '98 (U) [b2] CRC=8D2BAE98 D73725BF RefMD5=C17F78A103D99B21533F0C1566378EF6 [96F8B3E6F6B91923462B02554025C403] GoodName=Nagano Winter Olympics '98 (U) [h1C] CRC=8D2BAE98 D73725BF RefMD5=C17F78A103D99B21533F0C1566378EF6 [C9F607002F051F087F4FD68B8B77B4D3] GoodName=Nagano Winter Olympics '98 (U) [o1] CRC=8D2BAE98 D73725BF RefMD5=C17F78A103D99B21533F0C1566378EF6 [A8CDD4C61604B9C279861289ED7C4542] GoodName=Nagano Winter Olympics '98 (U) [o2] CRC=8D2BAE98 D73725BF RefMD5=C17F78A103D99B21533F0C1566378EF6 [E61251D2819E3BF3A9C0B95329F60F70] GoodName=Namco Museum 64 (U) [!] CRC=5129B6DA 9DEF3C8C Players=2 SaveType=None Mempak=Yes [EAD417FF24EAB32E2BF45CEA9200D425] GoodName=Namco Museum 64 (U) [f1] (PAL) CRC=A896AB1D 27E73688 RefMD5=E61251D2819E3BF3A9C0B95329F60F70 [1F455908263C2745E4100C0319B0F4C0] GoodName=Namco Museum 64 (U) [o1] CRC=5129B6DA 9DEF3C8C RefMD5=E61251D2819E3BF3A9C0B95329F60F70 [98C0A62FE977A8202F558E5F2E2A5A60] GoodName=Namco Museum 64 (U) [o1][f1] (PAL) CRC=AE21569D 5A5BC572 RefMD5=E61251D2819E3BF3A9C0B95329F60F70 [E001B32D05D36EDB7E8A99B7C7E4C789] GoodName=Namco Museum 64 (U) [t1] CRC=A864A921 99082CD0 RefMD5=E61251D2819E3BF3A9C0B95329F60F70 [CB7C26C00AB065F372DDA9950260BCBA] GoodName=Namp64 - N64 MP3-Player by Obsidian (PD) CRC=C4855DA2 83BBA182 [5E1940CA1236A76E8F2D15DE0414AE55] GoodName=Neon Genesis Evangelion (J) [!] CRC=147E0EDB 36C5B12C Players=1 SaveType=Eeprom 16KB Rumble=Yes [34F5F402064F76B375771EBF80DBE734] GoodName=Neon Genesis Evangelion (J) [b1] CRC=147E0EDB 36C5B12C RefMD5=5E1940CA1236A76E8F2D15DE0414AE55 [4374A8342E612951148136194053967C] GoodName=Neon Genesis Evangelion (J) [b2] CRC=147E0EDB 36C5B12C RefMD5=5E1940CA1236A76E8F2D15DE0414AE55 [DB2A3682451F1A6CEAFBF44792D4A5A7] GoodName=Neon Genesis Evangelion (J) [b3] CRC=147E0EDB 36C5B12C RefMD5=5E1940CA1236A76E8F2D15DE0414AE55 [7FE719DDE2CF1C9227BB9650AFA21A4B] GoodName=Neon Genesis Evangelion (J) [f1] (PAL) CRC=AC000A2B 38E3A55C RefMD5=5E1940CA1236A76E8F2D15DE0414AE55 [4723E4599E37DB86B9BBD2FD18BFDB8F] GoodName=Neon64 First Public Beta Release V2 by Halley's Comet Software (PD) CRC=3B18F6F9 8C4BE567 [B7A1D8B4BD19C710E4B9DAAC5590E301] GoodName=Neon64 First Public Beta Release V3 by Halley's Comet Software (PD) CRC=4F707583 2D6326AA [E062DD1E3C8B7A266FA018C6FBC17455] GoodName=Neon64 First Public Beta Release by Halley's Comet Software (PD) CRC=3B18F4F7 82BFB2B3 [5E4DABADB17439A1F2122F5E2C141FD1] GoodName=Neon64 V1.0 by Halley's Comet Software (PD) CRC=E87D098B 4C70341C [83CB0CE82555FE733A121C052BDF3662] GoodName=Neon64 V1.1 by Halley's Comet Software (PD) [o2] CRC=AE809DD0 0A99B360 [CA02C44E41D6A7CD51785DB0981C54C7] GoodName=Neon64 V1.1 by Halley's Comet Software (PD) CRC=ED42A2D4 7A71CD91 [08EBE38D2EA9BCACED94805BBBCE7192] GoodName=Neon64 V1.2 by Halley's Comet Software (PD) [o1] CRC=7040B082 1BE98D03 [D54FB5A78A2A9189D01ACF20A6043F4B] GoodName=Neon64 V1.2 by Halley's Comet Software (PD) CRC=ED42A2D4 7A71CD91 [43475AA0D793806C23D8645F49F6656D] GoodName=Neon64 V1.2a by Halley's Comet Software (PD) [b1] CRC=A9F7BB48 D63C5F56 [38D04A1C192D591940437B6BAF628119] GoodName=Neon64 V1.2a by Halley's Comet Software (PD) [o1] CRC=5AAD4E36 6625D1D2 [9FFA642B02C27D8E01EAB17B0F0F4251] GoodName=Neon64 V1.2a by Halley's Comet Software (PD) CRC=ED42A2D4 7A71CD91 [C4ECFEC66ECEEA23F39632AB6753300F] GoodName=New Tetris, The (E) [!] CRC=E61CFF0A CE1C0D71 Players=4 SaveType=SRAM Mempak=Yes [7A28179B00734C9AA0F0609FAFAAFD5F] GoodName=New Tetris, The (U) [!] CRC=2153143F 992D6351 Players=4 SaveType=SRAM Mempak=Yes [0B13983A634732FDE9D2D638C0A14C51] GoodName=New Tetris, The (U) [f1] (PAL) CRC=208A0427 DF465260 RefMD5=7A28179B00734C9AA0F0609FAFAAFD5F [99B35D7833DAEBCE199CDCC240E29FDF] GoodName=New Tetris, The (U) [f2] (PAL) CRC=208A0437 0E53FF5F RefMD5=7A28179B00734C9AA0F0609FAFAAFD5F [E2304DF5FF6B40E74FD5BF62655D3E57] GoodName=New Tetris, The (U) [f3] (PAL) CRC=43D67345 A60D5D3D RefMD5=7A28179B00734C9AA0F0609FAFAAFD5F [4116CF435DB315A2481AF8D1E9352FEB] GoodName=Nightmare Creatures (U) [!] CRC=2857674D CC4337DA Players=1 SaveType=None Mempak=Yes Rumble=Yes [60A2CFF1515D4C7902DDE32A6E01D411] GoodName=Nightmare Creatures (U) [b1] CRC=2857674D CC4337DA RefMD5=4116CF435DB315A2481AF8D1E9352FEB [68B478C274812450369DBF153CAD185D] GoodName=Nightmare Creatures (U) [b2] CRC=2857674D CC4337DA RefMD5=4116CF435DB315A2481AF8D1E9352FEB [FF02FE6A6FE7F6C31BCA6962E53A63CA] GoodName=Nightmare Creatures (U) [t1] CRC=AFDCF850 5CCD80DE RefMD5=4116CF435DB315A2481AF8D1E9352FEB [49198056DDEBB41B1A820A09289A2E3F] GoodName=Nightmare Creatures (U) [t2] CRC=AFDCF850 5CCD80DE RefMD5=4116CF435DB315A2481AF8D1E9352FEB [B04957D052EF850C5EDECE69DB7377B3] GoodName=Nintama Rantarou 64 Game Gallery (J) [!] CRC=CD3C3CDF 317793FA Players=4 CountPerOp=1 [66DB457B130D31A286A23D6E4DD9726E] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [!] CRC=67D20729 F696774C Status=3 Players=4 SaveType=SRAM Rumble=Yes CountPerOp=1 [B2DF29627E0219A9C14605F46803C94C] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [b1] CRC=67D20729 F696774C RefMD5=66DB457B130D31A286A23D6E4DD9726E [57CBADB75429AAFC0D7040DE69DC8D70] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [b2] CRC=88FFAB7D 298294A2 RefMD5=66DB457B130D31A286A23D6E4DD9726E [3D78B907657918C8C58EA002FEEE1D0F] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [b3] CRC=67D20729 F696774C RefMD5=66DB457B130D31A286A23D6E4DD9726E [4CFAED7DAD4EE592572964BA03D8C07E] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [f1] CRC=308BC746 A229B775 RefMD5=66DB457B130D31A286A23D6E4DD9726E [9C0E454CFFE65835AED12B39A8D9D6EC] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [f2] CRC=88FFAB7D 298294A2 RefMD5=66DB457B130D31A286A23D6E4DD9726E [9A27D420B43A908ECF4F28F859E1C541] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [f3] CRC=88FFAB7D 298294A2 RefMD5=66DB457B130D31A286A23D6E4DD9726E [053C515BEBE73391B4479A90A8EE93F9] GoodName=Nintendo All-Star! Dairantou Smash Brothers (J) [f4] (PAL) CRC=58886DD0 AD93BCB1 RefMD5=66DB457B130D31A286A23D6E4DD9726E [0AEE21A365F9450C258A59556F77EDB8] GoodName=Nintendo Family by CALi (PD) CRC=60E528A6 9500D4D3 [C10B51EEAC9F520419F23F95228C719A] GoodName=Nintendo On My Mind Demo by Kid Stardust (PD) CRC=6B2AFCC7 EEB27A34 [F79F17353DC5683AB60257462BE9D2FD] GoodName=Nintendo WideBoy 64 by SonCrap (PD) CRC=D1C6C55D F010EF52 [9EB9A0A45C2DD35DCB5A4A8A7FC4B151] GoodName=Nintro64 Demo by Lem (POM '98) (PD) [b1] CRC=4E01B4A6 C884D085 [497D1E0677395A921B6006BBF41EED04] GoodName=Nintro64 Demo by Lem (POM '98) (PD) CRC=4E01B4A6 C884D085 [898362D1F6E207818E8CDF88225017B6] GoodName=NuFan Demo by Kid Stardust (PD) [b1] CRC=FA7D3935 97AC54FC [9ED82C5E9B6BF204276B434C8B0F6892] GoodName=NuFan Demo by Kid Stardust (PD) CRC=FA7D3935 97AC54FC [710BA49EBD5C9A2B26653FAE93BD667A] GoodName=Nuclear Strike 64 (E) (M2) [!] CRC=8A97A197 272DF6C1 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [59C28E02BAF4065051C63EA51736892A] GoodName=Nuclear Strike 64 (E) (M2) [h1C] CRC=8A97A197 272DF6C1 RefMD5=710BA49EBD5C9A2B26653FAE93BD667A [D43C2E1938534363E56A22413B91D051] GoodName=Nuclear Strike 64 (G) [!] CRC=8F50B845 D729D22F Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [FFC584040D0D052FBAB4CB6C19245449] GoodName=Nuclear Strike 64 (U) [!] CRC=4998DDBB F7B7AEBC Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [76C8EFDD11F6D2E553055B801A022653] GoodName=Nuclear Strike 64 (U) [b1] CRC=4998DDBB F7B7AEBC RefMD5=FFC584040D0D052FBAB4CB6C19245449 [A3134DAE771ADDB83191422615DF8551] GoodName=Nuclear Strike 64 (U) [f1] (PAL) CRC=E6B339F6 22AE6901 RefMD5=FFC584040D0D052FBAB4CB6C19245449 [2B7370E6880F83C808A2CB9E7F33DC46] GoodName=Nuclear Strike 64 (U) [t1] CRC=FE5DC5D4 E1815BE5 RefMD5=FFC584040D0D052FBAB4CB6C19245449 [50C10082D0C077FDB5658EF5A6E3F54F] GoodName=Nushi Tsuri 64 (J) (V1.0) [!] CRC=D83BB920 CC406416 Players=1 Mempak=Yes Rumble=Yes Transferpak=Yes CountPerOp=1 [7412417C50A42427637575A3CD2E652E] GoodName=Nushi Tsuri 64 (J) (V1.0) [b1] CRC=24081000 AD880000 RefMD5=50C10082D0C077FDB5658EF5A6E3F54F [EEFD695B00354C5199DF348ECF404A0F] GoodName=Nushi Tsuri 64 (J) (V1.0) [b2] CRC=9ADD5DE5 451F0A65 RefMD5=50C10082D0C077FDB5658EF5A6E3F54F [C187BD285BA0E2D0EF5CFFEE44B367EE] GoodName=Nushi Tsuri 64 (J) (V1.0) [b3] CRC=D83BB920 CC406416 RefMD5=50C10082D0C077FDB5658EF5A6E3F54F [0B281D478B1B4FF9329B45EEB80D53F2] GoodName=Nushi Tsuri 64 (J) (V1.0) [b4] CRC=D83BB920 CC406416 RefMD5=50C10082D0C077FDB5658EF5A6E3F54F [FABCB3078EDE955C04A00479EE11C43F] GoodName=Nushi Tsuri 64 (J) (V1.0) [b5] CRC=49D83BB9 20CC4064 RefMD5=50C10082D0C077FDB5658EF5A6E3F54F [D2AF6993E4D657D00520C2CCE741480E] GoodName=Nushi Tsuri 64 (J) (V1.1) [!] CRC=C5F1DE79 5D4BEB6E Players=1 Mempak=Yes Rumble=Yes Transferpak=Yes CountPerOp=1 [828E0C399C0AA7E3B047859F4FAD3550] GoodName=Nushi Tsuri 64 - Shiokaze ni Notte (J) [b1] CRC=5B9A9618 4B86828E RefMD5=EEB69597E42E2F5D2914070ACF161B4F [A366BCBF8FF44D23A9450ECD8C71223C] GoodName=Nushi Tsuri 64 - Shiokaze ni Notte (J) [b2] CRC=5B9B1618 1B43C649 RefMD5=EEB69597E42E2F5D2914070ACF161B4F [EEB69597E42E2F5D2914070ACF161B4F] GoodName=Nushi Tsuri 64 - Shiokaze ni Notte (J) [!] CRC=5B9B1618 1B43C649 Players=1 Rumble=Yes Transferpak=Yes CountPerOp=1 [E2FB4F16A039A0E302D28ACA94D5D928] GoodName=O.D.T. (E) (M5) [!] CRC=E86415A6 98395B53 Players=1 Mempak=Yes Rumble=Yes [4116E492168AAFFF1BD3100C7B0AA28F] GoodName=O.D.T. (U) (M3) [!] CRC=2655BB70 667D9925 Players=1 Mempak=Yes Rumble=Yes [09BA01C6EC8B178A27FBEE3A9DEE8EB6] GoodName=Oerjan Intro by Oerjan (POM '99) (PD) CRC=7F2D025D 2B7DA4AD [E96FECBA52905DB14ADDAD7CFD61091F] GoodName=Off Road Challenge (E) [!] CRC=812289D0 C2E53296 Players=2 SaveType=None Mempak=Yes Rumble=Yes [F30DFECB19DBD82A2FD334A8A37B8D38] GoodName=Off Road Challenge (E) [b1] CRC=24081000 AD880000 RefMD5=E96FECBA52905DB14ADDAD7CFD61091F [1538A4235FDED9D65B98C25EDF6F9C0E] GoodName=Off Road Challenge (E) [b2] CRC=812289D0 C2E53296 RefMD5=E96FECBA52905DB14ADDAD7CFD61091F [AF7083FC0ABCFD5A2C6A5E971453D831] GoodName=Off Road Challenge (U) [!] CRC=319093EC 0FC209EF Players=2 SaveType=None Mempak=Yes Rumble=Yes [DC34F5AA26488352B4D025EDBF47FE39] GoodName=Off Road Challenge (U) [b1] CRC=319093EC 0FC209EF RefMD5=AF7083FC0ABCFD5A2C6A5E971453D831 [6F378FFB873C217675F4CDD00A0318D4] GoodName=Off Road Challenge (U) [b2] CRC=319093EC 0FC209EF RefMD5=AF7083FC0ABCFD5A2C6A5E971453D831 [D3BDAA50D6C0EFFF9D696C521B704376] GoodName=Off Road Challenge (U) [t1] CRC=698FE5E8 1D57B278 RefMD5=AF7083FC0ABCFD5A2C6A5E971453D831 [A45C39767D33AC21956A3D4E6C03CFA1] GoodName=Ogre Battle 64 - Person of Lordly Caliber (J) (V1.1) [!] CRC=0375CF67 56A93FAA Players=1 SaveType=SRAM [55CD360F12BE8063C9E7B6F59F268170 ] GoodName=Ogre Battle 64 - Person of Lordly Caliber (J) (V1.1) (VC) [!] CRC=0375CF67 56A93FAA Players=1 SaveType=SRAM [A3F64D34614A0B01B6A49AE4031ACBDF] GoodName=Ogre Battle 64 - Person of Lordly Caliber (J) (V1.1) [b1] CRC=0375CF67 56A93FAA RefMD5=A45C39767D33AC21956A3D4E6C03CFA1 [5468A2AC2E93AD3F49E9B271C8341CAC] GoodName=Ogre Battle 64 - Person of Lordly Caliber (J) (V1.1) [b1][o1] CRC=0375CF67 56A93FAA RefMD5=A45C39767D33AC21956A3D4E6C03CFA1 [7AF70073E7CFD8945E087A7FFD6D8348] GoodName=Ogre Battle 64 - Person of Lordly Caliber (J) (V1.1) [b2] CRC=0375CF67 56A93FAA RefMD5=A45C39767D33AC21956A3D4E6C03CFA1 [F666E020218392E52662FDDFA1EA4F21] GoodName=Ogre Battle 64 - Person of Lordly Caliber (U) (V1.0) [!] CRC=E6419BC5 69011DE3 Players=1 SaveType=SRAM Mempak=Yes [EBB4B4D2808DF427AAA3085A41B8A954] GoodName=Ogre Battle 64 - Person of Lordly Caliber (U) (V1.1) [!] CRC=0ADAECA7 B17F9795 Players=1 SaveType=SRAM Mempak=Yes [465DFD27DDAB4F5488F4DADC09B7F938] GoodName=Olympic Hockey Nagano '98 (E) (M4) [!] CRC=AE2D3A35 24F0D41A Players=4 SaveType=None Mempak=Yes [02AA0C059EC36145927353C8E617AA41] GoodName=Olympic Hockey Nagano '98 (E) (M4) [h1C] CRC=AE2D3A35 24F0D41A RefMD5=465DFD27DDAB4F5488F4DADC09B7F938 [8A964671C5A4F4FC62787F1F25EDD70D] GoodName=Olympic Hockey Nagano '98 (J) [!] CRC=90F43037 5C5370F5 Players=4 SaveType=None Mempak=Yes [9C99C6D9EA98A960056C531CB78EB35B] GoodName=Olympic Hockey Nagano '98 (U) [!] CRC=7EC22587 EF1AE323 Players=4 SaveType=None Mempak=Yes [8F9810383B86E86EC447F65D47CA74A7] GoodName=Olympic Hockey Nagano '98 (U) [T+Ita_cattivik66] CRC=7EC22587 EF1AE323 RefMD5=9C99C6D9EA98A960056C531CB78EB35B [7BD97D75D09E38996F82C6190780D447] GoodName=Olympic Hockey Nagano '98 (U) [b1] CRC=7EC22587 EF1AE323 RefMD5=9C99C6D9EA98A960056C531CB78EB35B [3A314CE9388E4178FD6FC9C74D5E7137] GoodName=Olympic Hockey Nagano '98 (U) [b2] CRC=7EC22587 EF1AE323 RefMD5=9C99C6D9EA98A960056C531CB78EB35B [CFCB20EACFCEAA43FDDBE05FB0D170D1] GoodName=Olympic Hockey Nagano '98 (U) [b3] CRC=7EC22587 EF1AE323 RefMD5=9C99C6D9EA98A960056C531CB78EB35B [3E973B5BBEF8B24A4C4D7C326955E71F] GoodName=Olympic Hockey Nagano '98 (U) [h1C] CRC=7EC22587 EF1AE323 RefMD5=9C99C6D9EA98A960056C531CB78EB35B [3796829F54958CE103DCF5E3E8EB80B4] GoodName=Onegai Monsters (J) [!] CRC=DC649466 572FF0D9 Players=4 Mempak=Yes [B19805B3DFECF85FEA7E04614362DC28] GoodName=Onegai Monsters (J) [b1] CRC=DC649466 572FF0D9 RefMD5=3796829F54958CE103DCF5E3E8EB80B4 [91CF1982F309BD73822165087DAD4371] GoodName=Operation WinBack (E) (M5) [!] CRC=D5898CAF 6007B65B Players=4 SaveType=None Mempak=Yes Rumble=Yes [F2DF4577D3749345F93BA0606BECA8DD] GoodName=PC-Engine 64 (POM '99) (PD) [t1] CRC=4B548E10 BB510803 [70FD44B722B55956BE86B660F153713D] GoodName=PC-Engine 64 (POM '99) (PD) CRC=9118F1B8 987DAC8C [52F4F3320607F3E8DD1A16A2F1BFBDB0] GoodName=PD Ultraman Battle Collection 64 (J) [!] CRC=F468118C E32EE44E Players=2 SaveType=Eeprom 16KB Mempak=Yes Transferpak=Yes [4FD424DF60F80EE7E362A9572049BA11] GoodName=PD Ultraman Battle Collection 64 (J) [b1] CRC=F468118C E32EE44E RefMD5=52F4F3320607F3E8DD1A16A2F1BFBDB0 [2755152E6168516F2224ADC6737B96F0] GoodName=PD Ultraman Battle Collection 64 (J) [f1] (PAL) CRC=37B52113 3A77A655 RefMD5=52F4F3320607F3E8DD1A16A2F1BFBDB0 [826AE85B4E74354EE378E8DC2AD33271] GoodName=PD Ultraman Battle Collection 64 (J) [f2] (PAL) CRC=170D4973 8FA23F51 RefMD5=52F4F3320607F3E8DD1A16A2F1BFBDB0 [0112FFAADA116D172ABCE136E9043A93] GoodName=PGA European Tour (E) (M5) [!] CRC=EE08C602 6BC2D5A6 Players=4 SaveType=Eeprom 4KB [2F6B0ACB7270F78C972F5E6D4C75B02B] GoodName=PGA European Tour (E) (M5) [f1] (NTSC) CRC=5243B915 BE7743B1 RefMD5=0112FFAADA116D172ABCE136E9043A93 [7DBA0D5D4279274AF07B0EF3EC3A84AD] GoodName=PGA European Tour (E) (M5) [f2] (NTSC) CRC=76515D11 42BF7875 RefMD5=0112FFAADA116D172ABCE136E9043A93 [617CECA1D2BEFFCE943EF832326898BF] GoodName=PGA European Tour (U) [!] CRC=B54CE881 BCCB6126 Players=4 SaveType=Eeprom 4KB [8E79EC6D9F8DB1C50100860BF4437462] GoodName=POMbaer Demo by Kid Stardust (POM '99) (PD) CRC=9D63C653 C26B460F [0BBE17EC2271DC293F1D2F4A7B0D61D4] GoodName=POMolizer Demo by Renderman (POM '99) (PD) CRC=EDAFD3C0 39EF3599 [D60046C23400BFEBD5B051F89E7F2F07] GoodName=Pachinko 365 Nichi (J) [!] CRC=74554B3B F4AEBCB5 Players=1 Mempak=Yes [2002438491F94C468CB487032AC4AA33] GoodName=Pachinko 365 Nichi (J) [b1] CRC=74554B3B F4AEBCB5 RefMD5=D60046C23400BFEBD5B051F89E7F2F07 [F38ECA581BF6944EA35E3A816AD472DF] GoodName=Pachinko 365 Nichi (J) [b2] CRC=74554B3B F4AEBCB5 RefMD5=D60046C23400BFEBD5B051F89E7F2F07 [FE38BB1EAA1C74BAF01847BDE64E7F9D] GoodName=Pamela Demo (PD) CRC=26AD85C5 F908A36B [3AAF74D7E6D560C9CB1331209AD00F22] GoodName=Pamela Demo - Resized (PD) CRC=26AD85C5 F908A36B [8F8F50AB00C4089AE32C6B9FEFD69543] GoodName=Paper Mario (Ch) (iQue) [!] [C4D652425AA4F2FC1D12564DF01F8A04] GoodName=Paper Mario (Ch) (V2) (iQue) (Manual) [!] [D9597922207298A87FA46878C017E6DA] GoodName=Paper Mario (Ch) (V4) (iQue) (Manual) [!] [A9BE6A493A680642D840F859A65816CA] GoodName=Paper Mario (E) (M4) [!] CRC=19AB29AF C71BCD28 Status=2 Players=1 SaveType=Flash RAM Rumble=Yes CountPerOp=1 [A722F8161FF489943191330BF8416496] GoodName=Paper Mario (U) [!] CRC=65EEE53A ED7D733C Status=2 Players=1 SaveType=Flash RAM Rumble=Yes CountPerOp=1 [8595BA0A0D2EA73944228BDED4A969AD] GoodName=Paper Mario (U) [T+Chi] CRC=85F5A08A EAC7053E RefMD5=A722F8161FF489943191330BF8416496 [B7F2EB7989C9C00096655D087D72EC51] GoodName=Paperboy (E) [!] CRC=AC976B38 C3A9C97A Players=1 SaveType=None Mempak=Yes Rumble=Yes [C4CBCB54B010A5A71FE5CAA391E5C25F] GoodName=Paperboy (U) [!] CRC=3E198D9E F2E1267E Players=1 SaveType=None Mempak=Yes Rumble=Yes [12827E2EF6EB1FF0F8AA494E671C3094] GoodName=Paperboy (U) [f1] (PAL) CRC=8952E61E AA89984C RefMD5=C4CBCB54B010A5A71FE5CAA391E5C25F [5DF3D21223F0DAFD0417998E9C1E7065] GoodName=Paperboy (U) [hI] CRC=89529B12 0853ED3B RefMD5=C4CBCB54B010A5A71FE5CAA391E5C25F [0451768553AB8CDD6C9CA37514E6C339] GoodName=Paperboy (U) [hI][f1] (PAL) CRC=8F00E51E 030C92C8 RefMD5=C4CBCB54B010A5A71FE5CAA391E5C25F [1F72E506250B16726E2C5A629CAE8E0F] GoodName=Paperboy (U) [hI][t1] CRC=8632071E 637E1042 RefMD5=C4CBCB54B010A5A71FE5CAA391E5C25F [DF2A6A2446E8E01375ADE872A8F93366] GoodName=Paperboy (U) [t1] CRC=8632071E 637E1042 RefMD5=C4CBCB54B010A5A71FE5CAA391E5C25F [D78E10C6B3E98F3B32FE0F23ED72DB42] GoodName=Parlor! Pro 64 - Pachinko Jikki Simulation Game (J) [!] CRC=CFE2CB31 4D6B1E1D Players=1 SaveType=Eeprom 16KB Mempak=Yes [6DF573EE08C4577BBBF117B813D93B19] GoodName=Pause Demo by RedboX (PD) CRC=7D1727F1 6C6B83EB [20DA62ECE553EDE84D02283174BECC8F] GoodName=Penny Racers (E) [!] CRC=C83CEB83 FDC56219 Status=3 Players=4 SaveType=Eeprom 4KB Mempak=Yes [B6DF5A75CED54DFEE0E29BCE9ABD0AAF] GoodName=Penny Racers (E) [h1C] CRC=C83CEB83 FDC56219 RefMD5=20DA62ECE553EDE84D02283174BECC8F [6AE97EC4933A13C153A281DC8B68A0D9] GoodName=Penny Racers (E) [h2C] CRC=C83CEB83 FDC56219 RefMD5=20DA62ECE553EDE84D02283174BECC8F [518B14054A667A3B9E0B72D3BF784E41] GoodName=Penny Racers (U) [!] CRC=73ABB1FB 9CCA6093 Players=4 Status=3 SaveType=Eeprom 4KB Mempak=Yes [26F033C7716A10755A3D22C62ACF6851] GoodName=Penny Racers (U) [hI] CRC=AB5E61C8 A2FA7596 RefMD5=518B14054A667A3B9E0B72D3BF784E41 [D9B5CD305D228424891CE38E71BC9213] GoodName=Perfect Dark (E) (M5) [!] CRC=E4B08007 A602FF33 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes Transferpak=Yes [9E6D80933B63B183CCBD8B5F6543DCAD] GoodName=Perfect Dark (E) (M5) [b1] CRC=E4B08007 A602FF33 RefMD5=D9B5CD305D228424891CE38E71BC9213 [AD2DE210A3455BA5EC541F0C78D91444] GoodName=Perfect Dark (E) (Debug) (2000-04-26) [!] CRC=F9864452 890A5EA3 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes Transferpak=Yes [538D2B75945EAE069B29C46193E74790] GoodName=Perfect Dark (J) [!] CRC=96747EB4 104BB243 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes Transferpak=Yes [7F4171B0C8D17815BE37913F535E4E93] GoodName=Perfect Dark (U) (V1.0) [!] CRC=DDF460CC 3CA634C0 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes Transferpak=Yes [BF167523E079C57DCCA880A6F38889F2] GoodName=Perfect Dark (U) (V1.0) [f1] (PAL) CRC=65264217 7FB64F7F RefMD5=7F4171B0C8D17815BE37913F535E4E93 [E03B088B6AC9E0080440EFED07C1E40F] GoodName=Perfect Dark (U) (V1.1) [!] CRC=41F2B98F B458B466 SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes Transferpak=Yes [AA93F4DF16FCEADA399A749F5AD2F273] GoodName=Perfect Dark (U) (Debug) (2000-03-22) [!] CRC=2CE75AEF E16825BC SaveType=Eeprom 16KB Players=4 Mempak=Yes Rumble=Yes Transferpak=Yes [5D72155E00Bf2CAB41B0F4A2f2E09C61] GoodName=Perfect Dark Plus CRC=FB453D58 AD565422 RefMD5=E03B088B6AC9E0080440EFED07C1E40F [E0BCB2758EDF0AC6AB7DB36D98E1E57C] GoodName=Pikachu Genki Dechu (J) [!] CRC=3F245305 FC0B74AA Players=1 SaveType=Eeprom 4KB Rumble=Yes AiDmaModifier=88 [D0AE6C07AC0481EBA5FF9CE798A69574] GoodName=Pikachu Genki Dechu (J) [b1] CRC=3F245305 FC0B74AA RefMD5=E0BCB2758EDF0AC6AB7DB36D98E1E57C [3FCD4969F9A080BD2BCB913EC5D7A3BD] GoodName=Pilotwings 64 (E) (M3) [!] CRC=1AA05AD5 46F52D80 Players=1 SaveType=Eeprom 4KB CountPerOp=3 [F21E2A3A05ACF49586F32DCE5C449FE4] GoodName=Pilotwings 64 (E) (M3) [b1] CRC=1AA05AD5 46F52D80 RefMD5=3FCD4969F9A080BD2BCB913EC5D7A3BD [987682CC63777221B938CC465607BD8C] GoodName=Pilotwings 64 (E) (M3) [b2] CRC=1AA05AD5 46F52D80 RefMD5=3FCD4969F9A080BD2BCB913EC5D7A3BD [99FD0E1CBA30C18C869F2DE98678CD16] GoodName=Pilotwings 64 (E) (M3) [h1C] CRC=1AA05AD5 46F52D80 RefMD5=3FCD4969F9A080BD2BCB913EC5D7A3BD [E8E6EC0692009009F5DCA6827B21F59A] GoodName=Pilotwings 64 (J) [!] CRC=09CC4801 E42EE491 Players=1 SaveType=Eeprom 4KB CountPerOp=3 [2740F1B89CE7D78A5D31CF60C97A0C11] GoodName=Pilotwings 64 (J) [b1] CRC=09CC4801 E42EE491 RefMD5=E8E6EC0692009009F5DCA6827B21F59A [8B346182730CEAFFE5E2CCF6D223C5EF] GoodName=Pilotwings 64 (U) [!] CRC=C851961C 78FCAAFA Players=1 SaveType=Eeprom 4KB CountPerOp=3 [E28F8F19E56CC6C7A0F3A3286AEB60C1] GoodName=Pilotwings 64 (U) [h1C] CRC=C851961C 78FCAAFA RefMD5=8B346182730CEAFFE5E2CCF6D223C5EF [F69DE158BC76416B4C6C4704B15B6EB0] GoodName=Pilotwings 64 (U) [t1] CRC=70478A35 F9897402 RefMD5=8B346182730CEAFFE5E2CCF6D223C5EF [BE9E0C9D509AAB0C72F7788D6BE3B443] GoodName=Pip's Pong by Mr. Pips (PD) [b1] CRC=D072CFE7 CE134788 [E821B540A91B7BF088E52ABC02A5CC9A] GoodName=Pip's Pong by Mr. Pips (PD) CRC=D072CFE7 CE134788 [63CBABEF9069FE3375A7726C89E9E25D] GoodName=Pip's Porn Pack 1 by Mr. Pips (PD) CRC=D851B920 F3D6C0CE [3DF1646CC28C04133B3CB5EB143AE016] GoodName=Pip's Porn Pack 2 by Mr. Pips (POM '99) (PD) CRC=BF9D0FB0 981C22D1 [547CF20308F2CE2CE5B5310A5E555113] GoodName=Pip's Porn Pack 3 by Mr. Pips (PD) CRC=EA2A6A75 52B2C00F [5D144D323785818A9BD5C667A5567BBD] GoodName=Pip's RPGs Beta 12 by Mr. Pips (PD) CRC=3CB8AAB8 05C8E573 [EFBCB657A3B05B5CB080FD628B852BD0] GoodName=Pip's RPGs Beta 14 by Mr. Pips (PD) CRC=56563C89 C803F77B [C6FAAC42045BE1AF769EC52CEA6DED52] GoodName=Pip's RPGs Beta 15 by Mr. Pips (PD) CRC=AFBBB9D5 8EE82954 [10A28DF32D06B7D3D9B14091AC9D2E14] GoodName=Pip's RPGs Beta 2 by Mr. Pips (PD) CRC=DAD7F751 8B6322F0 [6402498E891455FFB86C95AD8ABB87F6] GoodName=Pip's RPGs Beta 3 by Mr. Pips (PD) CRC=C830954A 29E257FC [10E62952244834E0B52AF32898DE8D9F] GoodName=Pip's RPGs Beta 6 by Mr. Pips (PD) CRC=7194B65B 9DE67E7D [35FAB2CC64E0E808EB629A25542C7326] GoodName=Pip's RPGs Beta 7 by Mr. Pips (PD) CRC=DB363DDA 50C1C2A5 [9E35B55606BDF4C77A1E817CE503A951] GoodName=Pip's RPGs Beta x (PD) [a1] CRC=668FA336 2C67F3AC [F8D6C5ABA62FC302C2848C53104E2683] GoodName=Pip's RPGs Beta x (PD) CRC=BB787C13 78C1605D [45CDCBCB7159EBAE1ED4D7AAE70749E0] GoodName=Pip's Tic Tak Toe by Mark Pips (PD) CRC=6459533B 7E22B56C [99D711AB6DFD36121E5C23C1DBA78C01] GoodName=Pip's World Game 1 by Mr. Pips (PD) [b1] CRC=762C75D1 AA09C759 [4D28DDB5B93EA302EE9F27805DE1B46F] GoodName=Pip's World Game 1 by Mr. Pips (PD) CRC=762C75D1 AA09C759 [BBF5060E64BD0201954E65BD281EC486] GoodName=Pip's World Game 2 by Mr. Pips (PD) [b1] CRC=FC051819 A46A48F6 [9358AA90887FC31C45BC2B849C37D6A0] GoodName=Pip's World Game 2 by Mr. Pips (PD) CRC=FC051819 A46A48F6 [9C1B750A2F9DFC53361F72F4BFB647A7] GoodName=Pipendo by Mr. Pips (PD) CRC=45627CED 28005F9C [1D7CFC7CDB5A0E1B69B1DC2E58A4F192] GoodName=Planet Console Intro (PD) CRC=1077590A B537FDA2 [83B75800690AF27800DF362697E5205E] GoodName=Plasma Demo (PD) [a1] CRC=7D1727F1 6C6B83EB [E27C00C2114A56D18DD27B426193B79C] GoodName=Plasma Demo (PD) CRC=E9F52336 6BEFAA5F [FBDD74ED68E6A0CD734562D56CCB752D] GoodName=Pocket Monsters Snap (J) [!] CRC=EC0F690D 32A7438C Players=1 SaveType=Flash RAM CountPerOp=1 [33FDAB9712D9FEA793A3AE44293999C3] GoodName=Pocket Monsters Snap (J) (VC) [!] CRC=E0044E9E CD659D0D RefMD5=FBDD74ED68E6A0CD734562D56CCB752D [42CC0FE1442B0A498DFD8F743179C51A] GoodName=Pocket Monsters Snap (J) [b1] CRC=BB2D10F8 B8ED4D23 RefMD5=FBDD74ED68E6A0CD734562D56CCB752D [76AE2B6F38E611683ACA3B87D1B3D5CE] GoodName=Pocket Monsters Snap (J) [f1] CRC=BB2D10F8 B8ED4D23 RefMD5=FBDD74ED68E6A0CD734562D56CCB752D [CCA8D3874996A78C3B5828E7A66AC916] GoodName=Pocket Monsters Snap (J) [f2] (GameShark) CRC=412D7090 CEDABAC3 RefMD5=FBDD74ED68E6A0CD734562D56CCB752D [C46E087D966A35095DF96799B0B4FFAE] GoodName=Pocket Monsters Stadium (J) [!] CRC=665E8259 D098BD1D Players=2 SaveType=SRAM Transferpak=Yes [B43B3C7A3D2149FEEDC8BA3B8198BE5D] GoodName=Pocket Monsters Stadium (J) [b1] CRC=665E8259 D098BD1D RefMD5=C46E087D966A35095DF96799B0B4FFAE [D0698135C4A74CDEA8374DA0BD15DFDB] GoodName=Pocket Monsters Stadium (J) [b2] CRC=58FBD28F FEB595F0 RefMD5=C46E087D966A35095DF96799B0B4FFAE [1A5D6FBF59D1639AF71B61410553AB04] GoodName=Pocket Monsters Stadium (J) [f1] (Boot-PAL) CRC=58FBD28F FEB595F0 RefMD5=C46E087D966A35095DF96799B0B4FFAE [9BBC3945F526C8329710824C29FFC040] GoodName=Pocket Monsters Stadium (J) [f2] (Boot) CRC=76AF28D8 64A07F55 RefMD5=C46E087D966A35095DF96799B0B4FFAE [2449BB712A64E3363A6CBD56F5ADEDA5] GoodName=Pocket Monsters Stadium 2 (J) [!] CRC=63775886 5FB80E7B SaveType=Flash RAM Players=4 Transferpak=Yes [907403B12D2AD59A0F186A1632AE39B9] GoodName=Pocket Monsters Stadium 2 (J) [f1] CRC=FE667A12 0D2195AD RefMD5=2449BB712A64E3363A6CBD56F5ADEDA5 [3F39C01455B585CAEB2DF8A09765D0B3] GoodName=Pocket Monsters Stadium 2 (J) [f2] CRC=FE667A12 0D2195AD RefMD5=2449BB712A64E3363A6CBD56F5ADEDA5 [DC8F45A200FED15C3B0BD97A2F52ACA5] GoodName=Pocket Monsters Stadium 2 (J) [f3] CRC=058381EF 6A36FEC6 RefMD5=2449BB712A64E3363A6CBD56F5ADEDA5 [E5D7B56B5EDBD8575ECEB9E5ECCF4A00] GoodName=Pocket Monsters Stadium 2 (J) [f4] CRC=FE667A12 0D2195AD RefMD5=2449BB712A64E3363A6CBD56F5ADEDA5 [A17AADCC962393D476EDC321E59C504B] GoodName=Pocket Monsters Stadium Kin Gin (J) [!] CRC=EE4FD7C2 9CF1D938 Players=4 SaveType=Flash RAM Transferpak=Yes [2EF9FA16DE2A09EA15B6289447F40490] GoodName=Pokemon Puzzle League (E) [!] CRC=4A1CD153 D830AEF8 Players=2 SaveType=Flash RAM [FBF566693BCA3145D86DF34D18DCDD43] GoodName=Pokemon Puzzle League (E) (VC) [!] CRC=4A1CD153 D830AEF8 Players=2 SaveType=Flash RAM [A3BA044DFC00BB766B4B2BFB9D4B5BE9] GoodName=Pokemon Puzzle League (F) [!] CRC=3EB2E6F3 062F9EFE Players=2 SaveType=Flash RAM [866D401C51CC05A3188C9A2D4E7BFEE5] GoodName=Pokemon Puzzle League (F) (VC) [!] CRC=3EB2E6F3 062F9EFE Players=2 SaveType=Flash RAM [000364BAC80E41D9060A31A5923874B7] GoodName=Pokemon Puzzle League (G) [!] CRC=7A4747AC 44EEEC23 Players=2 SaveType=Flash RAM [45B507AAAF0CCDB6EFE3CD717F0DDB95] GoodName=Pokemon Puzzle League (G) (VC) [!] CRC=7A4747AC 44EEEC23 Players=2 SaveType=Flash RAM [E722576A15182CFED6782379CE4BC8BE] GoodName=Pokemon Puzzle League (U) [!] CRC=19C553A7 A70F4B52 Players=2 SaveType=Flash RAM [D6F58B98115E78D841089074401AE524] GoodName=Pokemon Puzzle League (U) (VC) [!] CRC=19C553A7 A70F4B52 Players=2 SaveType=Flash RAM [DC09E2685EB95471311E57B3605F4894] GoodName=Pokemon Puzzle League (U) [t1] CRC=E1AAA925 27C9C94B RefMD5=E722576A15182CFED6782379CE4BC8BE [D5EDC7B884DFBA7CF4AC4CDFA8AC64A4] GoodName=Pokemon Puzzle League (U) [t2] CRC=AAE125A9 C9274BC9 RefMD5=E722576A15182CFED6782379CE4BC8BE [E5A0CA3DC54B38EA7FCD927E3CFFAD3B] GoodName=Pokemon Snap (A) [!] CRC=7BB18D40 83138559 Players=1 SaveType=Flash RAM CountPerOp=1 [A88FCF3FF00F21D3CEC44D2E0FAAAAD8] GoodName=Pokemon Snap (A) [f1] (GameShark) CRC=F795ACE1 8DEDE03C RefMD5=E5A0CA3DC54B38EA7FCD927E3CFFAD3B [F2A8106403D2BF9350BFEAB08689D54A] GoodName=Pokemon Snap (E) [!] CRC=4FF5976F ACF559D8 Players=1 SaveType=Flash RAM CountPerOp=1 [E9028F9CCC307806695DD81742D05D5D] GoodName=Pokemon Snap (F) [!] CRC=BA6C293A 9FAFA338 Players=1 SaveType=Flash RAM CountPerOp=1 [5FA70A63E352EA804607999674381749] GoodName=Pokemon Snap (F) [b1] CRC=BA6C293A 9FAFA338 RefMD5=E9028F9CCC307806695DD81742D05D5D [144B8906DC40534CFBEF6D7B994A982B] GoodName=Pokemon Snap (G) [!] CRC=5753720D 2A8A884D Players=1 SaveType=Flash RAM CountPerOp=1 [8E1968191DD27655C03BE812CF041A95] GoodName=Pokemon Snap (I) [!] CRC=C0C85046 61051B05 Players=1 SaveType=Flash RAM CountPerOp=1 [D0453459095F69BE36D675D8F743069B] GoodName=Pokemon Snap (I) [b1] CRC=C0C85046 61051B05 RefMD5=8E1968191DD27655C03BE812CF041A95 [A45D7115BE5A06FD1567F9F913C3BDF8] GoodName=Pokemon Snap (S) [!] CRC=817D286A EF417416 Players=1 SaveType=Flash RAM CountPerOp=1 [FC3C9329B7CDD67CF7650ABF63B9A580] GoodName=Pokemon Snap (U) [!] CRC=CA12B547 71FA4EE4 Players=1 SaveType=Flash RAM CountPerOp=1 [CCA6F7593302D46ADA66C991C976DA2D] GoodName=Pokemon Snap (U) [T+Spa] CRC=CA12B547 71FA4EE4 RefMD5=FC3C9329B7CDD67CF7650ABF63B9A580 [E3D4F75C24DA0521488E704812259A46] GoodName=Pokemon Snap (U) [f1] (Save) CRC=3FF65EDD 0F8158B0 RefMD5=FC3C9329B7CDD67CF7650ABF63B9A580 [373FBBF4B909E7C8A3AAB3DD80DEBD11] GoodName=Pokemon Snap (U) [f2] (Save-PAL) CRC=38186DAF 232AE3D8 RefMD5=FC3C9329B7CDD67CF7650ABF63B9A580 [BCB210A6A3DCA9A653F836E2957BD6DC] GoodName=Pokemon Snap (U) [f3] (GameShark) CRC=03529CD9 186BDDCD RefMD5=FC3C9329B7CDD67CF7650ABF63B9A580 [53A5D74FA55E378ADA84AF9B0ED2B728] GoodName=Pokemon Snap (U) [f3] CRC=3FF65EDD 0F8158B0 RefMD5=FC3C9329B7CDD67CF7650ABF63B9A580 [A9C272687DABD59C5144774B53BCC35A] GoodName=Pokemon Snap Station (U) [!] CRC=39119872 07722E9F Players=1 SaveType=Flash RAM CountPerOp=1 [B88F0EC125C54685FA516D233B564842] GoodName=Pokemon Snap Station (U) [f1] CRC=4B34DF0B 5899C0FE RefMD5=A9C272687DABD59C5144774B53BCC35A [2859090D78581E0925A3AF8045E81E4B] GoodName=Pokemon Stadium (E) (V1.0) [!] CRC=84077275 57315B9C Players=4 SaveType=Flash RAM Transferpak=Yes [9CC940F5F463416F0B2C15F07A088F33] GoodName=Pokemon Stadium (E) (V1.0) [f1] CRC=9DFE20E9 18894032 RefMD5=2859090D78581E0925A3AF8045E81E4B [31EE2DE8E65E30F5934C450DBAA924F0] GoodName=Pokemon Stadium (E) (V1.1) [!] CRC=91C9E05D AD3AAFB9 Players=4 SaveType=Flash RAM Transferpak=Yes [0E85A098D0F0E8A7EB572A69612A6873] GoodName=Pokemon Stadium (F) [!] CRC=A23553A3 42BF2D39 Players=4 SaveType=Flash RAM Transferpak=Yes [4688C66F8C13EDA13DD5678176A7FD8A] GoodName=Pokemon Stadium (F) [f1] CRC=7E3D8157 D9BF4D91 RefMD5=0E85A098D0F0E8A7EB572A69612A6873 [24BE2CCB0DEA0755908C02BF67E22FE5] GoodName=Pokemon Stadium (G) [!] CRC=42011E1B E3552DB5 Players=4 SaveType=Flash RAM Transferpak=Yes [8FAA825507E6CD3F388CC33343FAE547] GoodName=Pokemon Stadium (G) [f1] CRC=D7F73553 1347659F RefMD5=24BE2CCB0DEA0755908C02BF67E22FE5 [A81321759AF38BEB30A40FDACA2EA22A] GoodName=Pokemon Stadium (I) [!] CRC=A53FA82D DAE2C15D Players=4 SaveType=Flash RAM Transferpak=Yes [D14A499BC4E324974EAE3E42DEC58625] GoodName=Pokemon Stadium (S) [!] CRC=B6E549CE DC8134C0 Players=4 SaveType=Flash RAM Transferpak=Yes [8D296A614A47AC99B80D1EDE669E62B3] GoodName=Pokemon Stadium (S) [f1] CRC=4C115008 9F124960 RefMD5=D14A499BC4E324974EAE3E42DEC58625 [ED1378BC12115F71209A77844965BA50] GoodName=Pokemon Stadium (U) (V1.0) [!] CRC=90F5D9B3 9D0EDCF0 Players=4 SaveType=Flash RAM Transferpak=Yes [C9214988B08511D2F44FAC2FAD2EE67A] GoodName=Pokemon Stadium (U) (V1.0) [f1] CRC=84EBE70F 352C5E3F RefMD5=ED1378BC12115F71209A77844965BA50 [40E03EDA831C01E0A12294287FD240E2] GoodName=Pokemon Stadium (U) (V1.1) [!] CRC=1A122D43 C17DAF0F Players=4 SaveType=Flash RAM Transferpak=Yes [A7087A96A709E4C662A459B4B4159094] GoodName=Pokemon Stadium (U) (V1.1) [b1] CRC=1A122D43 C17DAF0F RefMD5=40E03EDA831C01E0A12294287FD240E2 [A0087A475A29F38BD4CE5DF0A41A89CB] GoodName=Pokemon Stadium (U) (V1.1) [b1][f1] CRC=3FC42B3E CED602E6 RefMD5=40E03EDA831C01E0A12294287FD240E2 [6DC6820CEF755FC1253D06DF45C9BD2A] GoodName=Pokemon Stadium (U) (V1.2) [!] CRC=9C8FB2FA 9B84A09B Players=4 SaveType=Flash RAM Transferpak=Yes [B1271DB50D6EF8F6B53CC640C3743E4F] GoodName=Pokemon Stadium 2 (E) [!] CRC=2952369C B6E4C3A8 Players=4 SaveType=Flash RAM Transferpak=Yes [BB1623BD4751240138DE55E18D3ACA7E] GoodName=Pokemon Stadium 2 (E) [T+Ita0.05] CRC=2952369C B6E4C3A8 RefMD5=B1271DB50D6EF8F6B53CC640C3743E4F [4748D96916AE2BCC5FC1630515EE2561] GoodName=Pokemon Stadium 2 (F) [!] CRC=AC5AA5C7 A9B0CDC3 Players=4 SaveType=Flash RAM Transferpak=Yes [484F3E696C94980ACF3D7068F9ACC98F] GoodName=Pokemon Stadium 2 (G) [!] CRC=439B7E7E C1A1495D Players=4 SaveType=Flash RAM Transferpak=Yes [5A04D7F1AB9C6B080176567AA7168D3A] GoodName=Pokemon Stadium 2 (I) [!] CRC=EFCEAF00 22094848 Players=4 SaveType=Flash RAM Transferpak=Yes [B26AAFD452C9816E1B7AA0954E75825F] GoodName=Pokemon Stadium 2 (S) [!] CRC=D0A1FC5B 2FB8074B Players=4 SaveType=Flash RAM Transferpak=Yes [1561C75D11CEDF356A8DDB1A4A5F9D5D] GoodName=Pokemon Stadium 2 (U) [!] CRC=03571182 892FD06D Players=4 SaveType=Flash RAM Transferpak=Yes [BBDC4C4F1C474298189312008A1768C4] GoodName=Polaris SnoCross (U) [!] CRC=41380792 A167E045 Players=2 SaveType=None Mempak=Yes Rumble=Yes [F27CBDB653AAF1D4856A53D5951F36DD] GoodName=Polaris SnoCross (U) [o1][t1] CRC=B8B73263 1492FC49 RefMD5=BBDC4C4F1C474298189312008A1768C4 [35A01AEB01F3184DD20904AF28FA71C6] GoodName=Polaris SnoCross (U) [t1] CRC=B8B73263 1492FC49 RefMD5=BBDC4C4F1C474298189312008A1768C4 [8847BD6403BA49FD62899115D661B623] GoodName=Pom Part 1 Demo (PD) CRC=1BC0CA2C 0F516B86 [037D2727B90998BED41DA0F290BB8441] GoodName=Pom Part 2 Demo (PD) CRC=ACD51083 EEC8DBED [5426EAED0D350367393F385025AF164C] GoodName=Pom Part 3 Demo (PD) CRC=1FE04890 D6696958 [C7921F3D4B91A42472DADD4DBA2CDC54] GoodName=Pom Part 4 Demo (PD) CRC=CFBEE39B 76F0A14A [F67C06AF4F6613804B3F700B1169B58D] GoodName=Pom Part 5 Demo (PD) CRC=2803B8CE 4A1EE409 [BA976164C2A900C03F445ACD51518FB0] GoodName=Pong V0.01 by Omsk (PD) CRC=C252F9B1 AD70338C [8EACC93671249508BF12CF6EC101056D] GoodName=Pong by Oman (PD) CRC=DAA76993 D8ACF77C Players=2 Status=3 Rumble=No SaveType=None [68C7FC1924AB4400CB65E40C32B7D3A6] GoodName=Pong by Oman (PD) [a1] CRC=DAA76993 D8ACF77C RefMD5=8EACC93671249508BF12CF6EC101056D [E3CFB5F1828CAF1F00B23ADA863460AD] GoodName=Pong by Oman (PD) [h1C][o1] CRC=DAA76993 D8ACF77C RefMD5=8EACC93671249508BF12CF6EC101056D [CD4D5C6C96C8C528A0FCE2958A4A7AC9] GoodName=Pong by Oman (PD) [t1] CRC=6BE878A8 3DC16D91 RefMD5=8EACC93671249508BF12CF6EC101056D [8CC73C373016070647030DDE492FDC8C] GoodName=Power League 64 (J) [!] CRC=D7A6DCFA CCFEB6B7 Players=4 Mempak=Yes [6504FC6F3ADB596F7D68060EB39A75B4] GoodName=Power League 64 (J) [o1] CRC=D7A6DCFA CCFEB6B7 RefMD5=8CC73C373016070647030DDE492FDC8C [AE3BDF729214964620417CC3163F0BB6] GoodName=Power Rangers - Lightspeed Rescue (E) [!] CRC=39F60C11 AB2EBA7D Players=2 SaveType=None Mempak=Yes [24B5BFA896802253D2B715FC760D1B3E] GoodName=Power Rangers - Lightspeed Rescue (E) [f1] (NTSC) CRC=8CD06379 62319493 RefMD5=AE3BDF729214964620417CC3163F0BB6 [91D74621DDEF6D37FB845B3BC7059A38] GoodName=Power Rangers - Lightspeed Rescue (U) [!] CRC=CF8957AD 96D57EA9 Players=2 SaveType=None Mempak=Yes [2991BB68ECA54813D6B834ADBBBACC4C] GoodName=Powerpuff Girls, The - Chemical X-Traction (U) [!] CRC=FC74D475 9A0278AB Players=2 SaveType=None [25BAFC84BA4D87854DC44DF3EF8764EA] GoodName=Premier Manager 64 (E) [!] CRC=F3D27F54 C111ACF9 Players=1 Mempak=Yes [527F05F166398599F0A1B10F8E1F9585] GoodName=Premier Manager 64 (E) [f1] (NTSC) CRC=F45A6784 F587C72F RefMD5=25BAFC84BA4D87854DC44DF3EF8764EA [ED4FE5EAA6631BB142DEF7F317315DFA] GoodName=Premier Manager 64 (E) [f2] (NTSC100%) CRC=C98C4580 A8C84DAD RefMD5=25BAFC84BA4D87854DC44DF3EF8764EA [7995D76F4CE236B0F0289F47AE523D32] GoodName=Pro Mahjong Kiwame 64 (J) (V1.0) [!] CRC=9BA10C4E 0408ABD3 Players=1 Mempak=Yes CountPerOp=1 [D1624977A3C25192671772623FA76438] GoodName=Pro Mahjong Kiwame 64 (J) (V1.0) [b1] CRC=9BA10C4E 0408ABD3 RefMD5=7995D76F4CE236B0F0289F47AE523D32 [6FEC88E88ED25AE7E823A69444D6098A] GoodName=Pro Mahjong Kiwame 64 (J) (V1.0) [o1] CRC=9BA10C4E 0408ABD3 RefMD5=7995D76F4CE236B0F0289F47AE523D32 [B42F62483F7CA2AAC5AF911175463DB8] GoodName=Pro Mahjong Kiwame 64 (J) (V1.1) [!] CRC=0AE2B37C FBC174F0 Players=1 Mempak=Yes CountPerOp=1 [F1A2E4DD22ADF4F90DA4BDDCA37D5F18] GoodName=Pro Mahjong Tsuwamono 64 - Jansou Battle ni Chousen (J) [!] CRC=1BDCB30F A132D876 Players=1 Mempak=Yes CountPerOp=1 [4FA4DC582C23EEE81FEB39B7EEBD15D6] GoodName=Psychodelic Demo by Ste (POM '98) (PD) [b1] CRC=C5C4F0D5 4EEF2573 [592292DF29823A0FD81ED32666878C15] GoodName=Psychodelic Demo by Ste (POM '98) (PD) CRC=C5C4F0D5 4EEF2573 [22B86AB3F320A607899A0516C90A24D0] GoodName=Puyo Puyo 4 - Puyo Puyo Party (J) [!] CRC=4B4672B9 2DBE5DE7 Players=4 Rumble=Yes Transferpak=Yes [FAAA2094B04DCA4C287AF9334D22529D] GoodName=Puyo Puyo Sun 64 (J) [!] CRC=94807E6B 60CC62E4 Players=2 Rumble=Yes [B8267C225583A02ACC3B74B3178B87E9] GoodName=Puyo Puyo Sun 64 (J) [T+Eng1.1_Zoinkity] CRC=1C348AFE 5B96ECFA RefMD5=FAAA2094B04DCA4C287AF9334D22529D [9803F144AB702A7C3E16092AA929AB45] GoodName=Puyo Puyo Sun 64 (J) [T+Kor1.0_Zoinkity&UltimatePenguin] CRC=7FCBF1D2 4546EB4 RefMD5=FAAA2094B04DCA4C287AF9334D22529D [20C7ABF5A4DB8DC1C70725FD213E29A2] GoodName=Puyo Puyo Sun 64 (J) [b1] CRC=94807E6B 60CC62E4 RefMD5=FAAA2094B04DCA4C287AF9334D22529D [B478D4AF60D43C38BA81DE9FAEA6E057] GoodName=Puzzle Bobble 64 (J) [!] CRC=C0DE0747 A2DF72D3 Players=4 SaveType=None Mempak=Yes Rumble=Yes [9B463A87DA73B8C923B05C3BD46EDB09] GoodName=Puzzle Bobble 64 (J) [f1] (PAL) CRC=53D93EA2 B88836C6 RefMD5=B478D4AF60D43C38BA81DE9FAEA6E057 [EA335A87C87F302C6A10D0D3D3E09B72] GoodName=Puzzle Bobble 64 (J) [f2] (PAL) CRC=412E02B8 51A57E8E RefMD5=B478D4AF60D43C38BA81DE9FAEA6E057 [FBDD421FC2105CF4B9663DF97FD7041D] GoodName=Puzzle Master 64 by Michael Searl (PD) CRC=4BBBA2E2 8BF3BBB2 Players=1 Rumble=No SaveType=None Status=2 [592CE7718EFDD1FF2F077C9B2B5275FB] GoodName=Quake 64 (E) [!] CRC=16931D74 65DC6D34 Players=2 SaveType=None Mempak=Yes Rumble=Yes [30EDCCA84850E3B4129936350A9B6B8B] GoodName=Quake 64 (E) [o1] CRC=16931D74 65DC6D34 RefMD5=592CE7718EFDD1FF2F077C9B2B5275FB [FE4AC551B284BD0924F2AAA387249B4B] GoodName=Quake 64 (E) [t1] CRC=68CE63CC 2FFE262C RefMD5=592CE7718EFDD1FF2F077C9B2B5275FB [097605021951024C3ECB2D502C0C2A9F] GoodName=Quake 64 (U) [!] CRC=9F5BF79C D2FE08A0 Players=2 SaveType=None Mempak=Yes Rumble=Yes [87F35BC0C6E2EAD981B49D691095B118] GoodName=Quake 64 (U) [b1] CRC=254CF663 DC8131EE RefMD5=097605021951024C3ECB2D502C0C2A9F [295FAA9B7CC7127BC82AEA90ADB211E5] GoodName=Quake 64 (U) [h1C] CRC=9F5BF79C D2FE08A0 RefMD5=097605021951024C3ECB2D502C0C2A9F [2138CE5AEC363BAC2F18CE65A78ECA25] GoodName=Quake 64 (U) [o1] CRC=9F5BF79C D2FE08A0 RefMD5=097605021951024C3ECB2D502C0C2A9F [D599490909FAACB26D134D152CB5F1ED] GoodName=Quake 64 (U) [o1][t1] CRC=254CF663 DC8131EE RefMD5=097605021951024C3ECB2D502C0C2A9F [F2FA48329FF6DDBB7BD4EEA838FD800B] GoodName=Quake 64 (U) [o2] CRC=9F5BF79C D2FE08A0 RefMD5=097605021951024C3ECB2D502C0C2A9F [7B593077EFC15B44C8D8FF639D6FB434] GoodName=Quake 64 (U) [o2][t1] CRC=254CF663 DC8131EE RefMD5=097605021951024C3ECB2D502C0C2A9F [953BB3AD87B3C1B7AC85F12B135FAA85] GoodName=Quake 64 (U) [t1] CRC=254CF663 DC8131EE RefMD5=097605021951024C3ECB2D502C0C2A9F [C31A8BB6705BD2112A5ABF4F825FD3C0] GoodName=Quake 64 Intro (PD) CRC=F4D89C08 3F34930D [673D4BA4F41A0FE23650F06AF53EEC50] GoodName=Quake II (E) [!] CRC=7433D9D7 2C4322D0 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [55A789C553827114306E29D71E26E5DC] GoodName=Quake II (E) [h1C] CRC=7433D9D7 2C4322D0 RefMD5=673D4BA4F41A0FE23650F06AF53EEC50 [CC93C30C633FF461C29B54CEABEFD701] GoodName=Quake II (U) [!] CRC=BDA8F143 B1AF2D62 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [920FAACCE1F8A80022433ACFD5CD2BC3] GoodName=Quake II (U) [f1] (PAL) CRC=4F8B1784 763A4E04 RefMD5=CC93C30C633FF461C29B54CEABEFD701 [EA552E33973468233A0712C251ABDB6B] GoodName=Quest 64 (U) [!] CRC=C8BB4DD9 CC5F430B Players=1 SaveType=None Mempak=Yes [6F32B4DE3B3FC0C719BF9EA27EFC18BE] GoodName=Quest 64 (U) [b1] CRC=C8BB4DD9 CC5F430B RefMD5=EA552E33973468233A0712C251ABDB6B [0E2CAB03B712E7D4E1C6501978E2E637] GoodName=Quest 64 (U) [b2] CRC=C8BB4DD9 CC5F430B RefMD5=EA552E33973468233A0712C251ABDB6B [4890576C70E8486D2A90424C57C53752] GoodName=Quest 64 (U) [b3] CRC=C8BB4DD9 CC5F430B RefMD5=EA552E33973468233A0712C251ABDB6B [E9EFCC508A7054BB94E5B3243018F1AC] GoodName=Quest 64 (U) [b4] CRC=C8BB4DD9 CC5F430B RefMD5=EA552E33973468233A0712C251ABDB6B [131CCC5C9E9BD830147562DFD06444BF] GoodName=Quest 64 (U) [b5] CRC=C8BB4DD9 CC5F430B RefMD5=EA552E33973468233A0712C251ABDB6B [C01A079E0005DCF5AD9AB0D58CD9515E] GoodName=Quest 64 (U) [t1] CRC=5F48A227 B97D9B7F RefMD5=EA552E33973468233A0712C251ABDB6B [5DF35D0C05E58FCE938BAEC6CB2A230E] GoodName=R.I.P. Jay Demo by Ste (PD) [b1] CRC=32A92961 DB34982C [03418F1567DC45CBB4B4E9DA772CAA7F] GoodName=R.I.P. Jay Demo by Ste (PD) CRC=32A92961 DB34982C [FFE3839FD3974A0858A62CF363D0F8DB] GoodName=RADWAR 2K Party Inv. Intro by Ayatolloh (PD) CRC=C9011D05 EF078B8C [34AF9F96DE01A7DF6B296598908BB398] GoodName=RPA Site Intro by Lem (PD) CRC=79E318E1 86861726 [4561840840760FFA7B59F03A5F416A5C] GoodName=RR64 - Ridge Racer 64 (E) [!] CRC=FEE97010 4E94A9A0 SaveType=Eeprom 16KB Players=4 Rumble=Yes [990F97D56456FC23E52BD263E709E21E] GoodName=RR64 - Ridge Racer 64 (U) [!] CRC=2500267E 2A7EC3CE SaveType=Eeprom 16KB Players=4 Rumble=Yes [8CF63267BA38AB73763354C79C4ADB74] GoodName=RR64 - Ridge Racer 64 (U) [f1] (PAL) CRC=4E17004A 259E946C RefMD5=990F97D56456FC23E52BD263E709E21E [07D6006F744727DAAC7F53692AD950C4] GoodName=RR64 - Ridge Racer 64 (U) [t1] CRC=5A98A468 AB27C89D RefMD5=990F97D56456FC23E52BD263E709E21E [A1082A6676455C040843FD75E92DE1A3] GoodName=RTL World League Soccer 2000 (G) [!] CRC=658F8F37 1813D28D Players=4 Mempak=Yes Rumble=Yes [09BEE9D7EB1159D11E49BDFB03A2C4CC] GoodName=RTL World League Soccer 2000 (G) [f1] (NTSC) CRC=D250103E 136A0F0C RefMD5=A1082A6676455C040843FD75E92DE1A3 [4392F33C4282B68C9DEF5111CCF733CA] GoodName=RTL World League Soccer 2000 (G) [f1][o1] CRC=D250103E 136A0F0C RefMD5=A1082A6676455C040843FD75E92DE1A3 [AA57D69867F53456F351A289EBA08C3D] GoodName=Racing Simulation 2 (G) [!] CRC=2877AC2D C3DC139A Players=2 SaveType=None Mempak=Yes Rumble=Yes [6160D5DE99BE421ACB620D2D203C2FEC] GoodName=Racing Simulation 2 (G) [h1C] CRC=2877AC2D C3DC139A RefMD5=AA57D69867F53456F351A289EBA08C3D [167A3502F06CF0EEF56758533F3D0E52] GoodName=Rakuga Kids (E) [!] CRC=67D21868 C5424061 Players=2 Mempak=Yes [28FE768CED3C87659B343A7811CFAC0A] GoodName=Rakuga Kids (E) [b1] CRC=67D21868 C5424061 RefMD5=167A3502F06CF0EEF56758533F3D0E52 [7F0900DD9726A7E56A398E910D014B61] GoodName=Rakuga Kids (E) [f1] (NTSC) CRC=49020C8E A000B949 RefMD5=167A3502F06CF0EEF56758533F3D0E52 [98A802D44FE4169FD73D7B481C08613E] GoodName=Rakuga Kids (E) [h1C] CRC=67D21868 C5424061 RefMD5=167A3502F06CF0EEF56758533F3D0E52 [813AD5C00BAD7C4D41F8558CECEDAE51] GoodName=Rakuga Kids (J) [!] CRC=9F1ECAF0 EEC48A0E Players=2 Mempak=Yes [378C6CE13DF3363F77D76B64C8DAB287] GoodName=Rakuga Kids (J) [b1] CRC=9F1ECAF0 EEC48A0E RefMD5=813AD5C00BAD7C4D41F8558CECEDAE51 [08D79A5C0F393D81296F50A6D556D999] GoodName=Rakuga Kids (J) [h1C] CRC=9F1ECAF0 EEC48A0E RefMD5=813AD5C00BAD7C4D41F8558CECEDAE51 [0630226F63561A05916EDCFBC8D96C04] GoodName=Rally '99 (J) [!] CRC=35D9BA0C DF485586 Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [035B02E493A388E950FB42F4B3D891F8] GoodName=Rally '99 (J) [f1] (PAL) CRC=4C2B343C 7249BAFF RefMD5=0630226F63561A05916EDCFBC8D96C04 [0458BC47CD771D8BC66B0CEAE6895724] GoodName=Rally Challenge 2000 (U) [!] CRC=73A88E3D 3AC5C571 Players=4 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [08E02F52E0547686A9BFAC7CBB03C129] GoodName=Rampage - World Tour (E) [!] CRC=84D44448 67CA19B0 Players=2 SaveType=None Mempak=Yes Rumble=Yes [410146EA14CF34D134BC97C78522D322] GoodName=Rampage - World Tour (E) [h1C] CRC=84D44448 67CA19B0 RefMD5=08E02F52E0547686A9BFAC7CBB03C129 [4645672A0CF00ADA9B5E37CFDE8B024E] GoodName=Rampage - World Tour (U) [!] CRC=C29FF9E4 264BFE7D Players=2 SaveType=None Mempak=Yes Rumble=Yes [1659F9F8C8A5C24F775B245BDA574462] GoodName=Rampage - World Tour (U) [b1] CRC=C29FF9E4 264BFE7D RefMD5=4645672A0CF00ADA9B5E37CFDE8B024E [71EC90E34421CEEAA8B71ACAF76EFD33] GoodName=Rampage - World Tour (U) [b2] CRC=C29FF9E4 264BFE7D RefMD5=4645672A0CF00ADA9B5E37CFDE8B024E [669584EEB9F85C7A8A96B716A2B43739] GoodName=Rampage - World Tour (U) [b3] CRC=C29FF9E4 264BFE7D RefMD5=4645672A0CF00ADA9B5E37CFDE8B024E [70C3E7412FF8196E16CCA076B3B622F7] GoodName=Rampage - World Tour (U) [b4] CRC=C29FF9E4 264BFE7D RefMD5=4645672A0CF00ADA9B5E37CFDE8B024E [BE823D7958151B97F812FBF01E7621D2] GoodName=Rampage - World Tour (U) [h1C] CRC=C29FF9E4 264BFE7D RefMD5=4645672A0CF00ADA9B5E37CFDE8B024E [E3060D3FADA2A502764E765F8140FC42] GoodName=Rampage - World Tour (U) [t1] CRC=588F980C 63FF7803 RefMD5=4645672A0CF00ADA9B5E37CFDE8B024E [4D280855EA4FFE98054BDF633EA5A7F7] GoodName=Rampage - World Tour (U) [t2] CRC=588F980C 63FF7803 RefMD5=4645672A0CF00ADA9B5E37CFDE8B024E [1492806F12D33C3EA0EDB6848D43B1CC] GoodName=Rampage 2 - Universal Tour (E) [!] CRC=5DFC4249 99529C07 Players=3 SaveType=None Mempak=Yes Rumble=Yes [8113D0EA2008402D4631F241F625D16B] GoodName=Rampage 2 - Universal Tour (U) [!] CRC=673D099B A4C808DE Players=3 SaveType=None Mempak=Yes Rumble=Yes [EBAFB5C3BCC84543A8E7FEF1993E573F] GoodName=Rampage 2 - Universal Tour (U) [t1] CRC=BF4317E2 2DF987E2 RefMD5=8113D0EA2008402D4631F241F625D16B [EA383E48637B44FFF9294D23B076548B] GoodName=Rampage 2 - Universal Tour (U) [t2] CRC=FD2FC875 3BD10D89 RefMD5=8113D0EA2008402D4631F241F625D16B [C7B9024594F932BA5E3A1FB70FE9BD6B] GoodName=Rape Kombat Trilogy Beta1 (Mortal Kombat Hack) CRC=9A2949C1 04E76074 [BC66239C12AE8696926E50C2B6ED9C49] GoodName=Rat Attack (E) (M6) [!] CRC=20FD0BF1 F5CF1D87 Players=4 SaveType=None Mempak=Yes ; Allows the game to boot Cheat0=F117DAEC 8014,F117DAEE A1D0 [E0BB65C30C1185FD9997020A1994B07E] GoodName=Rat Attack (E) (M6) [f1] (NTSC) CRC=85670AB4 3834BE8A RefMD5=BC66239C12AE8696926E50C2B6ED9C49 [6F868B1652183376665F67F8183EEB5C] GoodName=Rat Attack (E) (M6) [h1C] CRC=20FD0BF1 F5CF1D87 RefMD5=BC66239C12AE8696926E50C2B6ED9C49 [F661889FDF65DDCD212E9FB53B2C8F50] GoodName=Rat Attack (U) (M6) [!] CRC=0304C48E AC4001B8 Players=4 SaveType=None Mempak=Yes ; Allows the game to boot Cheat0=F117E34C 8014,F117E34E A8F0 [5DBBFD5ACE8222FA8FE51BE113453C13] GoodName=Rayman 2 - The Great Escape (E) (M5) [!] CRC=60D5E10B 8BEDED46 Players=1 SaveType=None Mempak=Yes [EF2001F581A80D760C51D130725A9930] GoodName=Rayman 2 - The Great Escape (E) (M5) [f1] (NTSC) CRC=B8C303FA 544BB5FA RefMD5=5DBBFD5ACE8222FA8FE51BE113453C13 [53B325CCDF2069AB20CAF1C9B401CD20] GoodName=Rayman 2 - The Great Escape (E) (M5) [f2] (NTSC) CRC=7055FD0A E0A45808 RefMD5=5DBBFD5ACE8222FA8FE51BE113453C13 [03AA4D09FDE77EED9B95BE68E603D233] GoodName=Rayman 2 - The Great Escape (U) (M5) [!] CRC=F3C5BF9B 160F33E2 Players=1 SaveType=None Mempak=Yes [2B1D9F38389522A372D950E1BC6FA13F] GoodName=Rayman 2 - The Great Escape (U) (M5) [t1] CRC=8BB6E3EB 2402CC87 RefMD5=03AA4D09FDE77EED9B95BE68E603D233 [406B08987AB92D73D72B597EC6B11BD9] GoodName=Razor Freestyle Scooter (U) [!] CRC=3918834A 15B50C29 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [FAA64ABB0D222FCC0C6E2515D3805D9F] GoodName=Re-Volt (E) (M4) [!] CRC=C3E7E29E 5D7251CC Players=4 SaveType=None Mempak=Yes Rumble=Yes [3FC4D3187435443455F8355B2D3F8934] GoodName=Re-Volt (U) [!] CRC=0F1FA987 BFC1AFA6 Players=4 SaveType=None Mempak=Yes Rumble=Yes [377DAF6EDD0C996422D2A9C8C5DEC033] GoodName=Re-Volt (U) [f1] (Country Check) CRC=529AA985 A85509A3 RefMD5=3FC4D3187435443455F8355B2D3F8934 [77DC38CCE0FFAB004FD54F54EE25A593] GoodName=Re-Volt (U) [f2] (PAL) CRC=53575A75 54573214 RefMD5=3FC4D3187435443455F8355B2D3F8934 [197E24C1AB6503998798D7F56EAE7ADD] GoodName=Re-Volt (U) [t1] CRC=B754A584 D3530516 RefMD5=3FC4D3187435443455F8355B2D3F8934 [ADC95AE01855FA305B13F8B22427E597] GoodName=Ready 2 Rumble Boxing (E) (M3) [!] CRC=8BD4A334 1E138B05 Players=2 SaveType=None Mempak=Yes Rumble=Yes [73165CBE4E2421475C5FE9A227DCAFEC] GoodName=Ready 2 Rumble Boxing (E) [T+Spa2.0_IlDucci] CRC=56E06922 10F665F6 RefMD5=ADC95AE01855FA305B13F8B22427E597 [70F73D01FEAF768758F31B23DE2C2620] GoodName=Ready 2 Rumble Boxing (E) (M3) [t1] (P1 Untouchable) CRC=8638A334 8EBF1508 RefMD5=ADC95AE01855FA305B13F8B22427E597 [A42F6F14F7EA10ABEB3B55FFD42EB572] GoodName=Ready 2 Rumble Boxing (U) [!] CRC=EAB7B429 BAC92C57 Players=2 SaveType=None Mempak=Yes Rumble=Yes [25620A9C9F372023A8BA862330E6373A] GoodName=Ready 2 Rumble Boxing (U) [f1] (PAL) CRC=5D6AA6EA 657352B1 RefMD5=A42F6F14F7EA10ABEB3B55FFD42EB572 [CCECEAA389A7847DE3433888C66A76E5] GoodName=Ready 2 Rumble Boxing (U) [t1] (P1 Untouchable) CRC=E655B42D F22370DD RefMD5=A42F6F14F7EA10ABEB3B55FFD42EB572 [DF4446A2B55C4D8D67E9C0C19E0FD9FB] GoodName=Ready 2 Rumble Boxing - Round 2 (U) [!] CRC=E9219533 13FBAFBD Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [CB97350D5CAB48EAB8B954D91C0E5DAC] GoodName=Ready 2 Rumble Boxing - Round 2 (U) [t1] CRC=6CED60AC C74292DC RefMD5=DF4446A2B55C4D8D67E9C0C19E0FD9FB [B04F298721223A22E1150CEBC712EE6A] GoodName=Resident Evil 2 (E) (M2) [!] CRC=9B500E8E E90550B3 Players=1 SaveType=SRAM Rumble=Yes CountPerOp=1 [DD21150CBC21C05420304599EC57411C] GoodName=Resident Evil 2 (U) (V1.0) [!] CRC=2F493DD0 2E64DFD9 Players=1 SaveType=SRAM Rumble=Yes CountPerOp=1 [1ADD2C0217662B307CDFD876B35FBF7A] GoodName=Resident Evil 2 (U) (V1.1) [!] CRC=AA18B1A5 07DB6AEB Players=1 SaveType=SRAM Rumble=Yes CountPerOp=1 [AD922DAE446A301E1AAFE1DFBAD75A2E] GoodName=Road Rash 64 (E) [!] CRC=02D8366A 6CABEF9C Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=3 [5EB2B1892B68767EB1D310FF7507D34E] GoodName=Road Rash 64 (E) [h1C] CRC=02D8366A 6CABEF9C RefMD5=AD922DAE446A301E1AAFE1DFBAD75A2E [28C2373F6D831EEC81F6146A809E701B] GoodName=Road Rash 64 (U) [!] CRC=F050746C 247B820B Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=3 [7966F17F36C43D3807C0949AAD45168A] GoodName=Road Rash 64 (U) [f1] (PAL) CRC=422D29E1 C1FB33F3 RefMD5=28C2373F6D831EEC81F6146A809E701B [C6867566C9E173BEAB459C5945B69C23] GoodName=Road Rash 64 (U) [t1] CRC=48176863 E1829A22 RefMD5=28C2373F6D831EEC81F6146A809E701B [41F67B5C8BB8DAEFFD989123846FC063] GoodName=Roadsters Trophy (E) (M6) [!] CRC=74E87A70 6293AED4 Players=4 SaveType=None Mempak=Yes Rumble=Yes [D3644B398C090528E0ED9EB3C140366E] GoodName=Roadsters Trophy (U) (M3) [!] CRC=0B6B4DDB 9671E682 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [AE705F25C57ACABBD0E8BAE5EC6E237F] GoodName=Roadsters Trophy (U) (M3) [f1] (PAL) CRC=787AECF1 CC8147BA RefMD5=D3644B398C090528E0ED9EB3C140366E [5C9C715430ACBAEF3A5FBDB3E6661ACF] GoodName=Roadsters Trophy (U) (M3) [t1] CRC=74BCA5D3 4A945F7E RefMD5=D3644B398C090528E0ED9EB3C140366E [444F70A655AC89CA900F6FAFAF926B16] GoodName=Robot Ponkottsu 64 - 7tsu no Umi no Caramel (J) [!] CRC=272B690F AD0A7A77 Players=2 SaveType=Eeprom 16KB Transferpak=Yes [34779AF3681F58E4F642F03EAEF198F9] GoodName=Robot Ponkotsu 64 - 7tsu no Umi no Caramel (J) [f1] (PAL) CRC=7F564549 ED60C5E6 RefMD5=444F70A655AC89CA900F6FAFAF926B16 [27C6F780F9032A531E9A322969CD9159] GoodName=Robotech - Crystal Dreams (Beta) CRC=75A0B893 4CA321B5 [B39592C6C9A3121258BDB62485956880] GoodName=Robotech - Crystal Dreams (Beta) [a1] CRC=75A0B893 4CA321B5 [2ABCD1AD41B3356FBC1018ECB121283E] GoodName=Robotron 64 (E) [!] CRC=9FF69D4F 195F0059 Players=2 SaveType=None Mempak=Yes [360044D5675A328E62191250F43B6671] GoodName=Robotron 64 (E) [h1C] CRC=9FF69D4F 195F0059 RefMD5=2ABCD1AD41B3356FBC1018ECB121283E [C4A9BBF989DDFAF5F389E4ADC6195DBC] GoodName=Robotron 64 (U) [!] CRC=AC8E4B32 E7B47326 Players=2 SaveType=None Mempak=Yes [5698757883A6F46FE5B4C9B6E780B480] GoodName=Robotron 64 (U) [b1] CRC=AC8E4B32 E7B47326 RefMD5=C4A9BBF989DDFAF5F389E4ADC6195DBC [8555DCF12FD35206451FB415F3FD2EEF] GoodName=Robotron 64 (U) [b2] CRC=8F4C4B32 6D881FCA RefMD5=C4A9BBF989DDFAF5F389E4ADC6195DBC [AB50026DAEA629F554408E5BA3EFA182] GoodName=Robotron 64 (U) [b3] CRC=8F4C4B32 6D881FCA RefMD5=C4A9BBF989DDFAF5F389E4ADC6195DBC [1AA79B5DEFE1F5852D5ADD799383CCCD] GoodName=Robotron 64 (U) [b4] CRC=575CCC2E A8B5ACE0 RefMD5=C4A9BBF989DDFAF5F389E4ADC6195DBC [377B9C40EBE4F4CF845E577A8DC9ACCB] GoodName=Robotron 64 (U) [f1] (PAL) CRC=8F4C4B32 6D881FCA RefMD5=C4A9BBF989DDFAF5F389E4ADC6195DBC [27E4C31540E18E3E8CEA97BFF744CC11] GoodName=Robotron 64 (U) [o1] CRC=AC8E4B32 E7B47326 RefMD5=C4A9BBF989DDFAF5F389E4ADC6195DBC [E151CCE259636C5AE15CA1C8B380EE76] GoodName=Robotron 64 (U) [t1] CRC=575CCC2E A8B5ACE0 RefMD5=C4A9BBF989DDFAF5F389E4ADC6195DBC [427C5457D4A29A222811F0CAA9CCA7B9] GoodName=Rocket - Robot on Wheels (E) (M3) [!] CRC=9FD375F8 45F32DC8 SaveType=Eeprom 4KB Players=1 Rumble=Yes [C2907EB2F9A350793317ECE878A3B8E3] GoodName=Rocket - Robot on Wheels (U) [!] CRC=0C5EE085 A167DD3E SaveType=Eeprom 4KB Players=1 Rumble=Yes [E8CBAADEDB6D19ACC142BE3105E94C4F] GoodName=Rocket - Robot on Wheels (U) [b1] CRC=0C5EE085 A167DD3E RefMD5=C2907EB2F9A350793317ECE878A3B8E3 [991E5F527EC9330320E65233C293D4C5] GoodName=Rocket - Robot on Wheels (U) [f1] (PAL) CRC=B9233DC7 9CCF2D4C RefMD5=C2907EB2F9A350793317ECE878A3B8E3 [B042C238C4093DB533EC4E849C40DE4F] GoodName=Rocket - Robot on Wheels (U) [t1] CRC=B31A9FBB 26D03050 RefMD5=C2907EB2F9A350793317ECE878A3B8E3 [0C74B44680276FFE808CFA6045329819] GoodName=Rockman Dash (J) [!] CRC=D666593B D7A25C07 Players=1 SaveType=Flash RAM Rumble=Yes [14F1F43A0314C3E36D9D248E1F03EC2E] GoodName=Ronaldinho's Soccer 64 (B) (Unl) (Pirate) CRC=6F46DA42 D971A312 [73971508A3B4CA92F7F4CF59C9170372] GoodName=Rotating Demo USA by Rene (PD) [a1] CRC=6FA4B821 29561690 [0BF79F532C938384431DA9406B846AFA] GoodName=Rotating Demo USA by Rene (PD) CRC=6FA4B821 29561690 [DEC4598A39728C28CD0CEBA45A173CE1] GoodName=Rugrats - Die grosse Schatzsuche (G) [!] CRC=451ACA0F 7863BC8A Players=4 SaveType=None Rumble=Yes [8C432235A57D34BC4A9B8B290E21E01E] GoodName=Rugrats - Scavenger Hunt (U) [!] CRC=0C02B3C5 9E2511B8 Players=4 SaveType=None Rumble=Yes [C3ED4CD05978DECFD761FA2503DCB39E] GoodName=Rugrats - Scavenger Hunt (U) [f1] (PAL) CRC=F04A729C 19971680 RefMD5=8C432235A57D34BC4A9B8B290E21E01E [55185016031CDC73C0FD471527C35706] GoodName=Rugrats - Treasure Hunt (E) [!] CRC=4D3ADFDA 7598FCAE Players=4 SaveType=None Rumble=Yes [950161325C7E11A057CC85C95685DB05] GoodName=Rugrats - Treasure Hunt (E) [h1C] CRC=4D3ADFDA 7598FCAE RefMD5=55185016031CDC73C0FD471527C35706 [229089089661F517C863242D6BB77746] GoodName=Rugrats in Paris - The Movie (E) [!] CRC=0AC61D39 ABFA03A6 Players=2 SaveType=None Mempak=Yes [207EFE58C7C221DBDFFF285AB80126C1] GoodName=Rugrats in Paris - The Movie (U) [!] CRC=1FC21532 0B6466D4 Players=2 SaveType=None Mempak=Yes [F3515A45EC01D2C9FEAFBAB2B85D72C4] GoodName=Rugrats in Paris - The Movie (U) [T+Spa0.10] CRC=40D5D2DE 78489F0F RefMD5=207EFE58C7C221DBDFFF285AB80126C1 [681DF5A32E857E77194106B35304D6B5] GoodName=Rush 2 - Extreme Racing USA (E) (M6) [!] CRC=B7CF2136 FA0AA715 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [8A59477C29B4353FEAB85303C58B98F0] GoodName=Rush 2 - Extreme Racing USA (E) (M6) [h1I] CRC=09A0A6E5 8396630D RefMD5=681DF5A32E857E77194106B35304D6B5 [E9F65EA602A442966BE4DDCE799A8E20] GoodName=Rush 2 - Extreme Racing USA (E) (M6) [h2I] CRC=09A0A6E5 8396630D RefMD5=681DF5A32E857E77194106B35304D6B5 [6A925AB624EE3B343231D799733BA898] GoodName=Rush 2 - Extreme Racing USA (U) [!] CRC=EDD6E031 68136013 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [7ED3F10BC32CF76F172D8C31D15A2799] GoodName=S.C.A.R.S. (E) (M3) [!] CRC=918E2D60 F865683E Players=4 SaveType=None Mempak=Yes Rumble=Yes [0DC80ADCD95AF4FC8FE2C7E648CA64F0] GoodName=S.C.A.R.S. (E) (M3) [h1C] CRC=918E2D60 F865683E RefMD5=7ED3F10BC32CF76F172D8C31D15A2799 [D0AA9D20A4B85FE514D2A3150D0133EA] GoodName=S.C.A.R.S. (U) [!] CRC=769147F3 2033C10E Players=4 SaveType=None Mempak=Yes Rumble=Yes [D0A050E86E27126FD7324B5674A30764] GoodName=S.C.A.R.S. (U) [f1] (PAL) CRC=8954584D EFE71E95 RefMD5=D0AA9D20A4B85FE514D2A3150D0133EA [40866BBE1629E9B170DE552ACA83D967] GoodName=S.C.A.R.S. (U) [t1] CRC=8954A655 3B38F292 RefMD5=D0AA9D20A4B85FE514D2A3150D0133EA [637A7EA2A39F20C5B20834187230D89D] GoodName=SD Hiryuu no Ken Densetsu (J) [!] CRC=EBF5F6B7 C956D739 Players=2 SaveType=None Mempak=Yes Rumble=Yes [F29A0A02C41815EE3F5437E409EC327B] GoodName=SD Hiryuu no Ken Densetsu (J) [f1] (PAL) CRC=EBF5F6B7 C956D739 RefMD5=637A7EA2A39F20C5B20834187230D89D [52FD60268A69DC7B532AD58EDD2133C0] GoodName=SLiDeS (PD) CRC=5BBE6E34 088B6D0E Status=2 Players=1 SaveType=None [F323E3807A6AEDEDEAC9E0739490D13C] GoodName=SNES 9X Alpha by Loom-Crazy Nation (PD) [f1] (V64BIOS1.91) CRC=CA69ECE5 13A88244 [29E875C7FFA44CA629F2576CB47A1020] GoodName=SNES 9X Alpha by Loom-Crazy Nation (PD) CRC=CA69ECE5 13A88244 [919A27C2ABBEA83BA996CEE553227929] GoodName=SPLiT's Nacho64 by SPLiT (PD) CRC=1FBD27A9 6CC3EB42 Players=0 Status=3 SaveType=None [A63921B3190C45940721BA3AC64D1114] GoodName=SPLiT's Nacho64 by SPLiT (PD) [f1] (PAL) CRC=1899FF33 885180E6 RefMD5=919A27C2ABBEA83BA996CEE553227929 [123417811CDC49118EB01ECF76BAF760] GoodName=SRAM Manager V1.0 Beta (32Mbit) (PD) [a1] CRC=029CAE05 2B8F9DF1 [891E4A11B6F80E31A2F247FEA3730744] GoodName=SRAM Manager V1.0 Beta (32Mbit) (PD) CRC=029CAE05 2B8F9DF1 [98A5DBA896685D86A07CEEA283FD36D3] GoodName=SRAM Manager V1.0 Beta (PD) CRC=029CAE05 2B8F9DF1 [57BEB4B0AFDD4AFADE9DB6A13B72D17D] GoodName=SRAM Manager V1.0 PAL Beta (PD) CRC=4DEC9986 A8904450 [ED46A867A648A101D239DA0650B49783] GoodName=SRAM Manager V2.0 (PD) [a1] CRC=4E5507F2 E7D3B413 [657836F55DCB952C56BC5C645D82D6C2] GoodName=SRAM Manager V2.0 (PD) [h1C] CRC=4E5507F2 E7D3B413 [2E8367ED95724816646131BAD480BDD2] GoodName=SRAM Manager V2.0 (PD) [h2C] CRC=4E5507F2 E7D3B413 [597ADB9702440E72D5954D50671D9C57] GoodName=SRAM Manager V2.0 (PD) CRC=4E5507F2 E7D3B413 [00F846A9AA9E0083CE8C0E566843A7C7] GoodName=SRAM Upload Tool (PD) CRC=98A2BB11 EE4D4A86 [2FA1AC0A989D5F081D6A8733F2330923] GoodName=SRAM Upload Tool + Star Fox 64 SRAM (PD) CRC=3C524346 E4ABE776 [103592E65C65464C141A2184DBFD0947] GoodName=SRAM Upload Tool V1 by LaC (PD) CRC=3B8E7E01 6AE876A8 [71C2E66CCE1FEC929B5485AC41A61D95] GoodName=SRAM Upload Tool V1.1 by Lac (PD) [b1] CRC=98A2BB11 EE4D4A86 [2B2186A38B0B3541C3227144EA3C71A3] GoodName=SRAM Upload Tool V1.1 by Lac (PD) CRC=3C524346 E4ABE776 [F26102590AA6982EA78701E6A418BED0] GoodName=SRAM Uploader-Editor by BlackBag (PD) CRC=EC9BECFF CAB83632 [A5C1F8AF5D9AA7D2C771DA1C84841017] GoodName=SRAM to DS1 Tool by WT_Riker (PD) CRC=52BA5D2A 9BE3AB78 [C4E47228706BC724D7FBD811231D20C9] GoodName=Saikyou Habu Shougi (J) [!] CRC=5E3E60E8 4AB5D495 Players=1 Mempak=Yes [D92EEBA87794311C8F4443C29CC177C5] GoodName=Saikyou Habu Shougi (J) [h1C] CRC=5E3E60E8 4AB5D495 RefMD5=C4E47228706BC724D7FBD811231D20C9 [0F205BA6B663C3C31579894873CAFA66] GoodName=Saikyou Habu Shougi (J) [h2C] CRC=5E3E60E8 4AB5D495 RefMD5=C4E47228706BC724D7FBD811231D20C9 [95C345EE264F3A91F1381E76CAD82F11] GoodName=Saikyou Habu Shougi (J) [h3C] CRC=5E3E60E8 4AB5D495 RefMD5=C4E47228706BC724D7FBD811231D20C9 [34F623903C3E2DBF8FB1E47F688D1859] GoodName=Saikyou Habu Shougi (J) [h4C] CRC=5E3E60E8 4AB5D495 RefMD5=C4E47228706BC724D7FBD811231D20C9 [630A177A8D5B603F8C86D8A089E3471B] GoodName=Sample Demo by Florian (PD) [b1] CRC=C541EAB4 7397CB5F [2F8109E5C9BCC45B9987F31EA00ECA66] GoodName=Sample Demo by Florian (PD) CRC=C541EAB4 7397CB5F [81B1122EE15F7B50A341AE62E9C5716B] GoodName=San Francisco Rush - Extreme Racing (E) (M3) [!] CRC=61D116B0 FA24D60C Players=2 SaveType=None Mempak=Yes Rumble=Yes [4FDF9E702D4A6A75124623D9434BF99F] GoodName=San Francisco Rush - Extreme Racing (E) (M3) [h1C] CRC=61D116B0 FA24D60C RefMD5=81B1122EE15F7B50A341AE62E9C5716B [F015FC28E1D62A36B4EBF4C79CA8F285] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.0) [!] CRC=2A6B1820 6ABCF466 Players=2 SaveType=None Mempak=Yes Rumble=Yes [2A8086945375826FA6495F1EF2F1DFB6] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.0) [b1] CRC=2A6B1820 6ABCF466 RefMD5=F015FC28E1D62A36B4EBF4C79CA8F285 [C870967473A8BD2942D00EAA3D7CCC9E] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.0) [b2] CRC=2A6B1820 6ABCF466 RefMD5=F015FC28E1D62A36B4EBF4C79CA8F285 [CFD1B123BBABF1658CA6D52F34434A1E] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.0) [b3] CRC=2A6B1820 6ABCF466 RefMD5=F015FC28E1D62A36B4EBF4C79CA8F285 [AD921B1336EDA406D124940BED174465] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.0) [o1] CRC=2A6B1820 6ABCF466 RefMD5=F015FC28E1D62A36B4EBF4C79CA8F285 [390FC46621581FA62F7F4CC3537F255D] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.0) [o2] CRC=2A6B1820 6ABCF466 RefMD5=F015FC28E1D62A36B4EBF4C79CA8F285 [90CA5D19B7F085474EBD2186D70C59AF] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.0) [o3] CRC=2A6B1820 6ABCF466 RefMD5=F015FC28E1D62A36B4EBF4C79CA8F285 [5B127E6B090A0B3F68A114D4D89323D4] GoodName=San Francisco Rush - Extreme Racing (U) (M3) (V1.1) [!] CRC=AC9F7DA7 A8C029D8 Players=2 SaveType=None Mempak=Yes Rumble=Yes [02B16AC23998F78F09AF6513F4ACB664] GoodName=San Francisco Rush 2049 (E) (M6) [!] CRC=51D29418 D5B46AE3 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [AF5BE0ADFF51A8E9C6D771282C295810] GoodName=San Francisco Rush 2049 (U) [!] CRC=B9A9ECA2 17AAE48E Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [1977D63B511A900628DB2A3A104160AC] GoodName=San Francisco Rush 2049 (U) [t1] CRC=01D66F37 365F18B3 RefMD5=AF5BE0ADFF51A8E9C6D771282C295810 [3B6DD7B60437234895500BEFF28DF6D6] GoodName=Scooby-Doo! - Classic Creep Capers (E) [!] CRC=E3BD221D 3C0834D3 Players=1 SaveType=None Mempak=Yes [16CC6DB10A56331B56F374B4FB254D5E] GoodName=Scooby-Doo! - Classic Creep Capers (U) (V1.0) [!] CRC=0C814EC4 58FE5CA8 Players=1 SaveType=None Mempak=Yes [01CD9938DAE5DCDD4B264AE7F26C6D4D] GoodName=Scooby-Doo! - Classic Creep Capers (U) (V1.1) [!] CRC=569433AD F7E13561 Players=1 SaveType=None Mempak=Yes [FE2605193736A128AD65DB1C9835A130] GoodName=Shadow Man (B) [!] CRC=93A625B9 2D6022E6 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [A485A6E9E30B7D55D23D8DD043770C64] GoodName=Shadow Man (E) (M3) [!] CRC=60C437E5 A2251EE3 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [235511BBDB21AF5A767BDB7502A80F06] GoodName=Shadow Man (F) [!] CRC=EA06F8C3 07C2DEED Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [AF40EF12CE923FF1C26E76CC9D9B9ED9] GoodName=Shadow Man (G) [!] CRC=84D5FD75 BBFD3CDF Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [CFBDC1C5E419FF162DF02A0065D9BC1D] GoodName=Shadow Man (G) [b1] CRC=84D5FD75 BBFD3CDF RefMD5=AF40EF12CE923FF1C26E76CC9D9B9ED9 [630776E478E00CDA1D09BAB55656ACA7] GoodName=Shadow Man (G) [b2] CRC=84D5FD75 BBFD3CDF RefMD5=AF40EF12CE923FF1C26E76CC9D9B9ED9 [0802F5BB4004D8948A6C0B51C8857B74] GoodName=Shadow Man (G) [f1] (NTSC) CRC=720278EC 594B7975 RefMD5=AF40EF12CE923FF1C26E76CC9D9B9ED9 [B457298B87B85BBF950F24867DAA9475] GoodName=Shadow Man (U) [!] CRC=3A4760B5 2D74D410 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [474647AEDFA95AEF73229A2784897EDD] GoodName=Shadow Man (U) [b1] CRC=3A4760B5 2D74D410 RefMD5=B457298B87B85BBF950F24867DAA9475 [5AE3BB3604539ABDEBA639E5892BD60E] GoodName=Shadow Man (U) [b2] CRC=3A4760B5 2D74D410 RefMD5=B457298B87B85BBF950F24867DAA9475 [22A689C97FAEDF39A8F115DB8F71830C] GoodName=Shadow Man (U) [b3] CRC=82342320 BC65A550 RefMD5=B457298B87B85BBF950F24867DAA9475 [C76828840668B6F3D4670CF4AD89C4AA] GoodName=Shadow Man (U) [t1] CRC=82342320 BC65A550 RefMD5=B457298B87B85BBF950F24867DAA9475 [A06E757CF1930B29FA4C0B5C9F31335F] GoodName=Shadowgate 64 - Trials Of The Four Towers (E) (M2) (Ita-Spa) [!] CRC=02B46F55 61778D0B Players=1 SaveType=None Mempak=Yes [11169A32D449EC3A8903CA8A9D69A6AA] GoodName=Shadowgate 64 - Trials Of The Four Towers (E) (M3) (Fre-Ger-Dut) [!] CRC=2BC1FCF2 7B9A0DF4 Players=1 SaveType=None Mempak=Yes [E8955C3B743FDDFE403E52E769E9853F] GoodName=Shadowgate 64 - Trials Of The Four Towers (E) [!] CRC=D84EEA84 45B2F1B4 Players=1 SaveType=None Mempak=Yes [5582CF3BB6E6B11D6D97F6FDD1EE9A3B] GoodName=Shadowgate 64 - Trials Of The Four Towers (E) [f1] (NTSC) CRC=80203B94 57B7F424 RefMD5=E8955C3B743FDDFE403E52E769E9853F [C4F4CA4FFA94A870D0A3E18B74FE9FDE] GoodName=Shadowgate 64 - Trials Of The Four Towers (J) [b1] CRC=CCEDB696 D3883DB4 RefMD5=1960A3879FADF2C5EFF5BEB47E0E1441 [66C31F31A386320F61AAF8F5F7936053] GoodName=Shadowgate 64 - Trials Of The Four Towers (J) [b2] CRC=CCEDB696 D3883DB4 RefMD5=1960A3879FADF2C5EFF5BEB47E0E1441 [1960A3879FADF2C5EFF5BEB47E0E1441] GoodName=Shadowgate 64 - Trials Of The Four Towers (J) [!] CRC=CCEDB696 D3883DB4 Players=1 SaveType=None Mempak=Yes [407A1A18BD7DBE0485329296C3F84EB8] GoodName=Shadowgate 64 - Trials Of The Four Towers (U) (M2) [!] CRC=036897CE E0D4FA54 Players=1 SaveType=None Mempak=Yes [3B21996F8C6496903C01DCBD77DDD6EE] GoodName=Shadowgate 64 - Trials Of The Four Towers (U) (M2) [f1] (PAL) CRC=015BB81E F105AC82 RefMD5=407A1A18BD7DBE0485329296C3F84EB8 [3D8F438057CB98F3C9E1472ABFF61610] GoodName=Shadowgate 64 - Trials Of The Four Towers (U) (M2) [f2] (PAL) CRC=123D0F44 CF60A446 RefMD5=407A1A18BD7DBE0485329296C3F84EB8 [F6B0E57512FDDD06345DD41B7C73B228] GoodName=Shag'a'Delic Demo by Steve and NEP (PD) CRC=9D9C362D 5BE66B08 [13893DB9E919C4E7CF0C0B0064CCB554] GoodName=Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban! (J) [!] CRC=D137A2CA 62B65053 Players=1 Rumble=Yes CountPerOp=1 [16EC788C8A4E7EEE268FDF9072A4F0D4] GoodName=Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban! (J) [b1] CRC=D137A2CA 62B65053 RefMD5=13893DB9E919C4E7CF0C0B0064CCB554 [13D9514A4D208DC6C7B0C833F68114D2] GoodName=Shin Nihon Pro Wrestling - Toukon Road - Brave Spirits (J) [!] CRC=EF703CA4 4D4A9AC9 Players=4 Mempak=Yes [DC1A78608B19DBE2AE3DC0CAD9B79472] GoodName=Shin Nihon Pro Wrestling - Toukon Road - Brave Spirits (J) [b1] CRC=EF703CA4 4D4A9AC9 RefMD5=13D9514A4D208DC6C7B0C833F68114D2 [113044B16B75F98792BF9C20C6B6282B] GoodName=Shin Nihon Pro Wrestling - Toukon Road 2 - The Next Generation (J) [!] CRC=551C7F43 9149831C Players=4 SaveType=SRAM Mempak=Yes [37149C4064A1D120B9F4F5482A915262] GoodName=Shuffle Puck 64 (PD) CRC=F7DF7D0D ED52018F [244BEA64EA209990E9C69A830B507135] GoodName=Sim City 2000 (J) [!] CRC=B1D5280C 4BA7BC2A Players=1 Mempak=Yes [FD2D06E59BF17A1BD1DA98454F83AB0D] GoodName=Sim City 2000 (J) [b1] CRC=B1D5280C 4BA7BC2A RefMD5=244BEA64EA209990E9C69A830B507135 [F0AD16AA47258818D320A5217F2E6B1E] GoodName=Sim City 2000 (J) [b1][o1] CRC=B1D5280C 4BA7BC2A RefMD5=244BEA64EA209990E9C69A830B507135 [A698B3419600E7E283AA1313FB2522CF] GoodName=Sim City 2000 (J) [b2] CRC=B1D5280C 4BA7BC2A RefMD5=244BEA64EA209990E9C69A830B507135 [65FC73D7ABFFABAFFF3C35FF3CB60DE2] GoodName=Sim City 2000 (J) [h1C] CRC=B1D5280C 4BA7BC2A RefMD5=244BEA64EA209990E9C69A830B507135 [137471D67DC8847815E327A73EA30068] GoodName=Sim City 2000 (J) [o1] CRC=B1D5280C 4BA7BC2A RefMD5=244BEA64EA209990E9C69A830B507135 [973DE87CFC38353259F3B1F6678FEB76] GoodName=Sim City 2000 (J) [o1][h1C] CRC=B1D5280C 4BA7BC2A RefMD5=244BEA64EA209990E9C69A830B507135 [A0E6FB493B57C2FAEE8E517E0330C23E] GoodName=Sim City 64 (J) [CART HACK] CRC=909535F8 118FEF8F [3E6FF36AE59F9261ED275FEABBF76CED] GoodName=Simon for N64 V0.1a by Jean-Luc Picard (POM '99) (PD) CRC=18531B7D 074AF73E SaveType=None Mempak=Yes Status=1 [F7F44996DD1140469C6C866DA0AFFAD7] GoodName=Sinus (PD) CRC=C603175E ACADF5EC Status=3 Players=0 SaveType=None [3194C65208047C938EF443325E1E73C1] GoodName=Sitero Demo by Renderman (PD) CRC=9A6CF2F5 D5F365EE [5AAC6E652C5CF1E37A466AC0073E88CA] GoodName=SmashRemix0.9.4 CRC=1B5AAD82 368B88C1 Status=3 SaveType=SRAM Players=4 Rumble=Yes CountPerOp=1 [983F8A1D9A8D6AA1A6500AF413CE31FF] GoodName=SmashRemix0.9.5b CRC=B9CDC5C3 0D2F4668 RefMD5=5AAC6E652C5CF1E37A466AC0073E88CA [D8D02E6F920E95047071E04420BB7D8F] GoodName=SmashRemix0.9.7 CRC=9D2B9C7F 6D90A8EF RefMD5=5AAC6E652C5CF1E37A466AC0073E88CA [8EC29958E0E3EB8C20AB7C9B3ACB07D8] GoodName=SmashRemix1.0.0 CRC=FD0E716E FB029C8E RefMD5=5AAC6E652C5CF1E37A466AC0073E88CA [0A6715A80957DD7C58F12E1F33D75F43] GoodName=SmashRemix1.0.1 CRC=FDFC3328 A0B2BA23 RefMD5=5AAC6E652C5CF1E37A466AC0073E88CA [D8AB932AFD1CED97ACD33FA984B309ED] GoodName=SmashRemix1.1.0 CRC=FB816989 6F442541 RefMD5=5AAC6E652C5CF1E37A466AC0073E88CA [70A61772B2123879367011A5E2900569] GoodName=SmashRemix1.1.1 CRC=FB816D35 3FC67AFF RefMD5=5AAC6E652C5CF1E37A466AC0073E88CA [44DE1F9ED1FA35B72D31A1F809285B01] GoodName=SmashRemix1.2.0 CRC=A1BFF9C9 8FB192A2 RefMD5=5AAC6E652C5CF1E37A466AC0073E88CA [B8D4B92E66A312708626B3216DE07A3A] GoodName=Snobow Kids (J) [!] CRC=84FC04FF B1253CE9 Players=4 SaveType=None Mempak=Yes Rumble=Yes [A29129B8C044D8A825F7F3780153FCC7] GoodName=Snobow Kids (J) [h1C] CRC=84FC04FF B1253CE9 RefMD5=B8D4B92E66A312708626B3216DE07A3A [4379C26BF067F7161BC6629445E22188] GoodName=Snobow Kids (J) [h2C] CRC=84FC04FF B1253CE9 RefMD5=B8D4B92E66A312708626B3216DE07A3A [F7E66DA23C8BB8E59F641A636A9CAE82] GoodName=Snow Speeder (J) [!] CRC=2EF4D519 C64A0C5E Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [F0FE973338C7170D54CB41602B9D48A3] GoodName=Snow Speeder (J) [b1] CRC=2EF4D519 C64A0C5E RefMD5=F7E66DA23C8BB8E59F641A636A9CAE82 [AB4382E583AE139EEDBAFCE5FA87E4C8] GoodName=Snowboard Kids (E) [!] CRC=5FD7CDA0 D9BB51AD Players=4 SaveType=None Mempak=Yes Rumble=Yes [55D13DC1512B1A3656DB8130E59E31D2] GoodName=Snowboard Kids (E) [h1C] CRC=5FD7CDA0 D9BB51AD RefMD5=AB4382E583AE139EEDBAFCE5FA87E4C8 [EB31F4F9C1FE26A3A663F74E9790516E] GoodName=Snowboard Kids (U) [!] CRC=DBF4EA9D 333E82C0 Players=4 SaveType=None Mempak=Yes Rumble=Yes [FB1F9F093F6081E5695F688B9EFD4095] GoodName=Snowboard Kids (U) [b1] CRC=DBF4EA9D 333E82C0 RefMD5=EB31F4F9C1FE26A3A663F74E9790516E [4B6914D5552E4FF348FB590D52A6DF8A] GoodName=Snowboard Kids (U) [b2] CRC=DBF4EA9D 333E82C0 RefMD5=EB31F4F9C1FE26A3A663F74E9790516E [349FF1B4AE28E31A2B2DC93D76A5219E] GoodName=Snowboard Kids (U) [b3] CRC=DBF4EA9D 333E82C0 RefMD5=EB31F4F9C1FE26A3A663F74E9790516E [759DF0ADF7F78D603AD344C89F360E32] GoodName=Snowboard Kids (U) [h1C] CRC=DBF4EA9D 333E82C0 RefMD5=EB31F4F9C1FE26A3A663F74E9790516E [641A6513E4FE77B88085478F99F1857D] GoodName=Snowboard Kids (U) [t1] CRC=A1E78A63 022A67C9 RefMD5=EB31F4F9C1FE26A3A663F74E9790516E [47B5E3955D54F969941533F26691AB38] GoodName=Snowboard Kids 2 (E) [!] CRC=C2751D1A F8C19BFF SaveType=Eeprom 4KB Players=4 Rumble=Yes [08E1152E9D9742E9BBF6C224B6958F2D] GoodName=Snowboard Kids 2 (U) [!] CRC=930C29EA 939245BF SaveType=Eeprom 4KB Players=4 Rumble=Yes [22C7FCDBC74DE237E0FC7778D8A6E671] GoodName=Snowboard Kids 2 (U) [f1] (PAL) CRC=D3DF2FEE 8090B699 RefMD5=08E1152E9D9742E9BBF6C224B6958F2D [835B149A0A312262A69DAA010728A825] GoodName=Snowboard Kids 2 (U) [f2] (PAL) CRC=D3DF2FEE 8090B699 RefMD5=08E1152E9D9742E9BBF6C224B6958F2D [B7240CADA85A35B6C872A865F6A018A1] GoodName=Soncrap Intro by RedboX (PD) CRC=AAA66229 98CA5CAA [7D47911B5C3D91A303EF19E764F3C02B] GoodName=Sonic Wings Assault (J) [!] CRC=22212351 4046594B Players=2 Rumble=Yes SaveType=Eeprom 4KB [D313AF5F8AF4D19F732A1A2C4D4D66BB] GoodName=South Park (B) [!] CRC=D21AF769 DE1A0E3D Players=4 SaveType=None Mempak=Yes Rumble=Yes [40CC2085A5C12456BEF830B047068326] GoodName=South Park (E) (M3) [!] CRC=20B53662 7B61899F Players=4 SaveType=None Mempak=Yes Rumble=Yes [26C99A528862342791193CA6AAACC9DD] GoodName=South Park (E) (M3) [b1] CRC=20B53662 7B61899F RefMD5=40CC2085A5C12456BEF830B047068326 [7C63BF480D1F84FC2C0D4A959154FA27] GoodName=South Park (E) (M3) [h1C] CRC=20B53662 7B61899F RefMD5=40CC2085A5C12456BEF830B047068326 [2C94A246E701D667BA807DAB6C9771E2] GoodName=South Park (G) [!] CRC=91B66D42 16AC4E46 Players=4 SaveType=None Mempak=Yes Rumble=Yes [1730119B0455EF89C4E495DEC8E950A5] GoodName=South Park (U) [!] CRC=7ECBE939 3C331795 Players=4 SaveType=None Mempak=Yes Rumble=Yes [BE22C6B95553B9CD5E0934B66BC36C84] GoodName=South Park (U) [b1] CRC=7ECBE939 3C331795 RefMD5=1730119B0455EF89C4E495DEC8E950A5 [6917DEEEBC2FA9E185582215E7460271] GoodName=South Park (U) [f1] (PAL) CRC=42EDB4BB DEA42760 RefMD5=1730119B0455EF89C4E495DEC8E950A5 [AC52781C224E9EB0B8F408A782FAC22A] GoodName=South Park (U) [t1] CRC=018CF733 5409AD45 RefMD5=1730119B0455EF89C4E495DEC8E950A5 [F1AE48B778C8431A50C37EB1ED96B120] GoodName=South Park - Chef's Luv Shack (E) [!] CRC=C00CA948 8E60D34B Players=4 SaveType=None [6AF573EB055648A8542AA82D9524FB2F] GoodName=South Park - Chef's Luv Shack (U) [!] CRC=C00CA948 8E60D34B Players=4 SaveType=None [FE2AA269FD3EC81C358845BBA6CA0167] GoodName=South Park - Chef's Luv Shack (U) [f1] (Country Check) CRC=C19EA928 226B2610 RefMD5=6AF573EB055648A8542AA82D9524FB2F [C33FA02791077A71B0AFE1CFED47C180] GoodName=South Park Rally (E) [!] CRC=4F8AFC3A F7912DF2 Players=4 SaveType=None Mempak=Yes Rumble=Yes [1C494719032FF99382B167C43FB11762] GoodName=South Park Rally (U) [!] CRC=07F3B276 EC8F3D39 Players=4 SaveType=None Mempak=Yes Rumble=Yes [CD17388E175BCF0F621EE9313D5A1C8D] GoodName=South Park Rally (U) [f1] (PAL) CRC=A4C8852A E512045C RefMD5=1C494719032FF99382B167C43FB11762 [5DA2C22480A3F6FE9BEF9C6AD4852D37] GoodName=South Park Rally (U) [t1] CRC=BE37CDC8 A88CB420 RefMD5=1C494719032FF99382B167C43FB11762 [DDA7AA9C5D1E617DA183750F82B55780] GoodName=South Park Rally (U) [t2] CRC=BE37CDC8 A88CB420 RefMD5=1C494719032FF99382B167C43FB11762 [7F9CDBBB1AAAAF0983C64988EF9C58BE] GoodName=Space Dynamites (J) [!] CRC=37463412 EAC5388D Players=2 SaveType=None [19BA66FEE088181BBB0ACA6894BB8971] GoodName=Space Dynamites (J) [b1] CRC=37463412 EAC5388D RefMD5=7F9CDBBB1AAAAF0983C64988EF9C58BE [C72417E0F8F043F9F11851633C4B1A57] GoodName=Space Invaders (U) [!] CRC=EBFE2397 FF74DA34 Players=2 SaveType=None Mempak=Yes Rumble=Yes [63FA04C30C4A0FBE162BCDEC3CB42888] GoodName=Space Invaders (U) [f1] (PAL) CRC=00EDCC34 75D2DEA0 RefMD5=C72417E0F8F043F9F11851633C4B1A57 [8C87830FF258893C453D70A90F62019F] GoodName=Space Invaders (U) [t1] CRC=33828616 933456E0 RefMD5=C72417E0F8F043F9F11851633C4B1A57 [4EE1DC953B1FF209811CF2808D78F064] GoodName=Space Invaders (U) [t2] CRC=138D7E56 72BCC9D9 RefMD5=C72417E0F8F043F9F11851633C4B1A57 [FCA7AFCADCF5E5545A62919BA94DAD18] GoodName=Space Station Silicon Valley (E) (M7) [!] CRC=FC70E272 08FFE7AA Players=1 SaveType=Eeprom 4KB Rumble=Yes [5919371BCA053C750D1CB357C58953A5] GoodName=Space Station Silicon Valley (E) (M7) [b1] CRC=FC70E272 08FFE7AA RefMD5=FCA7AFCADCF5E5545A62919BA94DAD18 [E66ED1CC4AB95D0872BB2EBC49B206C4] GoodName=Space Station Silicon Valley (J) [!] CRC=BFE23884 EF48EAAF Players=1 SaveType=Eeprom 4KB Rumble=Yes [868B37D1B66D1D994E2BAD4E218BF129] GoodName=Space Station Silicon Valley (U) [!] CRC=BFE23884 EF48EAAF Players=1 SaveType=Eeprom 4KB Rumble=Yes [4A8F8EBB93AF51878C8FB9057AD5F43C] GoodName=Space Station Silicon Valley (U) [f1] (PAL) CRC=47F09853 29CCE24F RefMD5=868B37D1B66D1D994E2BAD4E218BF129 [7AE0BA601FD72514C984BC80EE6BAB8E] GoodName=Space Station Silicon Valley (U) [f2] (PAL) CRC=BFE23884 EF48EAAF RefMD5=868B37D1B66D1D994E2BAD4E218BF129 [F1F1C5E2B895DB63348BC738C0CDC645] GoodName=Space Station Silicon Valley (U) (V1.1) [!] CRC=FC70E272 8FFE7AA Players=1 SaveType=Eeprom 4KB Rumble=Yes [630E4122B0743A29C246DA2C257F92DA] GoodName=Spacer by Memir (POM '99) (PD) CRC=A3A044B5 6DB1BF5E Players=4 Status=3 SaveType=None CountPerOp=1 [3A6A249843DDEAFFFD334AB3C5931F8D] GoodName=Spacer by Memir (POM '99) (PD) [t1] CRC=1B6FAB59 99199038 RefMD5=630E4122B0743A29C246DA2C257F92DA [A8E8AD9B1A05205085DCB4EADBE38020] GoodName=Spacer by Memir (POM '99) (PD) [t2] CRC=1B6FAB59 99199038 RefMD5=630E4122B0743A29C246DA2C257F92DA [E8D70E021C40078F8A82318AE8165A73] GoodName=Spacer by Memir (POM '99) (PD) [t2][b1] CRC=1B6FAB59 99199038 RefMD5=630E4122B0743A29C246DA2C257F92DA [44D7F3FC23428913D10E68017ACB097F] GoodName=Spice Girls Rotator Demo by RedboX (PD) [a1] CRC=8F5179C4 803526DC [1934618C99A70DD8E74305C6DB06CAF3] GoodName=Spice Girls Rotator Demo by RedboX (PD) CRC=8F5179C4 803526DC [7F1991B8861E7E532EC21ECF2AF82191] GoodName=Spider-Man (U) [!] CRC=A60ED171 3D85D06E Players=1 SaveType=None Mempak=Yes Rumble=Yes [8C5D52229DA5A223EA2DA093A5B9D31B] GoodName=Spider-Man (U) [t1] CRC=3E6250B2 12F5155C RefMD5=7F1991B8861E7E532EC21ECF2AF82191 [041CE6116C560C239023EFB88705DA94] GoodName=Split! 3D Demo by Lem (PD) CRC=60B8BCC9 2EC4DFB6 [515C86480A7FC1238BFE252BD2C53B36] GoodName=Sporting Clays by Charles Doty (PD) CRC=E584FE34 9D91B1E2 Players=1 SaveType=None Status=3 [993CCC0961CFD9F1342AD99A1BA2E282] GoodName=Sporting Clays by Charles Doty (PD) [a1] CRC=5402C27E 60021F86 RefMD5=515C86480A7FC1238BFE252BD2C53B36 [094FE60C44F35BDC7FBE85339E9C4470] GoodName=Sporting Clays by Charles Doty (PD) [b1] CRC=E584FE34 9D91B1E2 RefMD5=515C86480A7FC1238BFE252BD2C53B36 [B2242070800BF82E78CE33DC92A1DB84] GoodName=Star Fox 64 (Ch) (V5) (iQue) [!] [3DCD5E15AA35A73C68DB4F56E2670FA2] GoodName=Star Fox 64 (Ch) (V4) (iQue) (Manual) [!] [446D5215C4D34EB8AB0F355F324B8D0E] GoodName=Star Fox 64 (J) (V1.0) [!] CRC=FFCAA7C1 68858537 Players=4 SaveType=Eeprom 4KB Rumble=Yes [C4179723DC6E5D319C97F2F66AB05162] GoodName=Star Fox 64 (J) (V1.0) [f1] CRC=FFCAA7C1 68858537 RefMD5=446D5215C4D34EB8AB0F355F324B8D0E [D0DD14F100B3825536DB8F32C332457F] GoodName=Star Fox 64 (J) (V1.0) [o1] CRC=FFCAA7C1 68858537 RefMD5=446D5215C4D34EB8AB0F355F324B8D0E [D43D1E41DBA17FFF92829FD2495B7619] GoodName=Star Fox 64 (J) (V1.0) [o1][f1] CRC=FFCAA7C1 68858537 RefMD5=446D5215C4D34EB8AB0F355F324B8D0E [0C9F7FA54CA36BFC6D8BE4187E4ABD99] GoodName=Star Fox 64 (J) (V1.0) [o2][f1] CRC=FFCAA7C1 68858537 RefMD5=446D5215C4D34EB8AB0F355F324B8D0E [B74F70654B2FE3FC573D3BC913A62268] GoodName=Star Fox 64 (J) (V1.0) [o3][f1] CRC=FFCAA7C1 68858537 RefMD5=446D5215C4D34EB8AB0F355F324B8D0E [AF8A5A437F286FA230D99507109C79D9] GoodName=Star Fox 64 (J) (V1.0) [t1] (Boost) CRC=305AB328 F72F632A RefMD5=446D5215C4D34EB8AB0F355F324B8D0E [5E3B1FAC7C16D30499B3FAA36CAF98FD] GoodName=Star Fox 64 (J) (V1.0) [t2] (No Damage-Unbreakable Wings) CRC=1180A247 EBE234B3 RefMD5=446D5215C4D34EB8AB0F355F324B8D0E [91FC4C63CA613530DF22C8BB810CB2C3] GoodName=Star Fox 64 (J) (V1.1) (VC) [!] CRC=65AEDEEF 3857C728 Players=4 SaveType=Eeprom 4KB Rumble=Yes [CAF9A78DB13EE00002FF63A3C0C5EABB] GoodName=Star Fox 64 (U) (V1.0) [!] CRC=A7D015F8 2289AA43 Players=4 SaveType=Eeprom 4KB Rumble=Yes [5653B6DDAE328C870138E71EC30122A1] GoodName=Star Fox 64 (U) (V1.0) [f1] CRC=A7D015F8 2289AA43 RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [ECB9184142D288B40BCD198FB191A275] GoodName=Star Fox 64 (U) (V1.0) [f1][h1C] CRC=A7D015F8 2289AA43 RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [E566D58641BEDD25C450E443608EB46E] GoodName=Star Fox 64 (U) (V1.0) [f1][o1] CRC=A7D015F8 2289AA43 RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [D81FFD06311AB9334858CCC28EFE992A] GoodName=Star Fox 64 (U) (V1.0) [f2] (PAL) CRC=CBD83828 6FDEBEDC RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [7052F9C1BE69B103D6BE3DE61A94F861] GoodName=Star Fox 64 (U) (V1.0) [h1C] CRC=A7D015F8 2289AA43 RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [80E9D39B21E537FF53FD362B7272F255] GoodName=Star Fox 64 (U) (V1.0) [o1][f1] CRC=A7D015F8 2289AA43 RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [06DB24BEFB76C04D06D4DDC3A50D5319] GoodName=Star Fox 64 (U) (V1.0) [o2][f1] CRC=CBD83828 6FDEBEDC RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [831DC9EEB9114912ABABC15B6B14DA4B] GoodName=Star Fox 64 (U) (V1.0) [o3][f1] CRC=A7D015F8 2289AA43 RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [23E5AF30267036A69A8328F005DF07B1] GoodName=Star Fox 64 (U) (V1.0) [t1] CRC=CBD83828 6FDEBEDC RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [3D38BCD5B57CEECB0985609CCE940FFA] GoodName=Star Fox 64 (U) (V1.0) [t2] (Boost) CRC=1B80E202 CB5AE74F RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [63CE29BBA130AACD05402EFC06C0DC89] GoodName=Star Fox 64 (U) (V1.0) [t3] (No Damage-Unbreakable Wings) CRC=F6621BFB 186D11A6 RefMD5=CAF9A78DB13EE00002FF63A3C0C5EABB [741A94EEE093C4C8684E66B89F8685E8] GoodName=Star Fox 64 (U) (V1.1) [!] CRC=BA780BA0 0F21DB34 Players=4 SaveType=Eeprom 4KB Rumble=Yes [F0CD3B2DB0F20FFDD64BF081176EB421] GoodName=Star Fox 64 (U) (V1.1) [t1] (Energy) CRC=C3CA0BA3 25397DC8 RefMD5=741A94EEE093C4C8684E66B89F8685E8 [FFA562936DB863EA02204F9F514B6067] GoodName=Star Fox 64 (U) (V1.1) [t2] (Boost) CRC=8264014A 3C9FBFC1 RefMD5=741A94EEE093C4C8684E66B89F8685E8 [14A21928BE46C18BA04161305E89F5DE] GoodName=Star Soldier - Vanishing Earth (J) [!] CRC=B703EB23 28AAE53A Players=1 SaveType=Eeprom 4KB Rumble=Yes [565DA8D53422F16207ECF11A81D2E649] GoodName=Star Soldier - Vanishing Earth (J) [b1] CRC=B703EB23 28AAE53A RefMD5=14A21928BE46C18BA04161305E89F5DE [006CAFEC9BA13060D4D2F0BE211081BD] GoodName=Star Soldier - Vanishing Earth (J) [h1C] CRC=B703EB23 28AAE53A RefMD5=14A21928BE46C18BA04161305E89F5DE [97275F6585547462A73910E9A80E4067] GoodName=Star Soldier - Vanishing Earth (J) [o1] CRC=B703EB23 28AAE53A RefMD5=14A21928BE46C18BA04161305E89F5DE [CD40D9DD238E23AD79DC4484F77A7C4A] GoodName=Star Soldier - Vanishing Earth (J) [t1] CRC=31100ADC 86E97D63 RefMD5=14A21928BE46C18BA04161305E89F5DE [EE045A2E9F924CD8FD00018B50E46650] GoodName=Star Soldier - Vanishing Earth (U) [!] CRC=DDD93C85 DAE381E8 Players=1 SaveType=Eeprom 4KB Rumble=Yes [A68B65E6B4BC976AD9DEAB335DE3BF70] GoodName=Star Soldier - Vanishing Earth (U) [t1] CRC=DDD982EF 3B0D6FEC RefMD5=EE045A2E9F924CD8FD00018B50E46650 [0529542DE0794316320CF99EA80C51B7] GoodName=Star Soldier - Vanishing Earth Arcade (Aleck64) CRC=315C7466 3A453265 SaveType=Eeprom 4KB [CA28A3645FC7AD969EBD75C5D6506E7A] GoodName=Star Twins (J) [!] CRC=F163A242 F2449B3B Players=4 SaveType=Flash RAM Rumble=Yes [7F919D2E35CBE561E139AE8FE93ACA86] GoodName=Star Wars - Rogue Squadron (E) (M3) (V1.0) [!] CRC=7EE0E8BB 49E411AA Players=1 SaveType=Eeprom 4KB Rumble=Yes [E1376F9B151EE3DA3E8ED52D970480EF] GoodName=Star Wars - Rogue Squadron (E) (M3) (V1.0) (Language Select Hack) CRC=7EE0E945 7D8FEE20 RefMD5=7F919D2E35CBE561E139AE8FE93ACA86 [231F61E0D66A70B173BB22672EE67BD6] GoodName=Star Wars - Rogue Squadron (E) (M3) (V1.0) [t1] CRC=5E6508BB F321C996 RefMD5=7F919D2E35CBE561E139AE8FE93ACA86 [A9DD498E6A28F55311CE4EF057E164B8] GoodName=Star Wars - Rogue Squadron (E) (M3) (V1.1) [!] CRC=219191C1 33183C61 RefMD5=7F919D2E35CBE561E139AE8FE93ACA86 [47CAC4E2A6309458342F21A9018FFBF0] GoodName=Star Wars - Rogue Squadron (U) (M3) (V1.0) [!] CRC=66A24BEC 2EADD94F Players=1 SaveType=Eeprom 4KB Rumble=Yes [0583AD9FDD1E3D10076AAB40E5B4E7BB] GoodName=Star Wars - Rogue Squadron (U) (M3) (V1.0) [b1] CRC=66A24BEC 2EADD94F RefMD5=47CAC4E2A6309458342F21A9018FFBF0 [6560FFC9208A31F0518036F7937B53DA] GoodName=Star Wars - Rogue Squadron (U) (M3) (V1.0) [h1] (Language Select) CRC=66A24A12 22AF6AC2 RefMD5=47CAC4E2A6309458342F21A9018FFBF0 [4903C39007AEACC113FE0E9E4BBE4711] GoodName=Star Wars - Rogue Squadron (U) (M3) (V1.0) [t1] CRC=165CBDA2 05A62246 RefMD5=47CAC4E2A6309458342F21A9018FFBF0 [2E458D7CC355D7918493B0E0362C9A20] GoodName=Star Wars - Rogue Squadron (U) (M3) (V1.1) [!] CRC=C7F30CFA ECB0FA36 RefMD5=47CAC4E2A6309458342F21A9018FFBF0 [591CF8E672C9CC0FE9C871CC56DCC854] GoodName=Star Wars - Shadows of the Empire (E) [!] CRC=4D486681 AB7D9245 Players=1 SaveType=Eeprom 4KB [818737338B3F1D87B7E1B7FB55057BB5] GoodName=Star Wars - Shadows of the Empire (E) [b1] CRC=4D486681 AB7D9245 RefMD5=591CF8E672C9CC0FE9C871CC56DCC854 [E83325EC6E8520B0CBDB49B52418FE4E] GoodName=Star Wars - Shadows of the Empire (E) [b2] CRC=4D486681 AB7D9245 RefMD5=591CF8E672C9CC0FE9C871CC56DCC854 [64E59BA2F7BA4DAFFDD5934F818DC7DA] GoodName=Star Wars - Shadows of the Empire (E) [b3] CRC=4D486681 AB7D9245 RefMD5=591CF8E672C9CC0FE9C871CC56DCC854 [554BFCC857BE49B2AACD077E6059B281] GoodName=Star Wars - Shadows of the Empire (E) [b4] CRC=4D486681 AB7D9245 RefMD5=591CF8E672C9CC0FE9C871CC56DCC854 [30BDF5405A8C615DC924DB9480E996B7] GoodName=Star Wars - Shadows of the Empire (E) [o1] CRC=4D486681 AB7D9245 RefMD5=591CF8E672C9CC0FE9C871CC56DCC854 [4076973CFDA277FC876E9F066CC73DEB] GoodName=Star Wars - Shadows of the Empire (U) (Prototype) CRC=FB315F95 7786CBFB [5CCE8AD5F86E8A373A7525DC4C7E6705] GoodName=Star Wars - Shadows of the Empire (U) (V1.0) [!] CRC=264D7E5C 18874622 Players=1 SaveType=Eeprom 4KB [C88637DCC7A00FED6297B61E79CF75A9] GoodName=Star Wars - Shadows of the Empire (U) (V1.0) [b1] CRC=BC3C9F6C 93B3CB13 RefMD5=5CCE8AD5F86E8A373A7525DC4C7E6705 [C68CB260A7FD8D177640FA487DCCACF6] GoodName=Star Wars - Shadows of the Empire (U) (V1.0) [b2] CRC=BDA75F12 BDDC1661 RefMD5=5CCE8AD5F86E8A373A7525DC4C7E6705 [7527B90543E3D6042A72619818B47145] GoodName=Star Wars - Shadows of the Empire (U) (V1.0) [o1] CRC=264D7E5C 18874622 RefMD5=5CCE8AD5F86E8A373A7525DC4C7E6705 [C69FA82E2CA2460000C629E9D46D4DC2] GoodName=Star Wars - Shadows of the Empire (U) (V1.0) [t1] CRC=BC3C9F6C 93B3CB13 RefMD5=5CCE8AD5F86E8A373A7525DC4C7E6705 [F8906B10BAE363ACB170FA841A88E96C] GoodName=Star Wars - Shadows of the Empire (U) (V1.0) [t2] CRC=BDA75F12 BDDC1661 RefMD5=5CCE8AD5F86E8A373A7525DC4C7E6705 [FA635E837275D28FD5A24D5675BA42C8] GoodName=Star Wars - Shadows of the Empire (U) (V1.1) [!] CRC=4147B091 63251060 Players=1 SaveType=Eeprom 4KB [E8EE7D44858C1AB90C1F48A649DC98B6] GoodName=Star Wars - Shadows of the Empire (U) (V1.1) [b1] CRC=D3E792A5 05D39C97 RefMD5=FA635E837275D28FD5A24D5675BA42C8 [64B4FB2D4C49AE6902F13149C81CF2A1] GoodName=Star Wars - Shadows of the Empire (U) (V1.1) [o1] CRC=4147B091 63251060 RefMD5=FA635E837275D28FD5A24D5675BA42C8 [7BC08EAF55A645DE9226617C3F83B19F] GoodName=Star Wars - Shadows of the Empire (U) (V1.1) [t1] CRC=D3E792A5 05D39C97 RefMD5=FA635E837275D28FD5A24D5675BA42C8 [C7B40352AAD8D863D88D51672F9A0087] GoodName=Star Wars - Shadows of the Empire (U) (V1.2) [!] CRC=4DD7ED54 74F9287D Players=1 SaveType=Eeprom 4KB [3FE2B38E18152162A34E3002DEA071F7] GoodName=Star Wars - Shadows of the Empire (U) (V1.2) [b1] CRC=D3E792A5 05D39C97 RefMD5=C7B40352AAD8D863D88D51672F9A0087 [3BD4EE76D4CBB14D69BA628533BD7CBC] GoodName=Star Wars - Shadows of the Empire (U) (V1.2) [b2] CRC=D3E792A5 05D39C97 RefMD5=C7B40352AAD8D863D88D51672F9A0087 [CD2C0DFDAC5572988AAB98D125EEEB53] GoodName=Star Wars - Shadows of the Empire (U) (V1.2) [o1] CRC=4DD7ED54 74F9287D RefMD5=C7B40352AAD8D863D88D51672F9A0087 [4E12B97690897465A27BDF0DDA722826] GoodName=Star Wars - Shadows of the Empire (U) (Unl) CRC=1C5EE088 D32A963D RefMD5=C7B40352AAD8D863D88D51672F9A0087 [8603B180E70B2A72EF77D46C2BEC2234] GoodName=Star Wars - Shutsugeki! Rogue Chuutai (J) [!] CRC=827E4890 958468DC Players=1 SaveType=Eeprom 4KB Rumble=Yes [5B6B6B0C8C9A40286DCF61706B6A05CB] GoodName=Star Wars - Teikoku no Kage (J) [!] CRC=FE24AC63 1B41AA17 Players=1 SaveType=Eeprom 4KB [B5FDFDF26E1F27EAF0BD849CAA4CC3B8] GoodName=Star Wars - Teikoku no Kage (J) [o1] CRC=FE24AC63 1B41AA17 RefMD5=5B6B6B0C8C9A40286DCF61706B6A05CB [222F1E75F70A654B642382989E024749] GoodName=Star Wars - Teikoku no Kage (J) [o2] CRC=FE24AC63 1B41AA17 RefMD5=5B6B6B0C8C9A40286DCF61706B6A05CB [0BD1F7BB9F4B02520E4E9285C809F099] GoodName=Star Wars Episode I - Battle for Naboo (E) [!] CRC=EAE6ACE2 020B4384 Players=1 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [3CB88B934572E7520F35E5458798775B] GoodName=Star Wars Episode I - Battle for Naboo (U) [!] CRC=3D02989B D4A381E2 Players=1 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [B4724120C269A1DC86991D34B1561F3D] GoodName=Star Wars Episode I - Battle for Naboo (U) [b1] CRC=3D02989B D4A381E2 RefMD5=3CB88B934572E7520F35E5458798775B [24E6E064454DE99C88EBA9F8C3574AF3] GoodName=Star Wars Episode I - Battle for Naboo (U) [t1] CRC=FD8F6875 42608FDC RefMD5=3CB88B934572E7520F35E5458798775B [6EF9FED309F28BD59B605F128869AA00] GoodName=Star Wars Episode I - Racer (E) (M3) [!] CRC=53ED2DC4 06258002 Players=2 SaveType=Eeprom 16KB Rumble=Yes [73113AE7AAF0911BA6A1DF1353980D14] GoodName=Star Wars Episode I - Racer (E) [T+Spa1.0.2_IlDucci] CRC=E857ED95 6028F9AF RefMD5=6EF9FED309F28BD59B605F128869AA00 [8CC7E31925FBFA13A584F529E8912207] GoodName=Star Wars Episode I - Racer (E) (M3) [f1] (Save) CRC=166312CB C30220D2 RefMD5=6EF9FED309F28BD59B605F128869AA00 [7579AB0E79B1011479B88F2BF39D48E0] GoodName=Star Wars Episode I - Racer (J) [!] CRC=61F5B152 046122AB Players=2 SaveType=Eeprom 16KB Rumble=Yes [CFA21E43DAC50DFF3122ABF3AF3511F8] GoodName=Star Wars Episode I - Racer (J) [b1] CRC=61F5B152 046122AB RefMD5=7579AB0E79B1011479B88F2BF39D48E0 [1EE8800A4003E7F9688C5A35F929D01B] GoodName=Star Wars Episode I - Racer (U) [!] CRC=72F70398 6556A98B Players=2 SaveType=Eeprom 16KB Rumble=Yes [E4353B43CB4302B7A308A42D6BB04435] GoodName=Star Wars Episode I - Racer (U) [f1] (Save) CRC=86EDC3C1 E983A7BF RefMD5=1EE8800A4003E7F9688C5A35F929D01B [D6EED7BA15E4CF88B4D235A016B1C880] GoodName=Star Wars Episode I - Racer (U) [t1] CRC=C3193C16 53A19708 RefMD5=1EE8800A4003E7F9688C5A35F929D01B [81FE5AD03175B6F2D23DBF5A549B0CDA] GoodName=Star Wars Episode I - Racer (U) [t2] CRC=1C37BF54 AC368304 RefMD5=1EE8800A4003E7F9688C5A35F929D01B [0BE4958B3E8EED916307DC9F5DE3206D] GoodName=Star Wars Episode I - Racer (U) [t3] CRC=88C79381 85786A83 RefMD5=1EE8800A4003E7F9688C5A35F929D01B [F21C920F0A7BF42F80C38C39CD61BD60] GoodName=Star Wars Episode I - Racer (U) [t4] CRC=B722133E 5EECEC4D RefMD5=1EE8800A4003E7F9688C5A35F929D01B [0B2B4D3C38426763059D68AA53B86FDF] GoodName=Star Wars Episode I - Racer (U) (Unl) CRC=21CD632F 8BCA2AD4 RefMD5=1EE8800A4003E7F9688C5A35F929D01B [3EB732A8D004263AD8EB0DA59A29582A] GoodName=StarCraft 64 (Beta) CRC=BC9B2CC3 4ED04DA5 Status=1 Players=2 SaveType=Flash RAM Rumble=Yes [432DF5EAC0BA573C6587A5BB4E51834A] GoodName=StarCraft 64 (Beta) [f1] CRC=BC9B2CC3 4ED04DA5 RefMD5=3EB732A8D004263AD8EB0DA59A29582A [30486A26C7B87CDBDB1A421493CC745A] GoodName=StarCraft 64 (Beta) [f2] (PAL) CRC=036A20D8 A99C4D3D RefMD5=3EB732A8D004263AD8EB0DA59A29582A [A9683B99E82271DBF84DDB59806E9423] GoodName=StarCraft 64 (Beta) [f3] (Country Code) CRC=BC9B2CC3 4ED04DA5 RefMD5=3EB732A8D004263AD8EB0DA59A29582A [72B60FAC5EE257FA387B43C57632D50C] GoodName=StarCraft 64 (E) [!] CRC=42CF5EA3 9A1334DF Status=1 Players=2 SaveType=Flash RAM Rumble=Yes [B75945407D7DEA00A2A29AD24056A416] GoodName=StarCraft 64 (E) [b1] CRC=42CF5EA3 9A1334DF RefMD5=72B60FAC5EE257FA387B43C57632D50C [762543CC6409C199FD50A3BCF545730D] GoodName=StarCraft 64 (E) [f1] (NTSC) CRC=C7501968 06533B11 RefMD5=72B60FAC5EE257FA387B43C57632D50C [356A5D3D59E0ADEF6EFAE6096FC20F77] GoodName=StarCraft 64 (G) (Prototype) CRC=FD6907F0 83CBC160 [559F71B861F639B6376D891E3023414B] GoodName=StarCraft 64 (U) [!] CRC=0684FBFB 5D3EA8A5 Status=1 Players=2 SaveType=Flash RAM Rumble=Yes [A9C393AA232B32798ADF378F4318F99F] GoodName=Starshot - Space Circus Fever (E) (M3) [!] CRC=D89E0E55 B17AA99A Players=1 SaveType=Eeprom 4KB [B23BFC7DC874DDAA2005F9AFF59A47FF] GoodName=Starshot - Space Circus Fever (E) (M3) [f1] (NTSC100%) CRC=287AAA27 8C2C02D8 RefMD5=A9C393AA232B32798ADF378F4318F99F [AA11E9E44B401794C37290896C9412AC] GoodName=Starshot - Space Circus Fever (E) (M3) [f2] (NTSC) CRC=AD199971 1075F279 RefMD5=A9C393AA232B32798ADF378F4318F99F [BAE518E0D40F846B17C510E4EA9E8C52] GoodName=Starshot - Space Circus Fever (E) (M3) [f3] (NTSC) CRC=ADD78971 A09C18CF RefMD5=A9C393AA232B32798ADF378F4318F99F [530B796EA3B1748841F9D057F3F9EFA8] GoodName=Starshot - Space Circus Fever (E) (M3) [t1] CRC=AD197171 04DB7E9E RefMD5=A9C393AA232B32798ADF378F4318F99F [42AF1992978229BBB5F560571708E25E] GoodName=Starshot - Space Circus Fever (U) (M3) [!] CRC=94EDA5B8 8673E903 Players=1 SaveType=Eeprom 4KB [BD22A79568534B42EAA3D8DB9A7C4C91] GoodName=Starshot - Space Circus Fever (U) (M3) [b1] CRC=94EDA5B8 8673E903 RefMD5=42AF1992978229BBB5F560571708E25E [E8B666A429FEDB2A1A1228CD450CD4FC] GoodName=Stunt Racer 64 (U) [!] CRC=9510D8D7 35100DD2 Players=4 SaveType=None Mempak=Yes Rumble=Yes [14DDF19382385774F253049ABEAF01D2] GoodName=Summer64 Demo by Lem (PD) [b1] CRC=4794B85F 3EBD5B68 [1B1DC8B1DD950E70C0F532DD81C9A982] GoodName=Summer64 Demo by Lem (PD) CRC=4794B85F 3EBD5B68 [B3C1D4B9EC7DCD2922E681DBBC393915] GoodName=Super B-Daman - Battle Phoenix 64 (J) [!] CRC=F4646B69 C5751095 Players=4 Mempak=Yes Transferpak=Yes [4168C145279EA29912BA0E35DCA35289] GoodName=Super Bomberman 2 by Rider (POM '99) (PD) CRC=BB214F79 8B88B16B Status=1 Players=4 [09C5B4D19364EFE48BB818087734978E] GoodName=Super Bowling (J) [!] CRC=F3F2F385 6E490C7F Players=4 SaveType=None Mempak=Yes Rumble=Yes [FA3A043997A3ACDF17337385B126BC04] GoodName=Super Bowling (U) [!] CRC=AA1D215A 91CBBE9A Players=4 SaveType=None Mempak=Yes Rumble=Yes [7FCF424B960F4E429FD683A4B19B3356] GoodName=Super Fighter Demo Halley's Comet Software (PD) CRC=1AD61BB9 F1E2BE1A [A215BC1CE06960E0C469DB9520E907C6] GoodName=Super Irishley Drunk Giant WaLuigi 64 (Super Mario 64 Hack) CRC=635A42C5 BDC58EDC [29047FBA820695BD14C5BD7AA1AA4400] GoodName=Super Mario 64 (Ch) (iQue) [!] Players=1 [B4BD31B13E474DF29922150E1EF3F328] GoodName=Super Mario 64 (Ch) (V6) (iQue) (Manual) [!] [45676429EF6B90E65B517129B700308E] GoodName=Super Mario 64 (E) (M3) [!] CRC=A03CF036 BCC1C5D2 Players=1 Status=4 SaveType=Eeprom 4KB [9EE432F07F1E4E9A13CD0090CCC5A94B] GoodName=Super Mario 64 (E) (M3) [b1] CRC=A03CF036 BCC1C5D2 RefMD5=45676429EF6B90E65B517129B700308E [225223ABF4BC1F3E38A45873BA94CEBC] GoodName=Super Mario 64 (E) (M3) [b2] CRC=A03CF036 BCC1C5D2 RefMD5=45676429EF6B90E65B517129B700308E [6A954E08533C13DBD7599068D03A3ADB] GoodName=Super Mario 64 (E) (M3) [h1C] CRC=A03CF036 BCC1C5D2 RefMD5=45676429EF6B90E65B517129B700308E [D1F6BC22557BF5607AA2E3C61BE44D59] GoodName=Super Mario 64 (E) (M3) [o1] CRC=A03CF036 BCC1C5D2 RefMD5=45676429EF6B90E65B517129B700308E [DF2031338C9B0AB8317661AFA64E5F9E] GoodName=Super Mario 64 (E) (M3) [o2] CRC=A03CF036 BCC1C5D2 RefMD5=45676429EF6B90E65B517129B700308E [121A19E2A547C554155433788986033C] GoodName=Super Mario 64 (E) (M3) [t1] CRC=77C44B0F 5E8948A3 RefMD5=45676429EF6B90E65B517129B700308E [994D171A0154ABE747338890AF179252] GoodName=Super Mario 64 (E) (M3) [t2] CRC=16510823 E2EEE387 RefMD5=45676429EF6B90E65B517129B700308E [85D61F5525AF708C9F1E84DCE6DC10E9] GoodName=Super Mario 64 (J) [!] CRC=4EAA3D0E 74757C24 Players=1 Status=4 SaveType=Eeprom 4KB [6614298A943234FD30885BD0B1383CBB] GoodName=Super Mario 64 (J) [T+Kor1.0_Minio] CRC=B36CF0BE A35F5C7B RefMD5=85D61F5525AF708C9F1E84DCE6DC10E9 [DBF7F4D881E1DF604C41367B04233E74] GoodName=Super Mario 64 (J) [h1C] CRC=4EAA3D0E 74757C24 RefMD5=85D61F5525AF708C9F1E84DCE6DC10E9 [20B854B239203BAF6C961B850A4A51A2] GoodName=Super Mario 64 (U) [!] CRC=635A2BFF 8B022326 Players=1 Status=4 SaveType=Eeprom 4KB [E458F74E694B2916EBA9818103F7CF13] GoodName=Super Mario 64 (U) (Enable Hidden Scroller Hack) CRC=DACDE68E 7381B3C9 RefMD5=20B854B239203BAF6C961B850A4A51A2 [FF5A05FFDE29707C15D89E807ED66B81] GoodName=Super Mario 64 (U) (No Cap Hack) CRC=5B5DA9FB 11EEE5E5 RefMD5=20B854B239203BAF6C961B850A4A51A2 [6C5AEE2BE768E581038F3B211D7F6066] GoodName=Super Mario 64 (U) (Silver Mario Hack) CRC=658E2804 443386FA RefMD5=20B854B239203BAF6C961B850A4A51A2 [597204EE766B93C1AE33B7FC0739E170] GoodName=Super Mario 64 (U) [T+Rus] CRC=267FBAD5 7593FADC RefMD5=20B854B239203BAF6C961B850A4A51A2 [E51A6FF9B2DBBD216158CACFF35EB215] GoodName=Super Mario 64 (U) [T+SpaFinal_Mistergame] CRC=635A42C5 BDC58EDC RefMD5=20B854B239203BAF6C961B850A4A51A2 [99BD941850AA68440B886EA05539F7DC] GoodName=Super Mario 64 (U) [T+SpaFinal_Mistergame][a1] CRC=635A42C5 BDC58EDC RefMD5=20B854B239203BAF6C961B850A4A51A2 [E2FCF7782B622495FABE12FC7244B35B] GoodName=Super Mario 64 (U) [T+Spa3.9_Blade133bo] CRC=88EC3675 59CE4583 RefMD5=20B854B239203BAF6C961B850A4A51A2 Rumble=Yes [35BBAF4869D0B0D2147D35F1EC3CF2CA] GoodName=Super Mario 64 (U) [T-Ita1.0final_beta1_Rulesless] CRC=819D5B33 A5096295 RefMD5=20B854B239203BAF6C961B850A4A51A2 [CDACC6FE2CC7851A1110A60CE76FBDFB] GoodName=Super Mario 64 (U) [T+Ita2.0final_beta2_Rulesless] CRC=490A59F2 22BC515E RefMD5=20B854B239203BAF6C961B850A4A51A2 [E5544B156833120E7B97A05AAB743F98] GoodName=Super Mario 64 (U) [T+Ita4.2_Rulesless] CRC=5EDE011C E166686 RefMD5=20B854B239203BAF6C961B850A4A51A2 Rumble=Yes [933C474FC970A0E7D659F32334DB6475] GoodName=Super Mario 64 (U) [b1] CRC=635A2BFF 8B022326 RefMD5=20B854B239203BAF6C961B850A4A51A2 [0513A584BC6B3859555E72E10008B55F] GoodName=Super Mario 64 (U) [b2] CRC=77C44B0F 5E8948A3 RefMD5=20B854B239203BAF6C961B850A4A51A2 [C3A4EBEEA4D22D8FC245B346D5C1A81E] GoodName=Super Mario 64 (U) [h1C] CRC=635A2BFF 8B022326 RefMD5=20B854B239203BAF6C961B850A4A51A2 [179537A49DAA33BF031F09A9589EAA28] GoodName=Super Mario 64 (U) [h2C] CRC=635A2BFF 8B022326 RefMD5=20B854B239203BAF6C961B850A4A51A2 [AED29A731056F34B79E6B996BDBAFB63] GoodName=Super Mario 64 (U) [o1] CRC=635A2BFF 8B022326 RefMD5=20B854B239203BAF6C961B850A4A51A2 [3F3EBFAD624D623FAFEF767B99609E15] GoodName=Super Mario 64 (U) [t1] (Invincible) CRC=5C8BD407 63F71E2A RefMD5=20B854B239203BAF6C961B850A4A51A2 [B48A8F8E2D9C7403210C2AA5262D94C7] GoodName=Super Mario 64 (U) [t2] (Speed) CRC=5B652BFF 8FA82E35 RefMD5=20B854B239203BAF6C961B850A4A51A2 [C293D2ADF01E0528554CDBADF0F86554] GoodName=Super Mario 64 (U) [t3] CRC=FECE2B85 331406D1 RefMD5=20B854B239203BAF6C961B850A4A51A2 [A75637B1D22F59F2C32BDA359A9EE79E] GoodName=Super Mario Magic Plant Adventure 64 (Super Mario 64 Hack) CRC=635A42C5 BDC58EDC RefMD5=20B854B239203BAF6C961B850A4A51A2 [338FAA6E250F72F1B1D7B873BFAEE918] GoodName=SM64 Splitscreen Multiplayer Beta CRC=5C277FBA E8A351C9 RefMD5=20B854B239203BAF6C961B850A4A51A2 [F0595A36EAB6109C5FF2420EB452B6E2] GoodName=SM64 Splitscreen Multiplayer CRC=13CD0830 3CCF65E9 RefMD5=20B854B239203BAF6C961B850A4A51A2 [2D727C3278AA232D94F2FB45AEC4D303] GoodName=Super Mario 64 - Shindou Edition (J) [!] CRC=D6FBA4A8 6326AA2C Players=1 Status=4 SaveType=Eeprom 4KB Rumble=Yes [A00D0D095592113A279A27ACD785CE50] GoodName=Super Mario 64 - Shindou Edition (J) [T+Kor1.0_Minio] CRC=C1373DC8 ED88D197 RefMD5=2D727C3278AA232D94F2FB45AEC4D303 [23033085561CD331CC81F0026FCB2CE2] GoodName=Super Mario 64 - Shindou Edition (J) [b1] CRC=D6FBA4A8 6326AA2C RefMD5=2D727C3278AA232D94F2FB45AEC4D303 [8C361E9283D740E2F266782D9C1CE914] GoodName=Super Mario 64 - Shindou Edition (J) [b2] CRC=D6FBA4A8 6326AA2C RefMD5=2D727C3278AA232D94F2FB45AEC4D303 [E824B289A850E7E161AF761D876F1CAE] GoodName=Super Mario 64 - Shindou Edition (J) [h1C] CRC=D6FBA4A8 6326AA2C RefMD5=2D727C3278AA232D94F2FB45AEC4D303 [7BA990008966BDA71D8CB78FB7BA414E] GoodName=Super Mario 64 - Shindou Edition (J) [h2C] CRC=D6FBA4A8 6326AA2C RefMD5=2D727C3278AA232D94F2FB45AEC4D303 [3EC3F83EAB22702E146C467EB1DB45FA] GoodName=Super Robot Spirits (J) [!] CRC=66572080 28E348E1 Players=2 SaveType=Eeprom 4KB Rumble=Yes [E92FC6AE193092F6B597E05946B558EB] GoodName=Super Robot Spirits (J) [b1] CRC=66572080 28E348E1 RefMD5=3EC3F83EAB22702E146C467EB1DB45FA [3F4B73963ABC91CEE59C416063EFD4AE] GoodName=Super Robot Taisen 64 (J) [!] CRC=1649D810 F73AD6D2 Players=1 SaveType=SRAM Mempak=Yes Transferpak=Yes [462A2AF0E3B72DA4A0E9266078EE5717] GoodName=Super Robot Taisen 64 (J) [b1] CRC=1649D810 F73AD6D2 RefMD5=3F4B73963ABC91CEE59C416063EFD4AE [BB5C21BFEA9AA7E9C90FE76C132BEC49] GoodName=Super Robot Taisen 64 (J) [b2] CRC=1649D810 F73AD6D2 RefMD5=3F4B73963ABC91CEE59C416063EFD4AE [9AF2919C27FCF6972986993C564947CD] GoodName=Super Robot Taisen 64 (J) [f1] (PAL) CRC=AF981AB7 AA1A0A7A RefMD5=3F4B73963ABC91CEE59C416063EFD4AE [694DEA68DBF1C3F06FF0476ACF2169E6] GoodName=Super Smash Bros. (A) [!] CRC=DD26FDA1 CB4A6BE3 Status=3 SaveType=SRAM Players=4 Rumble=Yes CountPerOp=1 [7F18A06BB16A507E23F9DD636B7046A6] GoodName=Super Smash Bros. (A) [f1] CRC=9624C4F9 3FB02E03 RefMD5=694DEA68DBF1C3F06FF0476ACF2169E6 [7B815846EC91E6C4A8B8BAA0CE4078F0] GoodName=Super Smash Bros. (Ch) (iQue) [!] Players=4 [3ABC2D34AD3CE623F4ED8F126D30CC80] GoodName=Super Smash Bros. (Ch) (iQue) (Manual) [!] [5E54C6C563B09C107F86FB33E914EF81] GoodName=Super Smash Bros. (E) (M3) [!] CRC=93945F48 5C0F2E30 Status=3 SaveType=SRAM Players=4 Rumble=Yes CountPerOp=1 [4D37726FDFEC039CB36E2AAE65B9727D] GoodName=Super Smash Bros. (E) (M3) [b1] CRC=593BD58B C330786C RefMD5=5E54C6C563B09C107F86FB33E914EF81 [99C1AB76126B7BADFA9023D50DCA1430] GoodName=Super Smash Bros. (E) (M3) [f1] CRC=593BD58B C330786C RefMD5=5E54C6C563B09C107F86FB33E914EF81 [F7C52568A31AADF26E14DC2B6416B2ED] GoodName=Super Smash Bros. (U) [!] CRC=916B8B5B 780B85A4 Status=3 SaveType=SRAM Players=4 Rumble=Yes CountPerOp=1 [508BE860974B75470851A2D25C0FCB36] GoodName=Super Smash Bros. (U) [b1] CRC=916B8B5B 780B85A4 RefMD5=F7C52568A31AADF26E14DC2B6416B2ED [313F1541748ACF01C4355BA471043868] GoodName=Super Smash Bros. (U) [b2] CRC=916B8B5B 780B85A4 RefMD5=F7C52568A31AADF26E14DC2B6416B2ED [326DC227FCCAA4975583E63624DDFDA1] GoodName=Super Smash Bros. (U) [f1] CRC=3409CEB6 CEC8517A RefMD5=F7C52568A31AADF26E14DC2B6416B2ED [C2DBAE0C18C6666336F4CFA896D8ED18] GoodName=Super Smash Bros. (U) [f2] (PAL) CRC=8CF1CECB C8902FF4 RefMD5=F7C52568A31AADF26E14DC2B6416B2ED [5A19D395B6A8B1911DEB334E392F4526] GoodName=Super Smash Bros. (U) [f3] CRC=3409CEB6 CEC8517A RefMD5=F7C52568A31AADF26E14DC2B6416B2ED [98A3122A6D7C9B02381FC5B0CFB8C14B] GoodName=Super Smash Bros. (U) [f4] (GameShark) CRC=EA6D4C3F 13837E54 RefMD5=F7C52568A31AADF26E14DC2B6416B2ED [ED8641A704910BB4A0FAC9AD08F9C1D2] GoodName=Super Smash Bros. (U) [hI] CRC=916B8B5B 780B85A4 RefMD5=F7C52568A31AADF26E14DC2B6416B2ED [6B5D93B3566E96147009D1AC4FB15C97] GoodName=Super Speed Race 64 (J) [!] CRC=9CE02E22 206EF1B0 Players=4 SaveType=None Mempak=Yes Rumble=Yes [27A7A2A19FC67346BB25E3C5BB3A91CE] GoodName=Super Speed Race 64 (J) [o1] CRC=9CE02E22 206EF1B0 RefMD5=6B5D93B3566E96147009D1AC4FB15C97 [DB502D4577EE908160441D38531EBB8D] GoodName=Super WaLuigi 64 (Super Mario 64 Hack) CRC=635A42C5 BDC58EDC RefMD5=20B854B239203BAF6C961B850A4A51A2 [99138CB0D1325F7BB7C2EDAB5D7F6C54] GoodName=Super Wario 64 (Super Mario 64 Hack) CRC=635A42C5 BDC58EDC RefMD5=20B854B239203BAF6C961B850A4A51A2 [7DDF1CC63401CF43836BD14F199B6C70] GoodName=Super Wario 64 V1.0 by Rulesless (Super Mario 64 Hack) [T+Ita] CRC=75A15B07 2E391683 RefMD5=20B854B239203BAF6C961B850A4A51A2 [93582A59F442502CADAA39BD6CC1B2CE] GoodName=Super Wario 64 V1.0 by Rulesless (Super Mario 64 Hack) CRC=635A42C5 BDC58EDC RefMD5=20B854B239203BAF6C961B850A4A51A2 [6D58A01EF7A7A7C779D2A66315992C5F] GoodName=Supercross 2000 (E) (M3) [!] CRC=2CBB127F 09C2BFD8 Players=2 SaveType=None Mempak=Yes Rumble=Yes [60347200A1A7CABC0D849EE69EC51DF7] GoodName=Supercross 2000 (U) [!] CRC=C1452553 5D7B24D9 Players=2 SaveType=None Mempak=Yes Rumble=Yes [53922802F7744CC38BDD75852214057F] GoodName=Supercross 2000 (U) [b1] CRC=C1452553 5D7B24D9 RefMD5=60347200A1A7CABC0D849EE69EC51DF7 [4EAB63BE36DCC7FA6D612BE780BF79C1] GoodName=Supercross 2000 (U) [f1] (PAL) CRC=1917566C 8BE6CD0F RefMD5=60347200A1A7CABC0D849EE69EC51DF7 [5AB39F2D7A144E1BA243DF059560E878] GoodName=Superman (E) (M6) [!] CRC=B44CAB74 07029A29 Players=4 SaveType=None Mempak=Yes Rumble=Yes [3F64B4F72E61225EF3AE93976C9BFC7C] GoodName=Superman (U) (M3) [!] CRC=A2E8F35B C9DC87D9 Players=4 SaveType=None Mempak=Yes Rumble=Yes [1170033980ADC1981505CF958F35F1EB] GoodName=Superman (U) (M3) (Beta) [!] CRC=944FAFC4 B288266A RefMD5=3F64B4F72E61225EF3AE93976C9BFC7C [04A6F25CB0F2084E631B3B7FFF76BEFD] GoodName=Superman (U) (M3) [T+Ita100_Cattivik66] CRC=A2E8F35B C9DC87D9 RefMD5=3F64B4F72E61225EF3AE93976C9BFC7C [3C28C951B1EA46690065DC32862272E4] GoodName=Superman (U) (M3) [b1] CRC=A2E8F35B C9DC87D9 RefMD5=3F64B4F72E61225EF3AE93976C9BFC7C [574704AFFBD28C7A2728DA85CC1DA0F3] GoodName=Superman (U) (M3) [b2] CRC=A2E8F35B C9DC87D9 RefMD5=3F64B4F72E61225EF3AE93976C9BFC7C [12562BFF127E52A6EE9B4FEF92050AF9] GoodName=Superman (U) (M3) [f1] (PAL) CRC=EEF7DE23 57E4FEA9 RefMD5=3F64B4F72E61225EF3AE93976C9BFC7C [943337C945DA689AF869877498C7AA2C] GoodName=Superman (U) (M3) [f2] (PAL) CRC=06F6B180 97F0AD11 RefMD5=3F64B4F72E61225EF3AE93976C9BFC7C [DBA237ED8415383AFCABA035D817272F] GoodName=Superman (U) (M3) [t1] CRC=5AEB33A3 23063A25 RefMD5=3F64B4F72E61225EF3AE93976C9BFC7C [26F4CA20F7B9C88199AC046C57E282B4] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [!] CRC=35E811F3 99792724 Players=2 Mempak=Yes Rumble=Yes [59985249F824F74C335C6C47A6E29C4A] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [b1] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [993A67ECD02212B4BE5B2E14652F835B] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [b2] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [EFE2CEBF5BB21BF766FF72C055DF36BE] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [b3] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [B0FE1343A2ED21D2F083041B1FE1B7A9] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [h1C] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [987A07DAF0F06567BC8E794291D98695] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [h2C] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [E946855EEF7F1BBD47AEECA33A2737BB] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [o1] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [D6B0135BE06DF3545A8931957FE805FA] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [o2] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [6922A2D0DB719AD7972C0DC146FF0D8C] GoodName=Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [o2][b1] CRC=35E811F3 99792724 RefMD5=26F4CA20F7B9C88199AC046C57E282B4 [FC32007BA03FF2510020E979C7BDAD4F] GoodName=Sydney 2000 (E) (Prototype) CRC=ECBD95DD 1FAB637D [2EEA8D20BEF26F88A5E82FDD39F87E75] GoodName=Sydney 2000 (U) (Prototype) CRC=80A78080 5F9F8833 [4BC1D3074FA3A3DCAF1F16888B82A966] GoodName=T-Shirt Demo by Neptune and Steve (POM '98) (PD) [b1] CRC=1AA71519 51360D55 [E4D314C536F7BF78F60197EC238514AE] GoodName=T-Shirt Demo by Neptune and Steve (POM '98) (PD) CRC=1AA71519 51360D55 [ACD0118AC4709DB3943B3D35112C2001] GoodName=TG Rally 2 (E) [!] CRC=F82DD377 8C3FB347 Players=4 SaveType=None Rumble=Yes Mempak=Yes [65E67D43E0A9B146D7881CBC803EC5C3] GoodName=TR64 Demo by FIres and Icepir8 (PD) CRC=2070044B E7D82D16 [07660B03456DD0F776F392EF3E05C481] GoodName=TRON Demo (PD) [a1] CRC=CB3FF554 8773CD0B [4D6E12E0AB62D4045B4934B6D7BB8BDC] GoodName=TRON Demo (PD) CRC=CB3FF554 8773CD0B [503C548F7B38A3721B93FD0ABF979019] GoodName=TRSI Intro by Ayatollah (POM '99) (PD) CRC=2DD07E20 24D40CD6 [CECAB8DF02C02F38C9CF1BDD57B1DA00] GoodName=Tamiya Racing 64 (U) (Prototype) CRC=37955E65 C6F2B7B3 [192B715E8BC5972A4986DF21DC8BF357] GoodName=Taz Express (E) (M6) [!] CRC=AEBCDD54 15FF834A Players=1 Rumble=Yes [53DFA593019BDA070DD3CD5FC5B58436] GoodName=Taz Express (E) (M6) [f1] (NTSC) CRC=17679054 E235F4A7 RefMD5=192B715E8BC5972A4986DF21DC8BF357 [AD47A9521988CEDD8D43097CFD9BE042] GoodName=Taz Express (E) (M6) [f2] (NTSC) CRC=00BC1D78 00709D53 RefMD5=192B715E8BC5972A4986DF21DC8BF357 [7A94F94485BD28F0D6D67257050B26D4] GoodName=Taz Express (U) (Prototype) CRC=6C2C6C49 9BE5CA66 [7F244AFF8D729417E32B6A5B299AFDA5] GoodName=Telefoot Soccer 2000 (F) [!] CRC=D9042FBB FCFF997C Players=4 Mempak=Yes Rumble=Yes [8F96FF06D9B3C3219CEBA5CDB7CF19ED] GoodName=Telefoot Soccer 2000 (F) [b1] CRC=6440D7CE F6597A03 RefMD5=7F244AFF8D729417E32B6A5B299AFDA5 [D1B6D277F9FAE2029A7532D8E1F4D6B2] GoodName=Telefoot Soccer 2000 (F) [f1] (NTSC) CRC=6440D7CE F6597A03 RefMD5=7F244AFF8D729417E32B6A5B299AFDA5 [7C8EFCF4FBA28F9F5B5EA10A71283BF3] GoodName=Tetris 64 (J) [!] CRC=963ADBA6 F7D5C89B Players=4 Biopak=Yes SiDmaDuration=100 [1587B17344A43532B791DCEB237D2BFC] GoodName=Tetris 64 (J) [T+Ita] CRC=963ADBA6 F7D5C89B RefMD5=7C8EFCF4FBA28F9F5B5EA10A71283BF3 [ECC06617156122882C4FA4BBCD241A4F] GoodName=Tetris 64 (J) [b1] CRC=963ADBA6 F7D5C89B RefMD5=7C8EFCF4FBA28F9F5B5EA10A71283BF3 [9036BB44A51A62CB0A74C288EBB850C7] GoodName=Tetris 64 (J) [b2] CRC=963ADBA6 F7D5C89B RefMD5=7C8EFCF4FBA28F9F5B5EA10A71283BF3 [8C9F139BF5FC0B7A0497F28241C6F819] GoodName=Tetris Beta Demo by FusionMan (POM '98) (PD) [b1] CRC=81361532 2AEB643F [674D416C2BD1EF0192BEE34AA260B21A] GoodName=Tetris Beta Demo by FusionMan (POM '98) (PD) CRC=81361532 2AEB643F [765A330D5CE2DBE7120C6C8E18A1487D] GoodName=Tetrisphere (E) [!] CRC=0FE684A9 8BB77AC4 Players=2 SaveType=Eeprom 4KB [A87455244919BDA6E44FA32C7E72BFBA] GoodName=Tetrisphere (E) [b1] CRC=0FE684A9 8BB77AC4 RefMD5=765A330D5CE2DBE7120C6C8E18A1487D [822154EE2B96BF78BCE2E46AF6578131] GoodName=Tetrisphere (E) [b2] CRC=0FE684A9 8BB77AC4 RefMD5=765A330D5CE2DBE7120C6C8E18A1487D [3F88078E2D9DBF6C9372F6373CF9AE09] GoodName=Tetrisphere (U) [!] CRC=3C1FDABE 02A4E0BA Players=2 SaveType=Eeprom 4KB [7211951FDF7DA809D5F3D51CA06CD465] GoodName=Tetrisphere (U) [b1] CRC=3C1FDABE 02A4E0BA RefMD5=3F88078E2D9DBF6C9372F6373CF9AE09 [9F7527EE8A80DAE339DB769EAE707DCC] GoodName=Tetrisphere (U) [t1] CRC=4EF87A50 975A7CC7 RefMD5=3F88078E2D9DBF6C9372F6373CF9AE09 [B11B30536D445AB6C7DC22C85C68A218] GoodName=Textlight Demo by Horizon64 (PD) [b1] CRC=41B1BF58 A1EB9BB7 [33CF09D5EAB2FB1242108A172E1844C2] GoodName=Textlight Demo by Horizon64 (PD) CRC=41B1BF58 A1EB9BB7 [DA934FF1A6CE9EEC70C235F879B23AFE] GoodName=The Corporation 1st Intro by i_savant (PD) [b1] CRC=44705CED 6FDFDE02 [B42C11B1DCBFC0AE42551021CD69AB22] GoodName=The Corporation 1st Intro by i_savant (PD) CRC=44705CED 6FDFDE02 [F6AE85B8CC2B643F37DE95D7F5682262] GoodName=The Corporation 2nd Intro by TS_Garp (PD) [a1] CRC=C3AB938D D48143B2 [EA9D71AF1508636E88D95AC1D525EF93] GoodName=The Corporation 2nd Intro by TS_Garp (PD) [b1] CRC=C3AB938D D48143B2 [756325378480E1252CB089110A689563] GoodName=The Corporation 2nd Intro by TS_Garp (PD) CRC=C3AB938D D48143B2 [D52E871B562AD000BA3728D9B45EC9CB] GoodName=The Corporation XMAS Demo '99 by TS_Garp (PD) [b1] CRC=93DA8551 D231E8AB [AF284AB7FF9363016782E99D00574E70] GoodName=The Corporation XMAS Demo '99 by TS_Garp (PD) CRC=93DA8551 D231E8AB [A09663B596F348D28AF846A51375EB81] GoodName=Tigger's Honey Hunt (E) (M7) [!] CRC=E0C4F72F 769E1506 Players=1 SaveType=Flash RAM CountPerOp=1 [F8636514B5B0EDEBF376C3111D24417A] GoodName=Tigger's Honey Hunt (U) [!] CRC=4EBFDD33 664C9D84 Players=1 SaveType=Flash RAM CountPerOp=1 [7B41F28A920112F17401D633B368BA0C] GoodName=Tigger's Honey Hunt (U) [t1] CRC=E972B385 7668D414 RefMD5=F8636514B5B0EDEBF376C3111D24417A [7B261247150C431DE55AB371E8B46EA8] GoodName=Tokisora Senshi Turok (J) [!] CRC=916AE6B8 8817AB22 Players=1 SaveType=None Mempak=Yes [1B991CF41C70FF2C92FFBEFACABE8D03] GoodName=Tom Clancy's Rainbow Six (E) [!] CRC=4875AF3D 9A66D3A2 Players=2 SaveType=None Mempak=Yes Rumble=Yes [FC2D2F7EF02484EA0478A5EAFD0CBFF0] GoodName=Tom Clancy's Rainbow Six (E) [b1] CRC=4875AF3D 9A66D3A2 RefMD5=1B991CF41C70FF2C92FFBEFACABE8D03 [C0612AA12888C10E9565A57EB2C3605D] GoodName=Tom Clancy's Rainbow Six (E) [h1C] CRC=4875AF3D 9A66D3A2 RefMD5=1B991CF41C70FF2C92FFBEFACABE8D03 [AAD3D42A9E800780087009B16AFB1327] GoodName=Tom Clancy's Rainbow Six (E) [o1] CRC=4875AF3D 9A66D3A2 RefMD5=1B991CF41C70FF2C92FFBEFACABE8D03 [15E4C1B4F3F459D4CAA7F7E2CF0C95DA] GoodName=Tom Clancy's Rainbow Six (F) [!] CRC=486BF335 034DCC81 Players=2 SaveType=None Mempak=Yes Rumble=Yes [FDC76A53B1056D3E50EA6A3E295FE4D1] GoodName=Tom Clancy's Rainbow Six (G) [!] CRC=8D412933 588F64DB Players=2 SaveType=None Mempak=Yes Rumble=Yes [80F3B1ABD9FB9AE73997489DB185A74D] GoodName=Tom Clancy's Rainbow Six (U) [!] CRC=392A0C42 B790E77D Players=2 SaveType=None Mempak=Yes Rumble=Yes [2CF9568A149177AC0B86378FBC8DCB71] GoodName=Tom Clancy's Rainbow Six (U) [f1] (PAL) CRC=8B79DBFD 0BB32AC0 RefMD5=80F3B1ABD9FB9AE73997489DB185A74D [B9EF940408E1DFD63F867527E4212B9D] GoodName=Tom Demo (PD) CRC=5ECE09AE 8230C82D [46BE5D00682FCC1F7FC0FBA507E8E5C1] GoodName=Tom and Jerry in Fists of Furry (E) (M6) [!] CRC=2B4F4EFB 43C511FE Players=2 Rumble=Yes SaveType=Eeprom 4KB [9EAA60F295DBA9A9687E3238DABA14EE] GoodName=Tom and Jerry in Fists of Furry (E) (M6) [f1] (NTSC) CRC=EC6F66AC 618EF742 RefMD5=46BE5D00682FCC1F7FC0FBA507E8E5C1 [A63A9AF85BE8BB47C1741B8A37115354] GoodName=Tom and Jerry in Fists of Furry (U) [!] CRC=63E7391C E6CCEA33 Players=2 Rumble=Yes SaveType=Eeprom 4KB [17D6D6DA5D03C9D295D72A212A719EB2] GoodName=Tom and Jerry in Fists of Furry (U) [t1] CRC=9BF2A817 EE20252A RefMD5=A63A9AF85BE8BB47C1741B8A37115354 [99F95AD4A3B0C78B6F58A0FC3AD22DB6] GoodName=Tommy Thunder (U) (Prototype) CRC=21260D94 06AE1DFE [3D3573A855835A98DE29D598C35590E0] GoodName=Tonic Trouble (E) (M5) [!] CRC=093F916E 4408B698 Players=1 SaveType=None Mempak=Yes [7D3E935156844DE0002DB875E1076A5C] GoodName=Tonic Trouble (U) (V1.1) [!] CRC=EF9E9714 C03B2C7D Players=1 SaveType=None Mempak=Yes [A6C5625FF127D9E741F595EBF3B3ABB9] GoodName=Tonic Trouble (U) (V1.1) [b1] CRC=EF9E9714 C03B2C7D RefMD5=7D3E935156844DE0002DB875E1076A5C [012C9DAF61705F109392A85B2621CD42] GoodName=Tonic Trouble (U) (V1.1) [f1] (PAL) CRC=1671E7BC B7D756B9 RefMD5=7D3E935156844DE0002DB875E1076A5C [1987E0F12DDD619F440CD9637DF7CC28] GoodName=Tonic Trouble (U) (V1.1) [t1] CRC=1671F4A0 5C0E7928 RefMD5=7D3E935156844DE0002DB875E1076A5C [C9E9C4A18B1540C6B4111331D7C663B8] GoodName=Tony Hawk's Pro Skater (E) [!] CRC=9F8926A5 0587B409 Players=2 SaveType=None Mempak=Yes Rumble=Yes [5ED7E392198A5FA56EE37EA9E93A8D50] GoodName=Tony Hawk's Pro Skater (U) (V1.0) [!] CRC=204EC022 B119D185 Players=2 SaveType=None Mempak=Yes Rumble=Yes [30EC0EEA5C487E5609D9F9F356D21F27] GoodName=Tony Hawk's Pro Skater (U) (V1.0) [t1] CRC=85C52CA4 017EE9A6 RefMD5=5ED7E392198A5FA56EE37EA9E93A8D50 [AFF424A1883DC7BB92C7B2EBE9342F85] GoodName=Tony Hawk's Pro Skater (U) (V1.1) [!] CRC=E0144180 650B78C9 Players=2 SaveType=None Mempak=Yes Rumble=Yes [6BE030475C4DB52F273EF8A02B4DAFA8] GoodName=Tony Hawk's Pro Skater 2 (E) [!] CRC=84EAB557 C88A190F Players=2 SaveType=None Rumble=Yes Mempak=Yes [29974692808C112B306FBD259273DC96] GoodName=Tony Hawk's Pro Skater 2 (U) [!] CRC=99150E18 1266E6A5 Players=2 SaveType=None Mempak=Yes Rumble=Yes [9D4891BF26881C4541171B0235015FD4] GoodName=Tony Hawk's Pro Skater 3 (U) CRC=1A7F70B5 00B7B9FD Players=2 SaveType=None Rumble=Yes Mempak=Yes [B6FD2A048D1F4F324CEBC97BA09872BB] GoodName=Toon Panic (J) (Prototype) CRC=9A746EBF 2802EA99 [B60D26C2C2242BFF61F76469FC272D2A] GoodName=Top Gear Hyper Bike (Beta) CRC=75FBDE20 A3189B31 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [0072538EF925645DB310F8E23A480B89] GoodName=Top Gear Hyper Bike (E) [!] CRC=5F3F49C6 0DC714B0 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [561B438F6E8240BEF1DAEB36AAE72675] GoodName=Top Gear Hyper Bike (E) [b1] CRC=5F3F49C6 0DC714B0 RefMD5=0072538EF925645DB310F8E23A480B89 [4347174BB415CA970F2D50DF2973F656] GoodName=Top Gear Hyper Bike (J) [!] CRC=845B0269 57DE9502 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [7258F4AB367B025C95A4F476C461E717] GoodName=Top Gear Hyper Bike (U) [!] CRC=8ECC02F0 7F8BDE81 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [6C65A252F227AEF18DF2DD3CE04CC821] GoodName=Top Gear Overdrive (E) [!] CRC=D09BA538 1C1A5489 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [11D6FFF288DE1BD61CCBD7CCA0C4A97B] GoodName=Top Gear Overdrive (E) [h1C] CRC=D09BA538 1C1A5489 RefMD5=6C65A252F227AEF18DF2DD3CE04CC821 [B5691794A851D8B603F0C741D44AA244] GoodName=Top Gear Overdrive (J) [!] CRC=0578F24F 9175BF17 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [8C0F46FEF9A6034FCF0B7D6952FFEC53] GoodName=Top Gear Overdrive (J) [b1] CRC=0578F24F 9175BF17 RefMD5=B5691794A851D8B603F0C741D44AA244 [7818696426C0A429FBFCCC4EFE8D5570] GoodName=Top Gear Overdrive (U) [!] CRC=D741CD80 ACA9B912 Players=4 SaveType=Eeprom 4KB Rumble=Yes CountPerOp=1 [773FD446DA7F4E392907505053BF2A42] GoodName=Top Gear Overdrive (U) [o1] CRC=D741CD80 ACA9B912 RefMD5=7818696426C0A429FBFCCC4EFE8D5570 [211256ABBC0844D9152D6A7FFA9E48BD] GoodName=Top Gear Overdrive (U) [t1] CRC=0F5FD10B AAEDEBEB RefMD5=7818696426C0A429FBFCCC4EFE8D5570 [50195216C8A37F9BD5B2105A40EE8D8F] GoodName=Top Gear Rally (As) [!] CRC=1A4D3AD8 59AF7FA9 Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [1698508F521280D0A80E078EC981D4AC] GoodName=Top Gear Rally (E) [!] CRC=7F43E701 536328D1 Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [48D6C194AE106018DDFC3486A8B347F7] GoodName=Top Gear Rally (E) [b1] CRC=7F43E701 536328D1 RefMD5=1698508F521280D0A80E078EC981D4AC [108F6609CB131830EC4C67F4A8A71D30] GoodName=Top Gear Rally (E) [h1C] CRC=7F43E701 536328D1 RefMD5=1698508F521280D0A80E078EC981D4AC [6E0AF13DCEFEE6A11C4D7262206D6D2D] GoodName=Top Gear Rally (J) [!] CRC=0E596247 753D4B8B Players=2 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [6F7030284B6BC84A49E07DA864526B52] GoodName=Top Gear Rally (U) [!] CRC=62269B3D FE11B1E8 Players=2 SaveType=None Mempak=Yes Rumble=Yes [FA88969ECFA72358EF1C045035442F5C] GoodName=Top Gear Rally (U) [b1] CRC=62269B3D FE11B1E8 RefMD5=6F7030284B6BC84A49E07DA864526B52 [E9E3680C47CE093A3F0765539F31C6AE] GoodName=Top Gear Rally (U) [b2] CRC=62269B3D FE11B1E8 RefMD5=6F7030284B6BC84A49E07DA864526B52 [194CE13B2B6B1F584587A68CC2F398DC] GoodName=Top Gear Rally (U) [b3] CRC=62269B3D FE11B1E8 RefMD5=6F7030284B6BC84A49E07DA864526B52 [4FCD85C487E1FBEDFD85E27F991D1FA6] GoodName=Top Gear Rally (U) [o1] CRC=62269B3D FE11B1E8 RefMD5=6F7030284B6BC84A49E07DA864526B52 [C33CD926E1E71F39F7238AF7B9E0DC5C] GoodName=Top Gear Rally 2 (Beta) CRC=EFDF9140 A4168D6B Players=4 SaveType=None Mempak=Yes Rumble=Yes [44C4566572DC0662D4299AB5B19043AE] GoodName=Top Gear Rally 2 (E) [!] CRC=BEBAB677 51B0B5E4 Players=4 SaveType=None Mempak=Yes Rumble=Yes [B10D781EC625CA45713FD34E5096C24A] GoodName=Top Gear Rally 2 (J) [!] CRC=CFEF2CD6 C9E973E6 Players=4 SaveType=None Mempak=Yes Rumble=Yes [1FA409FCAC007DDECCC4CF439A0D8DAE] GoodName=Top Gear Rally 2 (U) [!] CRC=BE5973E0 89B0EDB8 Players=4 SaveType=None Mempak=Yes Rumble=Yes [4648C4F656BD4A74647DF6A7A2985F37] GoodName=Top Gear Rally 2 (U) [f1] (PAL) CRC=1C952873 FDA4238B RefMD5=1FA409FCAC007DDECCC4CF439A0D8DAE [CAA7CAA9ADFB4B8E4B2DBED88F963D07] GoodName=TopGun Demo by Horizon64 (PD) CRC=E8BF8416 F2D9DA43 [3CBB8012F1256A37D5284A85B859CC8B] GoodName=Tower&Shaft (Aleck64) CRC=90AF8D2C E1AC1B37 SaveType=Eeprom 4KB [5F2C9E5E39AB09311D96E6C751184B6B] GoodName=Toy Story 2 - Buzz Lightyear to the Rescue! (E) [!] CRC=CCEB3858 26952D97 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [FA0F12C15B3655F9F56888C3249B1CED] GoodName=Toy Story 2 - Buzz L'eclair A La Rescousse! (F) [!] CRC=CB93DB97 7F5C63D5 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [3F40F37B0464DD065067523FB21016DD] GoodName=Toy Story 2 - Captain Buzz Lightyear auf Rettungsmission! (G) (V1.0) [!] CRC=782A9075 E552631D Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [A4A2B825797E2059B5DF60D733461F34] GoodName=Toy Story 2 - Captain Buzz Lightyear auf Rettungsmission! (G) (V1.1) [!] CRC=BC4F2AB8 AA99E32E Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [B44E9C2D9D2F2DE3AF4793B824CCF936] GoodName=Toy Story 2 - Buzz Lightyear to the Rescue! (U) [!] CRC=A150743E CF2522CD Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [9E4F62BD672E3601F1BBF9CDAB791F9F] GoodName=Toy Story 2 - Buzz Lightyear to the Rescue! (U) (V1.0) [f1] (PAL) CRC=161545FE A3C44C28 RefMD5=B44E9C2D9D2F2DE3AF4793B824CCF936 [F551ADA6C6FC1877FCA0515DF4F515DF] GoodName=Toy Story 2 - Buzz Lightyear to the Rescue! (U) (V1.0) [t1] CRC=1416FEBB 93472028 RefMD5=B44E9C2D9D2F2DE3AF4793B824CCF936 [CD61A7FDBD7297733B246204E8360D83] GoodName=Toy Story 2 - Buzz Lightyear to the Rescue! (U) (V1.1) [!] CRC=C151AD61 280FFF22 Players=1 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [3D22D5BD7997293612ECDD3046BEBA13] GoodName=Transformers - Beast Wars Metals 64 (J) [!] CRC=91691C3D F4AC5B4D Players=2 SaveType=Eeprom 4KB Rumble=Yes Transferpak=Yes [6D38909FAA2840FC409AFA221489DE49] GoodName=Transformers - Beast Wars Transmetal (U) [!] CRC=4D79D316 E8501B33 Players=2 SaveType=None Rumble=Yes [6F2C37A20E6ECCB657FBFC4BA36A34BB] GoodName=Triple Play 2000 (U) [!] CRC=FE4B6B43 081D29A7 Players=2 SaveType=None Rumble=Yes Mempak=Yes CountPerOp=1 [25E03763FC8A388A33871C58DFEB7C0E] GoodName=Tristar and Lightforce Quake Intro by Ayatollah & Mike (PD) CRC=F4D89C08 3F34930D [5BA3AA2953C47C8B2E615B21E60F2F17] GoodName=Tsumi to Batsu - Hoshi no Keishousha (Ch) (iQue) [!] Players=2 [9ABB0F6F79E01FC9A942D6027719C3E4] GoodName=Tsumi to Batsu - Hoshi no Keishousha (Ch) (iQue) (Manual) [!] [A0657BC99E169153FD46AECCFDE748F3] GoodName=Tsumi to Batsu - Hoshi no Keishousha (J) [!] CRC=B6BC0FB0 E3812198 Players=2 Rumble=Yes [6E51B140A9B0C30D6F55CA7942A969FC] GoodName=Tsumi to Batsu - Hoshi no Keishousha (J) [T+Eng1.0_Zoinkity] CRC=B73AB6F6 296267DD RefMD5=A0657BC99E169153FD46AECCFDE748F3 [79BD05A97E50AC63A638E4E90AB9588B] GoodName=Tsumi to Batsu - Hoshi no Keishousha (J) [T+Spa1.0b_TheFireRed&IlDucci] CRC=B1C7794B D93DC5F3 RefMD5=A0657BC99E169153FD46AECCFDE748F3 [103E16BF7FCFB4D713D2EBE19DCB5311] GoodName=Tsumi to Batsu - Hoshi no Keishousha (J) [T+Spa1.0b_TheFireRed&IlDucci] (Fandub) CRC=B1C7794B D93DC5F3 RefMD5=A0657BC99E169153FD46AECCFDE748F3 [13FAA58604597E4EDC608070F8E0AE24] GoodName=Turok - Dinosaur Hunter (E) (V1.0) [!] CRC=2F7009DD FC3BAC53 Players=1 SaveType=None Mempak=Yes [6D5147A9CD7DDD0F1FA8B8BDA439A734] GoodName=Turok - Dinosaur Hunter (E) (V1.0) [b1] CRC=665F09DD FC3BAC53 RefMD5=13FAA58604597E4EDC608070F8E0AE24 [E887BEE5B1DE4E4D92ADA183A245150E] GoodName=Turok - Dinosaur Hunter (E) (V1.0) [h1C] CRC=2F7009DD FC3BAC53 RefMD5=13FAA58604597E4EDC608070F8E0AE24 [992BA72F4A1E9C51934FF345CDD0D90C] GoodName=Turok - Dinosaur Hunter (E) (V1.1) [!] CRC=2F700DCD 176CC5C9 Players=1 SaveType=None Mempak=Yes [548FC0E6035B65BC2108255039859934] GoodName=Turok - Dinosaur Hunter (E) (V1.2) [!] CRC=2F700DCD 176CC5C9 Players=1 SaveType=None Mempak=Yes [0C0BFD1038EDA4F5C958DC362CDFF2D6] GoodName=Turok - Dinosaur Hunter (G) (V1.0) [!] CRC=665FD963 B5CC6612 Players=1 SaveType=None Mempak=Yes [388440013641887D85B791CF01729FA8] GoodName=Turok - Dinosaur Hunter (G) (V1.1) [!] CRC=665FC793 6934A73B Players=1 SaveType=None Mempak=Yes [F0F687B449A9F4B0BFF08104C35EA08C] GoodName=Turok - Dinosaur Hunter (G) (V1.2) [!] CRC=665FC793 6934A73B Players=1 SaveType=None Mempak=Yes [85F616E54160FFE14E4E817065EA61CE] GoodName=Turok - Dinosaur Hunter (U) (V1.0) (Analog Movement Controls_1.01 - No Invert) CRC=2F70F10D 5C4187FF RefMD5=AE5107EFDD3C210E1EDD4ACD9B3CAC31 [AE5107EFDD3C210E1EDD4ACD9B3CAC31] GoodName=Turok - Dinosaur Hunter (U) (V1.0) [!] CRC=2F70F10D 5C4187FF Players=1 SaveType=None Mempak=Yes [E5B207E7C8DBD8BAF9B42C96EF3C42E8] GoodName=Turok - Dinosaur Hunter (U) (V1.0) [b1] CRC=2F70F10D 5C4187FF RefMD5=AE5107EFDD3C210E1EDD4ACD9B3CAC31 [7BBD5A1594526DE1CE6A16F4FAF82E7D] GoodName=Turok - Dinosaur Hunter (U) (V1.0) [h1C] CRC=2F70F10D 5C4187FF RefMD5=AE5107EFDD3C210E1EDD4ACD9B3CAC31 [9D258DF027ED369886A0249BFCA936BD] GoodName=Turok - Dinosaur Hunter (U) (V1.0) [o1] CRC=2F70F10D 5C4187FF RefMD5=AE5107EFDD3C210E1EDD4ACD9B3CAC31 [E7916845B46C3482CF4843968370557E] GoodName=Turok - Dinosaur Hunter (U) (V1.0) [t1] CRC=9542E183 B1D245E6 RefMD5=AE5107EFDD3C210E1EDD4ACD9B3CAC31 [3DC541C0B97DB9C95A6AA8C2DED27F4A] GoodName=Turok - Dinosaur Hunter (U) (V1.0) [t2] CRC=9542E183 B1D245E6 RefMD5=AE5107EFDD3C210E1EDD4ACD9B3CAC31 [37260287D59FE4EC6049C1D22B5614E6] GoodName=Turok - Dinosaur Hunter (U) (V1.1) [!] CRC=2F700DCD 176CC5C9 Players=1 SaveType=None Mempak=Yes [039875B92C0E4FEF9797EC1744877B17] GoodName=Turok - Dinosaur Hunter (U) (V1.2) [!] CRC=2F700DCD 176CC5C9 Players=1 SaveType=None Mempak=Yes [72A6AA28608EE93A1CB6FEB0A5F4C28C] GoodName=Turok - Legenden des Verlorenen Landes (G) [!] CRC=66E4FA0F DE88C7D0 Players=4 SaveType=None Mempak=Yes Rumble=Yes [241CF94BED487FFF62FFB7B846DA46AB] GoodName=Turok - Rage Wars (E) (M3) (Eng-Fre-Ita) [!] CRC=B6BE20A5 FACAF66D Players=4 SaveType=None Mempak=Yes Rumble=Yes [DBA166A42710F40DC78DC52EB37B0BE6] GoodName=Turok - Rage Wars (E) [!] CRC=1EA26214 E790900F Players=4 SaveType=None Mempak=Yes Rumble=Yes [CF5B28578FD62FA1FF8690079F5D68F5] GoodName=Turok - Rage Wars (U) (V1.0) [!] CRC=ADB9498B DAF28F55 Players=4 SaveType=None Mempak=Yes Rumble=Yes [07E123E104BA7B335B53932EDB2CFB2F] GoodName=Turok - Rage Wars (U) (V1.0) [f1] (PAL) CRC=700694EA 636C43D5 RefMD5=CF5B28578FD62FA1FF8690079F5D68F5 [CA825227E9E203E8429600189825AD74] GoodName=Turok - Rage Wars (U) (V1.0) [f2] (PAL) CRC=72618906 0EDC784B RefMD5=CF5B28578FD62FA1FF8690079F5D68F5 [9B2FFE72080B03A5F92EB87EA849CAC4] GoodName=Turok - Rage Wars (U) (V1.1) [!] CRC=2388984C DA7B3CC5 Players=4 SaveType=None Mempak=Yes Rumble=Yes [CE72237707F481CFE97FDE330C2AFCD6] GoodName=Turok 2 - Seeds of Evil (E) (Kiosk Demo) [!] CRC=E8C95AFC 35D121DA Players=4 SaveType=None Mempak=Yes Rumble=Yes [144B10A484A22367FD2679529DBD2FED] GoodName=Turok 2 - Seeds of Evil (E) (M4) [!] CRC=2E0E7749 B8B49D59 Players=4 SaveType=None Mempak=Yes Rumble=Yes [E5A39521FA954EB97B96AC2154A5FD7A] GoodName=Turok 2 - Seeds of Evil (E) [!] CRC=E0B92B94 80E87CBD Players=4 SaveType=None Mempak=Yes Rumble=Yes [AC1C00167B95929F8EE40DFACB49BB57] GoodName=Turok 2 - Seeds of Evil (E) [b1] CRC=E0B92B94 80E87CBD RefMD5=E5A39521FA954EB97B96AC2154A5FD7A [B932116C967795076B5C112841AB4427] GoodName=Turok 2 - Seeds of Evil (G) [!] CRC=FE05840B 9393320C Players=4 SaveType=None Mempak=Yes Rumble=Yes [3BD42F6AEC477C056E1AFEBB3515495C] GoodName=Turok 2 - Seeds of Evil (U) (Kiosk Demo) [!] CRC=E8C95AFC 35D121DA Players=4 SaveType=None Mempak=Yes Rumble=Yes [4250FF0265AD72FC798E6ABA61CFCD0E] GoodName=Turok 2 - Seeds of Evil (U) (Kiosk Demo) (Gore On Hack) CRC=AAD95AFC BB3A44AC RefMD5=3BD42F6AEC477C056E1AFEBB3515495C [4EA0F7563F2EAEB3D46E860C12FABFCB] GoodName=Turok 2 - Seeds of Evil (U) (Kiosk Demo) [h1C] CRC=E8C95AFC 35D121DA RefMD5=3BD42F6AEC477C056E1AFEBB3515495C [166221365DB70D446C4206083D422DD1] GoodName=Turok 2 - Seeds of Evil (U) (V1.1) [!] CRC=E0B92B94 B9A7E025 Players=4 SaveType=None Mempak=Yes Rumble=Yes [FAD4DA8E17CE12F68CDF29180CDD4A90] GoodName=Turok 2 - Seeds of Evil (U) (V1.0) [!] CRC=49088A11 6494957E Players=4 SaveType=None Mempak=Yes Rumble=Yes [8DC201A0A9CFD1D2C85EE2B42D8AC49A] GoodName=Turok 2 - Seeds of Evil (U) (V1.0) [t1] CRC=544E3629 875BDD4A RefMD5=FAD4DA8E17CE12F68CDF29180CDD4A90 [72BA2C693EFA5FF3B80374CDBD0C957B] GoodName=Turok 2 - Seeds of Evil (U) (V1.0) [t2] CRC=544E3629 875BDD4A RefMD5=FAD4DA8E17CE12F68CDF29180CDD4A90 [401C0DBDF49A64294DAA2BC8607245DD] GoodName=Turok 2 - Seeds of Evil (U) (V1.0) [t3] CRC=544E3629 875BDD4A RefMD5=FAD4DA8E17CE12F68CDF29180CDD4A90 [279EC83BD60A3CCE69A1DB22B0A5C318] GoodName=Turok 3 - Shadow of Oblivion (E) [!] CRC=6A162FF2 2093704C Players=4 SaveType=None Mempak=Yes Rumble=Yes [03D17AA3DC7663502017D3CC5A19AA8B] GoodName=Turok 3 - Shadow of Oblivion (E) (Beta) (2000-05-31) CRC=D124DBB7 7C9FF5E5 RefMD5=279EC83BD60A3CCE69A1DB22B0A5C318 [69CE88C46A7C829C6F54004DE93EFCEF] GoodName=Turok 3 - Shadow of Oblivion (E) (Beta) (2000-06-06) CRC=37FA8F16 5F824D37 RefMD5=279EC83BD60A3CCE69A1DB22B0A5C318 [C38ACBAE773CC3845EA354421E171998] GoodName=Turok 3 - Shadow of Oblivion (E) (Beta) (2000-07-10) CRC=D25C1211 13EEBF67 RefMD5=279EC83BD60A3CCE69A1DB22B0A5C318 [0A3A4C761960F7D648AFA60B1E565C7C] GoodName=Turok 3 - Shadow of Oblivion (U) (Beta) [h1C] CRC=D25C1211 13EEBF67 RefMD5=279EC83BD60A3CCE69A1DB22B0A5C318 [1211C556D77B169D81A666A9661E1777] GoodName=Turok 3 - Shadow of Oblivion (U) [!] CRC=89A579F1 667E97EF Players=4 SaveType=None Mempak=Yes Rumble=Yes [8A5F9B3308107C253EC5DCA198F55C83] GoodName=Turok 3 - Shadow of Oblivion (U) [t1] CRC=6192E59D 538A78CF RefMD5=1211C556D77B169D81A666A9661E1777 [A74738D03ACA4E51690408D203E86D49] GoodName=Twintris by Twinsen (POM '98) (PD) CRC=37B8F920 A58BB3EF [420C9FDBAE15767C5E584070209FF253] GoodName=Twisted Edge Extreme Snowboarding (E) [!] CRC=E688A5B8 B14B3F18 Players=2 SaveType=None Mempak=Yes Rumble=Yes [4F0E2AF205BEEB49270154810660FF37] GoodName=Twisted Edge Extreme Snowboarding (E) [b1] CRC=BBC99D32 117DAA80 RefMD5=420C9FDBAE15767C5E584070209FF253 [FDE5F910974A8B9C561A27B07E68F244] GoodName=Twisted Edge Extreme Snowboarding (E) [h1C] CRC=E688A5B8 B14B3F18 RefMD5=420C9FDBAE15767C5E584070209FF253 [9DF6C2C97FA34A978EF3CB77631536FE] GoodName=Twisted Edge Extreme Snowboarding (U) [!] CRC=BBC99D32 117DAA80 Players=2 SaveType=None Rumble=Yes Mempak=Yes [0B0DF8EC747BF99F3A55A3300CE8BC0D] GoodName=U64 (Chrome) Demo by Horizon64 (PD) [a1] CRC=7739A454 A2F52A66 [9B4EFC228C894E1BA80D7D11FDA4E037] GoodName=U64 (Chrome) Demo by Horizon64 (PD) [a1][b1] CRC=7739A454 A2F52A66 [DFB437BFB32864A17E903FEDE9EC3A27] GoodName=U64 (Chrome) Demo by Horizon64 (PD) [b1] CRC=95013CCC 73F7C072 [33EFC323AA05F522CEF2324CC1D3F5DD] GoodName=U64 (Chrome) Demo by Horizon64 (PD) CRC=7739A454 A2F52A66 [A56BEF4C7E6899A96F1F33424B434790] GoodName=U64 (Chrome) Demo by Horizon64 (older) (PD) [b1] CRC=95013CCC 73F7C072 [2628818AF2FEE3C649AAF8627981A63D] GoodName=U64 (Chrome) Demo by Horizon64 (older) (PD) CRC=95013CCC 73F7C072 [FFEB5C1A85BABBBE60F2FEBA2B35C893] GoodName=Uchhannanchan no Hono no Challenger - Denryu IraIra Bou (J) [!] CRC=28D5562D E4D5AE50 Players=2 Rumble=Yes CountPerOp=1 [07B7A5CFDE9BC43F02A622387C5B5C58] GoodName=Uchhannanchan no Hono no Challenger - Denryu IraIra Bou (J) [h1C] CRC=28D5562D E4D5AE50 RefMD5=FFEB5C1A85BABBBE60F2FEBA2B35C893 [6AFA476787B762DC08F5B9EEB237C4EE] GoodName=Uchhannanchan no Hono no Challenger - Denryu IraIra Bou (J) [h2C] CRC=28D5562D E4D5AE50 RefMD5=FFEB5C1A85BABBBE60F2FEBA2B35C893 [D42E4496BEA3C61E353643C8438CD9C7] GoodName=Uchhannanchan no Hono no Challenger - Denryu IraIra Bou (J) [o1] CRC=28D5562D E4D5AE50 RefMD5=FFEB5C1A85BABBBE60F2FEBA2B35C893 [CEEDAB23299FA003F32975A4C1E407E3] GoodName=Ultra Demo Bootcode by Locke^ (PD) [h1C] CRC=ED42A2D4 7A71CD91 [B882EDA9CBF832BEEA2641E442A79EDD] GoodName=Ultra Demo Bootcode by Locke^ (PD) CRC=ED42A2D4 7A71CD91 [7E6456E104503B51A97735C8FF349E4C] GoodName=Ultra Demo by Locke^ (PD) [a1] CRC=ED42A2D4 7A71CD91 [2E2C990D8BBAEE7E0681FDC89C29C0F3] GoodName=Ultra Demo by Locke^ (PD) CRC=ED42A2D4 7A71CD91 [1DE07FCA04FB0810D95B8AE4DA173A2E] GoodName=UltraMSX2 V1.0 by Jos Kwanten (PD) [f1] (V64) CRC=31C41A8B 544057AE [6A11F7EB319CF603AB30A281E0639126] GoodName=UltraMSX2 V1.0 by Jos Kwanten (PD) CRC=4E7DE4EF 0DEC3712 [FCA7BE078D6DC68AC6F2E1B7B4369720] GoodName=UltraMSX2 V1.0 w-F1 Spirit by Jos Kwanten (PD) CRC=504ABA0A 269AA7F4 [D2BD19A0873A6900AEF07ECCE103710C] GoodName=UltraMSX2 V1.0 w-Salamander by Jos Kwanten (PD) CRC=FF922478 570B5673 [8E3D79FD6C089F88ED7A2CC1CDBDD535] GoodName=UltraSMS V1.0 by Jos Kwanten (PD) [f1] (V64) CRC=CD29E6E5 4533F032 [8095B5926A9FA7A0C9DA7B46731513A1] GoodName=UltraSMS V1.0 by Jos Kwanten (PD) CRC=F291B959 A24CBCAF [27CB290FAB6C32FAA75EB0E53BE73418] GoodName=Ultrafox 64 by Megahawks (PD) CRC=66D8DE56 C2AA25B2 Players=0 SaveType=None Rumble=No Status=3 [C0B245E95A0CE736E1401A2183C3BBD1] GoodName=Unix SRAM-Upload Utility 1.0 by Madman (PD) CRC=5F44492A 18552A0A [DCAC12EB5832D4A489188330EB9EC387] GoodName=V-Rally Edition 99 (E) (M3) [!] CRC=636E6B19 E57DDC5F Players=2 SaveType=Eeprom 4KB Rumble=Yes [7DCEAFF24BB1BB3D9B8FE9B78CCC7048] GoodName=V-Rally Edition 99 (E) (M3) [f1] (NTSC) CRC=75CF4CCD F47E10F6 RefMD5=DCAC12EB5832D4A489188330EB9EC387 [8541D7A8737BE09C52D4EC1274DE2A91] GoodName=V-Rally Edition 99 (J) [!] CRC=4D0224A5 1BEB5794 Players=2 SaveType=Eeprom 4KB Rumble=Yes [0C3448A9D85300ACB9C5556F27A84B23] GoodName=V-Rally Edition 99 (U) [!] CRC=3C059038 C8BF2182 Players=2 SaveType=Eeprom 4KB Rumble=Yes [9768A9874D8329569F8FB27EC0AB723B] GoodName=V-Rally Edition 99 (U) [f1] (PAL) CRC=6F48FF84 754B4549 RefMD5=0C3448A9D85300ACB9C5556F27A84B23 [7E0AC3917227EDF51132FBEBB867FF9B] GoodName=V64Jr 512M Backup Program by HKPhooey (PD) CRC=760EF304 AD6D6A7C [FD523AF9832B5A17F0EB96ED2A77E77B] GoodName=V64Jr Backup Tool V0.2b_Beta by RedboX (PD) CRC=F11B663A 698824C0 [5BAA85768F2410C61FBE2DFB62C3D836] GoodName=V64Jr Backup Tool by WT_Riker (PD) CRC=4BD245D4 4202B322 [19BA19834F948EEE3828640246405B5D] GoodName=V64Jr Flash Save Util by CrowTRobo (PD) CRC=6FC4EEBC 125BF459 [1A232A07B0D2A102CA528E75CB7BBA22] GoodName=VNES64 + Galaga (PD) CRC=DCBE12CD FCCB5E58 Status=0 SaveType=None Mempak=Yes [495E0B30318FC67978D68BD034165981] GoodName=VNES64 + Mario (PD) CRC=66807E77 EBEA2D76 Status=0 SaveType=None Mempak=Yes [2953091D648ED1B60A67200B17A9410D] GoodName=VNES64 + Test Cart (PD) CRC=4537BDFF D1ECB425 [BE804A0317F138775454405155C1D9A5] GoodName=VNES64 V0.1 by Jean-Luc Picard (POM '98) (PD) CRC=4537BDFF D1ECB425 Status=0 SaveType=None Mempak=Yes [062C3AD13478D5C75B4E8DB2FFD500DC] GoodName=VNES64 V0.12 by Jean-Luc Picard (PD) CRC=0E4B8C92 7F47A9B8 Status=0 SaveType=None Mempak=Yes [B61F53695517D380EB7240331A2342C2] GoodName=Vector Demo by Destop (POM '99) (PD) CRC=1CEACBA0 42BC06D6 [A95442CE25EEB3BD31CEF8525B9936FD] GoodName=View N64 Test Program (PD) [b1] CRC=A38F7AA6 03A48A45 [CF17AF84662E1457E61AD54575D50D20] GoodName=View N64 Test Program (PD) CRC=34B493C9 07654185 [DF011E19F41B1B19C21F1E77E13780B7] GoodName=Vigilante 8 (E) [!] CRC=151F79F4 8EEDC8E5 Players=4 SaveType=None Mempak=Yes Rumble=Yes [637B9A40BED777FC96EB1BD07EA74783] GoodName=Vigilante 8 (E) [h1C] CRC=151F79F4 8EEDC8E5 RefMD5=DF011E19F41B1B19C21F1E77E13780B7 [FF9F85C50982DBDBA9853A8915321D31] GoodName=Vigilante 8 (F) [!] CRC=E2BC82A2 591CD694 Players=4 SaveType=None Mempak=Yes Rumble=Yes [B69B84083D1B4EC99A465B3067F74417] GoodName=Vigilante 8 (F) [b1] CRC=E2BC82A2 591CD694 RefMD5=FF9F85C50982DBDBA9853A8915321D31 [37B430EE16167831C6C6292994F93277] GoodName=Vigilante 8 (G) [!] CRC=6EDA5178 D396FEC1 Players=4 SaveType=None Mempak=Yes Rumble=Yes [D616ADF6441ACBBD0E6BEF023A8F6031] GoodName=Vigilante 8 (U) [!] CRC=EA71056A E4214847 Players=4 SaveType=None Mempak=Yes Rumble=Yes [9F42209E413A1A92C788BF7BC26BFB7B] GoodName=Vigilante 8 (U) [b1] CRC=5573C64D 905B49FA RefMD5=D616ADF6441ACBBD0E6BEF023A8F6031 [5DDCE4475A98F7BA9CCE2F255723EB31] GoodName=Vigilante 8 (U) [b2] CRC=EA71056A E4214847 RefMD5=D616ADF6441ACBBD0E6BEF023A8F6031 [B6154ECD50053CA96953176404B07824] GoodName=Vigilante 8 (U) [f1] (PAL) CRC=4FAFC64B B7DBE63A RefMD5=D616ADF6441ACBBD0E6BEF023A8F6031 [F747B178FFAB97EE8545F7E6EFAEF7CA] GoodName=Vigilante 8 (U) [f2] (PAL) CRC=44C54A0B 22C0B63A RefMD5=D616ADF6441ACBBD0E6BEF023A8F6031 [829E4F5DDECED5DB6C64E346EDA47E5C] GoodName=Vigilante 8 (U) [t1] CRC=5573C64D 905B49FA RefMD5=D616ADF6441ACBBD0E6BEF023A8F6031 [47661EF1964524B6319B759913F08B62] GoodName=Vigilante 8 - 2nd Offence (E) [!] CRC=DD10BC7E F900B351 Players=4 SaveType=None Mempak=Yes Rumble=Yes [60CDF7445FAD2ABA05C958F46691501B] GoodName=Vigilante 8 - 2nd Offense (U) [!] CRC=F5C5866D 052713D9 Players=4 SaveType=None Mempak=Yes Rumble=Yes [5E30D0208FC4CB810A464E5DEFFB29A3] GoodName=Vigilante 8 - 2nd Offense (U) [f1] (PAL) CRC=098D46A2 D1A4CF3B RefMD5=60CDF7445FAD2ABA05C958F46691501B [C3005D76AF42E929E5C67421A19F8235] GoodName=Violence Killer - Turok New Generation (J) [!] CRC=60006C98 2605A381 Players=4 SaveType=None Mempak=Yes Rumble=Yes [50272F8EA99E4E06ADD8CCAB5F5A4F41] GoodName=Violence Killer - Turok New Generation (J) [b1] CRC=60006C98 2605A381 RefMD5=C3005D76AF42E929E5C67421A19F8235 [E790BE1A5B883BEBA44BC0D2666C65F5] GoodName=Virtual Chess 64 (E) (M6) [!] CRC=2FDAA221 A588A7CE Players=2 SaveType=None Mempak=Yes [4166D03402397A56043AC2CD45F4CB87] GoodName=Virtual Chess 64 (E) (M6) [b1] CRC=2FDAA221 A588A7CE RefMD5=E790BE1A5B883BEBA44BC0D2666C65F5 [C5594DEFBCFE16D56284C66FDE49E540] GoodName=Virtual Chess 64 (E) (M6) [b2] CRC=2FDAA221 A588A7CE RefMD5=E790BE1A5B883BEBA44BC0D2666C65F5 [88D89282B2346F98C7F30850B061D486] GoodName=Virtual Chess 64 (E) (M6) [o1] CRC=2FDAA221 A588A7CE RefMD5=E790BE1A5B883BEBA44BC0D2666C65F5 [CB2B7214BE1084F2BFAEE556B0B4FD2C] GoodName=Virtual Chess 64 (E) (M6) [o1][h1C] CRC=2FDAA221 A588A7CE RefMD5=E790BE1A5B883BEBA44BC0D2666C65F5 [F8A35270279B277586D7210FD15134FF] GoodName=Virtual Chess 64 (U) (M3) [!] CRC=82B3248B E73E244D Players=2 SaveType=None Mempak=Yes [F05BD2DAD01F3E354713380AAFFB63E9] GoodName=Virtual Chess 64 (U) (M3) [b1] CRC=82B3248B E73E244D RefMD5=F8A35270279B277586D7210FD15134FF [C252FEC96171ABD07A6C5B99B74924D4] GoodName=Virtual Chess 64 (U) (M3) [b1][o1] CRC=82B3248B E73E244D RefMD5=F8A35270279B277586D7210FD15134FF [F41FCA7F185B3EC45ED90491BC8C0983] GoodName=Virtual Chess 64 (U) (M3) [f1] (PAL) CRC=46F3248B 534F2F61 RefMD5=F8A35270279B277586D7210FD15134FF [E62751EFDE5312ED12DEC6C9FDCBF062] GoodName=Virtual Chess 64 (U) (M3) [f1][o1] CRC=46F3248B 534F2F61 RefMD5=F8A35270279B277586D7210FD15134FF [0343B990F58CD816D96FBE5D5E710C82] GoodName=Virtual Chess 64 (U) [o1] CRC=82B3248B E73E244D RefMD5=F8A35270279B277586D7210FD15134FF [AB68FB43F012C1A45AF1DBCC8E8C109C] GoodName=Virtual Pool 64 (E) [!] CRC=98F9F2D0 03D9F09C Players=2 SaveType=None Mempak=Yes CountPerOp=1 [C4FD61C707977F1BF48DC15E31BD2FB1] GoodName=Virtual Pool 64 (E) [o1] CRC=98F9F2D0 03D9F09C RefMD5=AB68FB43F012C1A45AF1DBCC8E8C109C [6D3DB67319DA339DF4B68AD0084904D5] GoodName=Virtual Pool 64 (U) [!] CRC=4E4A7643 A37439D7 Players=2 SaveType=None Mempak=Yes CountPerOp=1 [C6855DF00BD5BE8A41DCE809093EE40B] GoodName=Virtual Pool 64 (U) [o1] CRC=4E4A7643 A37439D7 RefMD5=6D3DB67319DA339DF4B68AD0084904D5 [90002501777E3237739F5ED9B0E349E2] GoodName=Virtual Pro Wrestling 2 - Oudou Keishou (J) [!] CRC=CD094235 88074B62 Players=4 SaveType=SRAM Mempak=Yes Rumble=Yes [5E6202200AF40A8F026780EDFE1E15D0] GoodName=Virtual Pro Wrestling 64 (J) [!] CRC=045C08C4 4AFD798B Players=4 SaveType=SRAM Mempak=Yes Rumble=Yes [7FDC16C96B517D4E433CF7353B22FBA6] GoodName=Virtual Pro Wrestling 64 (J) [b1] CRC=045C08C4 4AFD798B RefMD5=5E6202200AF40A8F026780EDFE1E15D0 [290BE44B47110A011523A343786A15A0] GoodName=Virtual Pro Wrestling 64 (J) [f1] CRC=B3CD11F6 60725EB0 RefMD5=5E6202200AF40A8F026780EDFE1E15D0 [9B241103CE0F13CAD5FE522DF67ED88B] GoodName=Virtual Pro Wrestling 64 (J) [f2] CRC=B3CD11F6 60725EB0 RefMD5=5E6202200AF40A8F026780EDFE1E15D0 [1D2CB88BBCB67E12289B74F5BD88AE4C] GoodName=Virtual Pro Wrestling 64 (J) [h1C] CRC=045C08C4 4AFD798B RefMD5=5E6202200AF40A8F026780EDFE1E15D0 [35BF5C390AF1AD730E00EB618AED7B72] GoodName=Virtual Springfield Site Intro by Presten (PD) CRC=4F55D05C 0CD66C91 [2AEE59CC8DDA4382969BB76DC97D4228] GoodName=Vivid Dolls (Aleck64) CRC=2F57C9F7 F1E29CA6 SaveType=Eeprom 4KB [02AED169EB579494ACE75D22E10D789B] GoodName=WCW Backstage Assault (U) [!] CRC=396F5ADD 6693ECA7 Players=4 SaveType=None Mempak=Yes Rumble=Yes [9E943752BCF4FBA9CA3028E596F4EB4A] GoodName=WCW Mayhem (E) [!] CRC=AA7B0658 9C96937B Players=4 SaveType=None Mempak=Yes Rumble=Yes [F1AF35375519E97BB7C0E37E2F68416E] GoodName=WCW Mayhem (E) [h1C] CRC=AA7B0658 9C96937B RefMD5=9E943752BCF4FBA9CA3028E596F4EB4A [87BF3784709CD09693CD7BCC08460C63] GoodName=WCW Mayhem (U) [!] CRC=33BE8CD6 EC186912 Players=4 SaveType=None Mempak=Yes Rumble=Yes [5D7368D95B89F451E68F0832ED2BA8FF] GoodName=WCW Mayhem (U) [f1] (PAL) CRC=2AD07230 7A0719F7 RefMD5=87BF3784709CD09693CD7BCC08460C63 [1E9FEAD701FE5AAAA248D4713891775D] GoodName=WCW Nitro (U) [!] CRC=D4C45A1A F425B25E Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=3 [EC097EB33BAD93A8AC6E15F7839762AB] GoodName=WCW Nitro (U) [b3] CRC=D4C45A1A F425B25E RefMD5=1E9FEAD701FE5AAAA248D4713891775D [BC8BA67065FDBAA731DEFC866D25B8C2] GoodName=WCW Nitro (U) [b1] CRC=D4C45A1A F425B25E RefMD5=1E9FEAD701FE5AAAA248D4713891775D [CE86CE535A5B55AE4A0E6CC942701082] GoodName=WCW Nitro (U) [b2] CRC=5DDB495C CE6E5573 RefMD5=1E9FEAD701FE5AAAA248D4713891775D [8524D92A742BC9D0D6F072F9F80E887C] GoodName=WCW Nitro (U) [f1] (PAL) CRC=85DB4944 43ADE940 RefMD5=1E9FEAD701FE5AAAA248D4713891775D [A6A0109023837C4ED5CAC62F4A66ABA6] GoodName=WCW Nitro (U) [f2] (PAL) CRC=ACDCA0C6 0F4C66F9 RefMD5=1E9FEAD701FE5AAAA248D4713891775D [553D8D5347969C66E5D91C3FE35208B9] GoodName=WCW vs. nWo - World Tour (E) [!] CRC=8BDBAF68 345B4B36 Players=4 SaveType=None Mempak=Yes Rumble=Yes [203C3BBFDD10C5A0B7C5D0CDB085D853] GoodName=WCW vs. nWo - World Tour (U) (V1.0) [!] CRC=2C3E19BD 5113EE5E Players=4 SaveType=None Mempak=Yes Rumble=Yes [6BD5C85E25BF3146A42F962A379B4F54] GoodName=WCW vs. nWo - World Tour (U) (V1.0) [b1] CRC=2C3E19BD 5113EE5E RefMD5=203C3BBFDD10C5A0B7C5D0CDB085D853 [B7A220B59303D47F3BEAE233CA868CFD] GoodName=WCW vs. nWo - World Tour (U) (V1.1) [!] CRC=71BE60B9 1DDBFB3C Players=4 SaveType=None Mempak=Yes Rumble=Yes [30C6676EC1D62122F4E7607EF3ABBD41] GoodName=WCW-nWo Revenge (E) [!] CRC=68E8A875 0CE7A486 Players=4 SaveType=SRAM Rumble=Yes CountPerOp=1 [07F0AD841350BD7CA1E6A99FB7E887E6] GoodName=WCW-nWo Revenge (E) [h1C] CRC=68E8A875 0CE7A486 RefMD5=30C6676EC1D62122F4E7607EF3ABBD41 [C1384F3637D7A381B29341FED3EF3CEB] GoodName=WCW-nWo Revenge (U) [!] CRC=DEE596AB AF3B7AE7 Players=4 SaveType=SRAM Rumble=Yes CountPerOp=1 [B230D307428F4B69B3A80109AC905A44] GoodName=WCW-nWo Revenge (U) [b1] CRC=DEE596AB AF3B7AE7 RefMD5=C1384F3637D7A381B29341FED3EF3CEB [117EF2639E0485210C7AB70CBF3E0C00] GoodName=WCW-nWo Revenge (U) [b2] CRC=DEE596AB AF3B7AE7 RefMD5=C1384F3637D7A381B29341FED3EF3CEB [D6CD1AF1597CF0D279A39F75EE07C43A] GoodName=WCW-nWo Revenge (U) [f1] (PAL) CRC=768AD2AA C3C79B68 RefMD5=C1384F3637D7A381B29341FED3EF3CEB [847A00F2C5DA6696FC49702431DF3150] GoodName=WCW-nWo Revenge (U) [f2] (PAL) CRC=768AD2AA C3C79B68 RefMD5=C1384F3637D7A381B29341FED3EF3CEB [EBC0CF55FC58845C6EE86CF8B2D87303] GoodName=WWF - War Zone (E) [!] CRC=33A275A4 B8504459 Players=4 SaveType=None Mempak=Yes Rumble=Yes [2322DA2B9E7DC74678CD683B7A246B49] GoodName=WWF - War Zone (U) [!] CRC=CD5BEC0F 86FD1008 Players=4 SaveType=None Mempak=Yes Rumble=Yes [3FDB2E5F9982FDA2C2344A883B8AB6EF] GoodName=WWF Attitude (E) [!] CRC=5BF45B7B 596BEEE8 Players=4 SaveType=None Mempak=Yes Rumble=Yes [B86EC8D19D7D1A50EA900EA10355A735] GoodName=WWF Attitude (G) [!] CRC=8F3151C8 4F3AF545 Players=4 SaveType=None Mempak=Yes Rumble=Yes [5AC5CEDBD22CEEA8DD50CF6084193357] GoodName=WWF Attitude (G) [b1] CRC=8F3151C8 4F3AF545 RefMD5=B86EC8D19D7D1A50EA900EA10355A735 [9FAF514CB3DBB742C129DEB395DCA342] GoodName=WWF Attitude (U) [!] CRC=D2BE2F14 38453788 Players=4 SaveType=None Mempak=Yes Rumble=Yes [6D4CBA7FB2E910CA1A87E63A4C1924C2] GoodName=WWF Attitude (U) [b1] CRC=D2BE2F14 38453788 RefMD5=9FAF514CB3DBB742C129DEB395DCA342 [44BC029B5219E1A16F3B99125056F98B] GoodName=WWF Attitude (U) [b2] CRC=D2BE2F14 38453788 RefMD5=9FAF514CB3DBB742C129DEB395DCA342 [382ECA33C5DD52B8C03A56D20F2D3F21] GoodName=WWF Attitude (U) [f1] (PAL) CRC=D89261A9 B1A2C9AF RefMD5=9FAF514CB3DBB742C129DEB395DCA342 [D94A8F78178473D4BA4BED62FA8E2E66] GoodName=WWF No Mercy (E) (V1.0) [!] CRC=6D8DF08E D008C3CF SaveType=Flash RAM Players=4 Mempak=Yes Rumble=Yes [473FDDBB121255A171A40C14130D0165] GoodName=WWF No Mercy (E) (V1.0) [b1] CRC=6D8DF08E D008C3CF RefMD5=D94A8F78178473D4BA4BED62FA8E2E66 [C9A6446918DA5D65612C521D432B7DA1] GoodName=WWF No Mercy (E) (V1.0) [b2] CRC=6D8DF08E D008C3CF RefMD5=D94A8F78178473D4BA4BED62FA8E2E66 [400A14F132D993F5544F8B008EC136FA] GoodName=WWF No Mercy (E) (V1.1) [!] CRC=8CDB94C2 CB46C6F0 Players=4 SaveType=Flash RAM Mempak=Yes Rumble=Yes [04C492BE7F89FC6F425238BD67629544] GoodName=WWF No Mercy (U) (V1.0) [!] CRC=4E4B0640 1B49BCFB Players=4 SaveType=Flash RAM Mempak=Yes Rumble=Yes [51074CFE7A319270CF088A7C65387368] GoodName=WWF No Mercy (U) (V1.0) [t1] CRC=361E1288 7A26BE5F RefMD5=04C492BE7F89FC6F425238BD67629544 [66B8EC24557A50514A814F15429BD559] GoodName=WWF No Mercy (U) (V1.1) [!] CRC=6C80F13B 427EDEAA RefMD5=04C492BE7F89FC6F425238BD67629544 [B75149F87CC5F3A508643AC377F2FCC9] GoodName=WWF WrestleMania 2000 (E) [!] CRC=C71353BE AA09A6EE Players=4 SaveType=SRAM Mempak=Yes Rumble=Yes [EBB9E3D3782347743BFFB8B6D178FC8A] GoodName=WWF WrestleMania 2000 (E) [h1C] CRC=C71353BE AA09A6EE RefMD5=B75149F87CC5F3A508643AC377F2FCC9 [11EEE2F34BF8DA05A1B8F4FB9FE9F74C] GoodName=WWF WrestleMania 2000 (J) [!] CRC=12737DA5 23969159 Players=4 SaveType=SRAM Mempak=Yes Rumble=Yes [AFC5EEDD3FCEEF85458E9C8FA162B303] GoodName=WWF WrestleMania 2000 (J) [b1] CRC=12737DA5 23969159 RefMD5=11EEE2F34BF8DA05A1B8F4FB9FE9F74C [D9030CA30E4D1AF805ACCE1BFED988CC] GoodName=WWF WrestleMania 2000 (U) [!] CRC=90A59003 31089864 Players=4 SaveType=SRAM Mempak=Yes Rumble=Yes [CB174FA89F352DD8451A43FEF2B8D1AA] GoodName=WWF WrestleMania 2000 (U) [b1] CRC=90A59003 31089864 RefMD5=D9030CA30E4D1AF805ACCE1BFED988CC [9EAFCA831487923E0BE79717A678894E] GoodName=WWF WrestleMania 2000 (U) [t1] (Never Drop Weapons) CRC=90A59003 31089864 RefMD5=D9030CA30E4D1AF805ACCE1BFED988CC [5F1906DF4EB30537C2AC2FCBD005907D] GoodName=Waialae Country Club - True Golf Classics (E) (M4) (V1.0) [!] CRC=93053075 261E0F43 Players=4 SaveType=SRAM Rumble=Yes [1FC540D2168650E135BCC7D3B542E03A] GoodName=Waialae Country Club - True Golf Classics (E) (M4) (V1.0) [b1] CRC=93053075 261E0F43 RefMD5=5F1906DF4EB30537C2AC2FCBD005907D [F7C1B1EE1CE37CE09AA48C7E0A115EFA] GoodName=Waialae Country Club - True Golf Classics (E) (M4) (V1.1) [!] CRC=0C5057AD 046E126E RefMD5=5F1906DF4EB30537C2AC2FCBD005907D [DD8154D507C88694AFD69C7AF16A8CD6] GoodName=Waialae Country Club - True Golf Classics (U) (V1.0) [!] CRC=8066D58A C3DECAC1 Players=4 SaveType=SRAM Rumble=Yes [67F75C4DD30922A001C8C32AEB9333AC] GoodName=Waialae Country Club - True Golf Classics (U) (V1.1) [!] CRC=DD318CE2 B73798BA RefMD5=DD8154D507C88694AFD69C7AF16A8CD6 [D25DD15903BDCB7724A2E8A02561987F] GoodName=War Gods (E) [!] CRC=D715CC70 271CF5D6 Players=2 SaveType=None CountPerOp=1 [9FF2BA3C8408DE9F0EDB6D764A97C197] GoodName=War Gods (U) [!] CRC=F7FE28F6 C3F2ACC3 Players=2 SaveType=None CountPerOp=1 [D08D61E3C244A081C166C6A8D539A181] GoodName=War Gods (U) [o1] CRC=F7FE28F6 C3F2ACC3 RefMD5=9FF2BA3C8408DE9F0EDB6D764A97C197 [0D3F2F58310387C60F932F6EC936788D] GoodName=War Gods (U) [o1][h1C] CRC=F7FE28F6 C3F2ACC3 RefMD5=9FF2BA3C8408DE9F0EDB6D764A97C197 [F87937C9DE3703898C480FC84C692523] GoodName=War Gods (U) [o2] CRC=F7FE28F6 C3F2ACC3 RefMD5=9FF2BA3C8408DE9F0EDB6D764A97C197 [5C98466C2B2AAF7F3B51D4406EEE39FD] GoodName=War Gods (U) [o3] CRC=F7FE28F6 C3F2ACC3 RefMD5=9FF2BA3C8408DE9F0EDB6D764A97C197 [771FC17CDC840ED36DB8A699757C37F8] GoodName=War Gods (U) [t1] (God Mode) CRC=59BEB6F9 E6DC1630 RefMD5=9FF2BA3C8408DE9F0EDB6D764A97C197 [D24435C65C48E8DE0831FC8F466BAA51] GoodName=War Gods (U) (Power Bar Hack) CRC=AFBEB6F6 B0E715DC RefMD5=9FF2BA3C8408DE9F0EDB6D764A97C197 [1F83663B2C84512FC3706A6CACC1A9F3] GoodName=Wave Race 64 (Ch) (iQue) [!] [A66FEE7AF89D58B24A25C346A0E90172] GoodName=Wave Race 64 (Ch) (V2) (iQue) (Manual) [!] [926B1495565435DA0AF29BB660532DA3] GoodName=Wave Race 64 (Ch) (V4) (iQue) (Manual) [!] [310659115E9939F219A783ABDD456CE9] GoodName=Wave Race 64 (E) (M2) [!] CRC=650EFA96 30DDF9A7 Players=2 SaveType=Eeprom 4KB Mempak=Yes [A992E010BC3740C7C266D4F6E90226A1] GoodName=Wave Race 64 (E) (M2) [h1C] CRC=650EFA96 30DDF9A7 RefMD5=310659115E9939F219A783ABDD456CE9 [470D3E391A2B4CEBF0A9E15EC49CD324] GoodName=Wave Race 64 (E) (M2) [o1] CRC=650EFA96 30DDF9A7 RefMD5=310659115E9939F219A783ABDD456CE9 [B32E555BC1A375256E8A4021A25339BE] GoodName=Wave Race 64 (J) [!] CRC=5C9191D6 B30AC306 Players=2 SaveType=Eeprom 4KB Mempak=Yes [D05C6F3CAF9059B306CC13535E2A8BA6] GoodName=Wave Race 64 (J) (V1.1) [!] CRC=44995484 20A5FC5E RefMD5=B32E555BC1A375256E8A4021A25339BE [AE480013F39D4AEC86EEA1B4995600D1] GoodName=Wave Race 64 (U) (V1.0) [!] CRC=7DE11F53 74872F9D Players=2 SaveType=Eeprom 4KB Mempak=Yes [D653E6B050F63B5E1C1E9856319287E1] GoodName=Wave Race 64 (U) (V1.0) [t1] CRC=C5F4865F 03340B83 RefMD5=AE480013F39D4AEC86EEA1B4995600D1 [2048A640C12D1CF2052BA1629937D2FF] GoodName=Wave Race 64 (U) (V1.1) [!] CRC=492F4B61 04E5146A Players=2 SaveType=Eeprom 4KB Mempak=Yes [FF67DF97476C210D158779AE6142F239] GoodName=Wave Race 64 - Shindou Edition (J) (V1.2) [!] CRC=535DF3E2 609789F1 Players=2 CountPerOp=3 SaveType=Eeprom 4KB Mempak=Yes Rumble=Yes [ECC1692D12FDCB0C3F605E44DD54CE8C] GoodName=Wave Race 64 - Shindou Edition (J) (V1.2) [T+Eng1.0_Zoinkity] CRC=57AF893E 884A377C RefMD5=FF67DF97476C210D158779AE6142F239 [D0472173524D6EC4E78CBCA30EFD98FC] GoodName=Wave Race 64 - Shindou Edition (J) (V1.2) [T+Eng1.1_Zoinkity] CRC=57AF893E 8EEF209A RefMD5=FF67DF97476C210D158779AE6142F239 [AFBC694A3BA5AE83D3CEEF906BF01839] GoodName=Wave Race 64 - Shindou Edition (J) (V1.2) [b1] CRC=535DF3E2 609789F1 RefMD5=FF67DF97476C210D158779AE6142F239 [41E419F4392CFEF2C354006169362286] GoodName=Wave Race 64 - Shindou Edition (J) (V1.2) [b2] CRC=535DF3E2 609789F1 RefMD5=FF67DF97476C210D158779AE6142F239 [CAD993128A11B5616E5DDE5CF50CB998] GoodName=Wave Race 64 - Shindou Edition (J) (V1.2) [h1C] CRC=535DF3E2 609789F1 RefMD5=FF67DF97476C210D158779AE6142F239 [F9DA7EB74E391C5E6813212F7F55959A] GoodName=Wave Race 64 - Shindou Edition (J) (V1.2) [o1] CRC=535DF3E2 609789F1 RefMD5=FF67DF97476C210D158779AE6142F239 [24A0D8C8CABC22116E469476FF6C691D] GoodName=Wayne Gretzky's 3D Hockey '98 (E) (M4) [!] CRC=661B45F3 9ED6266D Players=4 SaveType=None Mempak=Yes [810F8BC2C8C66BDA3B206C7DD4B6D42F] GoodName=Wayne Gretzky's 3D Hockey '98 (U) [!] CRC=5A9D3859 97AAE710 Players=4 SaveType=None Mempak=Yes [096726498E698B51AFE72AAB5262A15A] GoodName=Wayne Gretzky's 3D Hockey '98 (U) [T+Ita_cattivik66] CRC=5A9D3859 97AAE710 [C9F95F9480B5867B03CFC0533F319253] GoodName=Wayne Gretzky's 3D Hockey '98 (U) [h1C] CRC=5A9D3859 97AAE710 [F7E5BDF8E4076C27961BAF9A42C73524] GoodName=Wayne Gretzky's 3D Hockey '98 (U) [h2C] CRC=5A9D3859 97AAE710 [319816AAA30E512827BE7B7F81F80D86] GoodName=Wayne Gretzky's 3D Hockey (E) (M4) [!] CRC=2209094B 2C9559AF Players=4 SaveType=None Mempak=Yes [65F1D583B5392D3467BD187224FBBD89] GoodName=Wayne Gretzky's 3D Hockey (E) (M4) [b1] CRC=2209095F ECD28311 RefMD5=319816AAA30E512827BE7B7F81F80D86 [0905A37DBB3B9CEC38B52F6E109A9EAA] GoodName=Wayne Gretzky's 3D Hockey (E) (M4) [h1C] CRC=2209094B 2C9559AF RefMD5=319816AAA30E512827BE7B7F81F80D86 [61E637B542D5DF178040454075C28E19] GoodName=Wayne Gretzky's 3D Hockey (J) [!] CRC=F1301043 FD80541A Players=4 SaveType=None Mempak=Yes Rumble=Yes [371620871660767900FC00F72681E1FD] GoodName=Wayne Gretzky's 3D Hockey (J) [b1] CRC=F1301043 FD80541A RefMD5=61E637B542D5DF178040454075C28E19 [03877A5CD0DD1E8C14EEEE70660E79DA] GoodName=Wayne Gretzky's 3D Hockey (J) [o1] CRC=F1301043 FD80541A RefMD5=61E637B542D5DF178040454075C28E19 [81EFB80DB5E014D865EC2EC88C393E4D] GoodName=Wayne Gretzky's 3D Hockey (J) [o2] CRC=F1301043 FD80541A RefMD5=61E637B542D5DF178040454075C28E19 [6DF0D6259261D0096C90BBC6AA037D8E] GoodName=Wayne Gretzky's 3D Hockey (U) (V1.0) [!] CRC=6B45223F F00E5C56 Players=4 SaveType=None Mempak=Yes [EDBDB55AD58554C48B25A47D7E178513] GoodName=Wayne Gretzky's 3D Hockey (U) (V1.0) [b1] CRC=6B45223F F00E5C56 RefMD5=6DF0D6259261D0096C90BBC6AA037D8E [5349ABD4EE13C8F029A60032735B1AE3] GoodName=Wayne Gretzky's 3D Hockey (U) (V1.0) [o1] CRC=6B45223F F00E5C56 RefMD5=6DF0D6259261D0096C90BBC6AA037D8E [04E650B7742A69DAE98F125D1B492D78] GoodName=Wayne Gretzky's 3D Hockey (U) (V1.1) [!] CRC=DC3BAA59 0ABB456A Players=4 SaveType=None Mempak=Yes [98C20A229170CF393BBF442D44FFC5B1] GoodName=Wet Dreams Can Beta Demo by Immortal (POM '99) (PD) CRC=CA3BC095 9649860A [D652769F8EE9BBE5F0BD5DF9B955D47E] GoodName=Wet Dreams Madeiragames Demo by Immortal (POM '99) (PD) CRC=993B7D7A 2E54F04D [37C0C97DFCE99F9968778448F5C9F0B6] GoodName=Wet Dreams Main Demo by Immortal (POM '99) (PD) CRC=A3A95A57 9FE6C27D [7B7B2916A857B9FC513C5F9619B36C98] GoodName=Wet Dreams Readme by Immortal (POM '99) (PD) CRC=9C044945 D31E0B0C Status=5 SaveType=None Players=0 Rumble=No [A99E2CB6ACEF7A004961DE5F6DFEEFF0] GoodName=Wetrix (E) (M6) [!] CRC=CEA8B54F 7F21D503 Players=4 SaveType=None Mempak=Yes CountPerOp=3 [15F425829D54DD290451D2F3EBAF953F] GoodName=Wetrix (E) (M6) [f1] (NTSC) CRC=792C3A8E 0F2200F7 RefMD5=A99E2CB6ACEF7A004961DE5F6DFEEFF0 [087B6C2D5FBD778667C12D7FC7C305A7] GoodName=Wetrix (E) (M6) [t1] CRC=773E3E8E 1E8A0CBE RefMD5=A99E2CB6ACEF7A004961DE5F6DFEEFF0 [E8997BF5662540B184FBF8277D260984] GoodName=Wetrix (J) [!] CRC=DCB6EAFA C6BBCFA3 Players=4 SaveType=Eeprom 4KB CountPerOp=3 [08826E96F3FB022A1C6351774198BA9D] GoodName=Wetrix (J) [o1] CRC=DCB6EAFA C6BBCFA3 RefMD5=E8997BF5662540B184FBF8277D260984 [6E81D3056E409208E4AF2D39A2FF0F03] GoodName=Wetrix (U) (M6) [!] CRC=CEA8B54F 7F21D503 Players=4 SaveType=None Mempak=Yes CountPerOp=3 [2ABE36754E866B9B6C4BDCFFC1D11ABF] GoodName=Wheel of Fortune (U) [!] CRC=E896092B DC244D4E SaveType=None Players=4 Rumble=Yes [CC75D0771DBC825AC9F499400443A6A0] GoodName=Wheel of Fortune (U) [b1] CRC=E896092B DC244D4E RefMD5=2ABE36754E866B9B6C4BDCFFC1D11ABF [D20F2C6704D5B93372816BA0559E4E0F] GoodName=Wheel of Fortune (U) [o1] CRC=E896092B DC244D4E RefMD5=2ABE36754E866B9B6C4BDCFFC1D11ABF [CC8460B117AAFBD484CF43C1EB3D8E15] GoodName=Wheel of Fortune (U) [o1][b1] CRC=E896092B DC244D4E RefMD5=2ABE36754E866B9B6C4BDCFFC1D11ABF [764DCDF5163D3FCE81D3E7189FA97E05] GoodName=WideBoy BIOS V980910 CRC=D1C6C55D F010EF52 [FFF632A867CDADB5AB2098CB8E2CFADC] GoodName=WideBoy BIOS V980914 CRC=64F1084A 763C7E91 [F85F2A2B6CA64898F0ADD2A78CCDCCF3] GoodName=Wild Choppers (J) [!] CRC=0CEBC4C7 0C9CE932 Players=1 SaveType=Eeprom 4KB Rumble=Yes [BA538CBF43471B3522C4D08BAD0797A7] GoodName=Wild Choppers (J) [b1] CRC=0CEBC4C7 0C9CE932 RefMD5=F85F2A2B6CA64898F0ADD2A78CCDCCF3 [AC1339207A3E442B61EC0E074673C93B] GoodName=Wild Choppers (J) [b2] CRC=F4520439 753A6281 RefMD5=F85F2A2B6CA64898F0ADD2A78CCDCCF3 [DFB55C3F9B2D2A188616E9C123E0C816] GoodName=Wild Choppers (J) [b3] CRC=0CEBC4C7 0C9CE932 RefMD5=F85F2A2B6CA64898F0ADD2A78CCDCCF3 [7FE135D08035782A8AAE0BEFE9A9780B] GoodName=Wild Choppers (J) [o1] CRC=0CEBC4C7 0C9CE932 RefMD5=F85F2A2B6CA64898F0ADD2A78CCDCCF3 [B2DE25613755B234A376747422D83BBC] GoodName=Wild Choppers (J) [t1] CRC=F4520439 753A6281 RefMD5=F85F2A2B6CA64898F0ADD2A78CCDCCF3 [B867880C96C9E8D3130DDE5526C95439] GoodName=Wildwaters (U) (Prototype) CRC=A04237B9 68F62C72 [EE3D3550ACC463CA57408BF14E541F68] GoodName=WinBack (J) (V1.0) [!] CRC=1FA056E0 A4B9946A Players=4 SaveType=None Mempak=Yes Rumble=Yes [1B94D98F509F467F9BC541102F6EBDFC] GoodName=WinBack (J) (V1.0) [b1] CRC=1FA056E0 A4B9946A RefMD5=EE3D3550ACC463CA57408BF14E541F68 [9789A48E1D9E42C2F69C59964371089F] GoodName=WinBack (J) (V1.1) [!] CRC=C52E0BC6 56BC6556 Players=4 SaveType=None Mempak=Yes Rumble=Yes [48DA6CDCAB838153CAA2ECC3DD592A65] GoodName=WinBack - Covert Operations (U) [!] CRC=ED98957E 8242DCAC Players=4 SaveType=None Mempak=Yes Rumble=Yes [ACC6FD4E26D360D1BED54C316D7E33B9] GoodName=WinBack - Covert Operations (U) [b1] CRC=ED98957E 8242DCAC RefMD5=48DA6CDCAB838153CAA2ECC3DD592A65 [F3365B47E430011D89162FB0D7DD8DE5] GoodName=WinBack - Covert Operations (U) [f1] (PAL) CRC=337F24EE 73A807D9 RefMD5=48DA6CDCAB838153CAA2ECC3DD592A65 [FA34EAEBAA8A4E48D6BBD93DF62CD995] GoodName=WinBack - Covert Operations (U) [t1] CRC=35F51C8E 39EF72B8 RefMD5=48DA6CDCAB838153CAA2ECC3DD592A65 [5783373634B11F81C86908C3D81CA988] GoodName=Wipeout 64 (E) [!] CRC=54310E7D 6B5430D8 Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [7260DA1CECD0D8844C5E29AA63476DEF] GoodName=Wipeout 64 (E) (Beta) [!] CRC=136EBEE3 35B7229E Players=4 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [73C6D87DBE50F73F3B44E0F237A546D7] GoodName=Wipeout 64 (U) [!] CRC=132D2732 C70E9118 SaveType=None Mempak=Yes Rumble=Yes Players=4 CountPerOp=1 [361F65D37F41536CDE98F83CAD456217] GoodName=Wipeout 64 (U) [o1] CRC=132D2732 C70E9118 RefMD5=73C6D87DBE50F73F3B44E0F237A546D7 [0E274A162CAD0B1B50F9B8D64D9F82FC] GoodName=Wipeout 64 (U) [t1] CRC=A6A99491 52B4E765 RefMD5=73C6D87DBE50F73F3B44E0F237A546D7 [B8DD77F17A8B638B1D38F57C81EAA89A] GoodName=Wipeout 64 (U) [t2] CRC=A6A99491 52B4E765 RefMD5=73C6D87DBE50F73F3B44E0F237A546D7 [0FF1F8628D8FE69582DB54572D2BEA79] GoodName=Wonder Project J2 - Koruro no Mori no Jozet (J) [!] CRC=E43C9765 05B1C1BE Players=1 SaveType=None Mempak=Yes CountPerOp=1 [D6E56B92EC7DBFB8B14DD5D8CFF6492E] GoodName=Wonder Project J2 - Koruro no Mori no Jozet (J) [b1] CRC=E43C9765 05B1C1BE RefMD5=0FF1F8628D8FE69582DB54572D2BEA79 [F5977968B621E74773E80CC4A33F7D2E] GoodName=Wonder Project J2 - Koruro no Mori no Jozet (J) [h1C] CRC=E43C9765 05B1C1BE RefMD5=0FF1F8628D8FE69582DB54572D2BEA79 [3C02F56DD7B1A06BE83A7A288755612F] GoodName=Wonder Project J2 - Koruro no Mori no Jozet (J) [T+Eng1.0_Ryu] CRC=4F1E88F7 4A5A3F96 RefMD5=0FF1F8628D8FE69582DB54572D2BEA79 [3AA263ACA66F3A07BB081B575D66DEEB] GoodName=World Cup 98 (E) (M8) [!] CRC=F9FC3090 FF014EC2 Players=4 SaveType=None Mempak=Yes [E3DB1863E138B3AD5685A16029D0A44C] GoodName=World Cup 98 (E) (M8) [f1] (NTSC) CRC=F9FC3090 FF014EC2 RefMD5=3AA263ACA66F3A07BB081B575D66DEEB [4BEF5E9AA9E71205DAC1A7060E778235] GoodName=World Cup 98 (U) (M8) [!] CRC=BD636D6A 5D1F54BA Players=4 SaveType=None Mempak=Yes [431DE8F6611A8131B536F0EDE1F330D9] GoodName=World Driver Championship (E) (M5) [!] CRC=AC062778 DFADFCB8 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [9A2B0F3226FB8D129BEB7509C169476A] GoodName=World Driver Championship (E) (M5) [h1C] CRC=AC062778 DFADFCB8 RefMD5=431DE8F6611A8131B536F0EDE1F330D9 [7C567A5BB1AD4CBE414FB6BBFF66E336] GoodName=World Driver Championship (U) [!] CRC=308DFEC8 CE2EB5F6 Players=2 SaveType=None Mempak=Yes Rumble=Yes CountPerOp=1 [4B86C373533D015860467C5DC1F1C662] GoodName=World Driver Championship (U) [b1] CRC=308DFEC8 CE2EB5F6 RefMD5=7C567A5BB1AD4CBE414FB6BBFF66E336 [0C26665C2F40A786778EE4370C3A43FC] GoodName=World Driver Championship (U) [f1] (PAL) CRC=2A721F06 4097F7B1 RefMD5=7C567A5BB1AD4CBE414FB6BBFF66E336 [628C10A5D2ACC462C5527E6302467440] GoodName=World Driver Championship (U) [f2] (PAL) CRC=2A980400 7D805B1C RefMD5=7C567A5BB1AD4CBE414FB6BBFF66E336 [A4599EF88F36E62C1692BCEC416C5477] GoodName=World Driver Championship (U) [t1] CRC=C8FEF05D DAA3407D RefMD5=7C567A5BB1AD4CBE414FB6BBFF66E336 [44FC2A7F028F0B6F71B255F672C8B495] GoodName=Worms - Armageddon (E) (M6) [!] CRC=2D21C57B 8FE4C58C Players=4 SaveType=Eeprom 4KB [35FDA68C8481F7C3419CCD91EDBB6A9E] GoodName=Worms - Armageddon (E) (M6) [f1] (NTSC) CRC=94FBA5FD BC8FE181 RefMD5=44FC2A7F028F0B6F71B255F672C8B495 [491D4DB6718302489BF05FB962C73651] GoodName=Worms - Armageddon (U) (M3) [!] CRC=13E959A0 0E93CAB0 Players=4 SaveType=Eeprom 4KB [EC2BCB1B7FC7D068BE1F39E79E49A842] GoodName=Xena Warrior Princess - The Talisman of Fate (E) [!] CRC=0A1667C7 293346A6 CountPerOp=4 Players=4 SaveType=None Mempak=Yes Rumble=Yes [1AC234649D28F09E82C0D11ABB17F03B] GoodName=Xena Warrior Princess - The Talisman of Fate (U) [!] CRC=0553AE9D EAD8E0C1 CountPerOp=3 Players=4 SaveType=None Mempak=Yes Rumble=Yes [687AF471A5A16D665E16AC1E9069D16B] GoodName=Xena Warrior Princess - The Talisman of Fate (U) [f1] (PAL) CRC=BC875B60 8C993DF1 RefMD5=1AC234649D28F09E82C0D11ABB17F03B [6CB35999D2E3820391913F0E4B9BC072] GoodName=Xena Warrior Princess - The Talisman of Fate (U) [t1] CRC=BEADC61C 8622D9F6 RefMD5=1AC234649D28F09E82C0D11ABB17F03B [BC4BCD45FA712ECDD8A85918A9CA5F4B] GoodName=Xeno Crisis (A) CRC=470112E9 53C66CB4 Players=2 SaveType=None Mempak=Yes Rumble=Yes [9137129A586E1BCAB6AE81BAC6B01275] GoodName=Xplorer64 BIOS V1.067 (G) CRC=656C6561 73652031 [763E5EACA4606E15A1E4D67DD6D987C0] GoodName=XtraLife Dextrose Demo by RedboX (PD) [h1C] CRC=1EDA4DE0 22BF698D [46C45620F26E4ED77B918F862FA597CD] GoodName=XtraLife Dextrose Demo by RedboX (PD) CRC=1EDA4DE0 22BF698D [A954E2BC5D774DC6E1CEBCE529F1CDED] GoodName=Y2K Demo by WT_Riker (PD) [b1] CRC=83F9F2CB E7BC4744 [76A1480BE9985D30FC580E4216974D3E] GoodName=Y2K Demo by WT_Riker (PD) CRC=83F9F2CB E7BC4744 [E24942948F7140EE4260268DB763D0FD] GoodName=Yakouchuu II - Satsujin Kouru (J) [!] CRC=9F8B96C3 A01194DC Players=1 Rumble=Yes CountPerOp=1 [F7AA4F819F41CB4236792A8145684627] GoodName=Yoshi's Story (Ch) (iQue) [!] [DF8164DA753C9EF0B7C2611F584E81A9] GoodName=Yoshi's Story (Ch) (V2) (iQue) (Manual) [!] [D6778D9D560DEC35D8C05AF4738E27AA] GoodName=Yoshi's Story (Ch) (V4) (iQue) (Manual) [!] [85A90C61B65B56334E00950210C6CFC4] GoodName=Yoshi's Story (Ch) (V6) (iQue) (Manual) [!] [DD8A0E5472F13EA87B176F0155FA0C66] GoodName=Yoshi Story (J) [!] CRC=2DCFCA60 8354B147 Players=1 SaveType=Eeprom 16KB Rumble=Yes [B7B236051E4347428288F8D840BFD2E4] GoodName=Yoshi Story (J) [b1] CRC=E3CCFE36 398FBC75 RefMD5=DD8A0E5472F13EA87B176F0155FA0C66 [4BA4B1A2ABAF72EC83A2DB4CB6AEB7D6] GoodName=Yoshi Story (J) [f1] CRC=70666F63 FEC28A44 RefMD5=DD8A0E5472F13EA87B176F0155FA0C66 [38F004F68D5F1ABBC4391D156DEBCAEF] GoodName=Yoshi Story (J) [f2] CRC=70666F63 FEC28A44 RefMD5=DD8A0E5472F13EA87B176F0155FA0C66 [C43E3E28D84F337FF1BC88FA77996D33] GoodName=Yoshi Story (J) [f3] CRC=05BCD54E 97E2A8C9 RefMD5=DD8A0E5472F13EA87B176F0155FA0C66 [20ED9559D47535EA491D3548FB9E15E2] GoodName=Yoshi Story (J) [f4] CRC=D4DD9982 FDBA7B67 RefMD5=DD8A0E5472F13EA87B176F0155FA0C66 [3B41BAD41ABF4512FBF62727410EAC71] GoodName=Yoshi Story (J) [t1] CRC=369B314B E7780D04 RefMD5=DD8A0E5472F13EA87B176F0155FA0C66 [CF3802A99D8FE412359F1EB018FD991F] GoodName=Yoshi Story (J) [t2] (Health and Eggs) CRC=AF5F3773 B29B2C9A RefMD5=DD8A0E5472F13EA87B176F0155FA0C66 [2524E5FB8ED4BB8C831C5AC057E8F344] GoodName=Yoshi's Story (E) (M3) [!] CRC=D3F97D49 6924135B Players=1 SaveType=Eeprom 16KB Rumble=Yes [6E5E919D0FA292B97AAD08E9200E8C9C] GoodName=Yoshi's Story (E) (M3) [b1] CRC=D3F97D49 6924135B RefMD5=2524E5FB8ED4BB8C831C5AC057E8F344 [5D3C7935193A3B7327021B5E4740DEB6] GoodName=Yoshi's Story (E) (M3) [b2] CRC=D3F97D49 6924135B RefMD5=2524E5FB8ED4BB8C831C5AC057E8F344 [E2F6EF5D4181558656DDE8B0162D39D3] GoodName=Yoshi's Story (E) (M3) [b2][f1] CRC=9CB1BBB0 BC3439C7 RefMD5=2524E5FB8ED4BB8C831C5AC057E8F344 [C80D0A8193D530530AE875F8D9398E82] GoodName=Yoshi's Story (E) (M3) [b3] CRC=D3F97D49 6924135B RefMD5=2524E5FB8ED4BB8C831C5AC057E8F344 [ADEE5835A112677CCF74D5F4A1503294] GoodName=Yoshi's Story (E) (M3) [t1] (Health and Eggs) CRC=94FEDD3F 95719E88 RefMD5=2524E5FB8ED4BB8C831C5AC057E8F344 [586A092E22604840973B82DFACEAC77A] GoodName=Yoshi's Story (U) (M2) [!] CRC=2337D8E8 6B8E7CEC Players=1 SaveType=Eeprom 16KB Rumble=Yes [B907C051F1D7D0D15DE65EA87CF3F922] GoodName=Yoshi's Story (U) (M2) [b1] CRC=9CB1BBB0 BC3439C7 RefMD5=586A092E22604840973B82DFACEAC77A [B4A2127033CB671EEFE535B08F1AFB38] GoodName=Yoshi's Story (U) (M2) [b2] CRC=88047F1D 3B837D28 RefMD5=586A092E22604840973B82DFACEAC77A [D635824B5FC256DA0F2E457663CFF286] GoodName=Yoshi's Story (U) (M2) [b3] CRC=CCE336FE 8F3975BC RefMD5=586A092E22604840973B82DFACEAC77A [75F91A5D3012080EE9BF90C017B5128F] GoodName=Yoshi's Story (U) (M2) [b4] CRC=395E91DF 441D95C5 RefMD5=586A092E22604840973B82DFACEAC77A [8F47F6A80734D6C8501ADED549FF65C5] GoodName=Yoshi's Story (U) (M2) [b5] CRC=E3CCFE36 398FBC75 RefMD5=586A092E22604840973B82DFACEAC77A [0DCF29478A6DB0A3113B9EDD2AE428E1] GoodName=Yoshi's Story (U) (M2) [f1] CRC=E3CCFE36 398FBC75 RefMD5=586A092E22604840973B82DFACEAC77A [7CE4559FED0EA7D82670E9A4ECC370CD] GoodName=Yoshi's Story (U) (M2) [t1] CRC=88047F1D 3B837D28 RefMD5=586A092E22604840973B82DFACEAC77A [3DA2C5FA29D11D0481B60F6C6B14393A] GoodName=Yoshi's Story (U) (M2) [t2] (Health and Eggs) CRC=E606EE26 8783EC43 RefMD5=586A092E22604840973B82DFACEAC77A [5FE7486A5A458D538179DA898B067AD3] GoodName=Yoshi's Story BootEmu (PD) CRC=83D8A30C 8552C117 [2AE35BDF163613024D876A09F25063F3] GoodName=Yuke Yuke!! Trouble Makers (J) [!] CRC=9FE6162D E97E4037 Players=1 SaveType=Eeprom 4KB CountPerOp=1 [6F9E56C8A2B6BA5F6DBE5214E352590D] GoodName=Yuke Yuke!! Trouble Makers (J) [a1] CRC=9FE6162D E97E4037 RefMD5=2AE35BDF163613024D876A09F25063F3 [BE734B15770D28C0A26D2DB98DF6CCCC] GoodName=Yuke Yuke!! Trouble Makers (J) [b1] CRC=9FE6162D E97E4037 RefMD5=2AE35BDF163613024D876A09F25063F3 [BADCEDF5B6BECDBCCA7267BD2D791EB1] GoodName=Yuke Yuke!! Trouble Makers (J) [o1] CRC=9FE6162D E97E4037 RefMD5=2AE35BDF163613024D876A09F25063F3 [C66D2037A654378C5CD365B135E36D87] GoodName=Z64 BIOS V1.05 CRC=551E06B4 02CD16A8 [730209AD52C178551C29074F49AE9B39] GoodName=Z64 BIOS V1.07 CRC=551E06B4 02CD16A8 [60BC7FE282C6BE6B90EA0B5FC63BC944] GoodName=Z64 BIOS V1.08 (Ravemax Hack V1.00b) CRC=00000000 00005053 [F5441580B27ECFB94A8C6B7989B1D101] GoodName=Z64 BIOS V1.08 CRC=00000000 00005053 [60A39BA7F3DCC592112FDF8220335F3D] GoodName=Z64 BIOS V1.09 CRC=00000000 00005053 [1412DDDCFD2DC960DA7D282D99FC2356] GoodName=Z64 BIOS V1.10b CRC=00000000 00005053 [40E74DA10255DCF00A45F02BED1AFCAD] GoodName=Z64 BIOS V1.11 CRC=00000000 00005053 [E81062B36B08078CE4CFF5A362F44764] GoodName=Z64 BIOS V1.12 CRC=00000000 00005053 [FFAAAFB32A2D87C6B621B62FFC85A2D6] GoodName=Z64 BIOS V2.00 (Barebones) CRC=B038EEEB 00BA6901 [A1CDE773E4FB8B691098F2B3D5F2DBBA] GoodName=Z64 BIOS V2.00 CRC=00000000 00005053 [319377A6D811EF8AD7B3E16B537E6346] GoodName=Z64 BIOS V2.00b (Ravemax Hack) CRC=00000000 00005053 [72775AB85B5106A97DECB0520DFD9180] GoodName=Z64 BIOS V2.10NTSC CRC=00000000 00005053 [DB67B8D7251314163E4F713724F55C66] GoodName=Z64 BIOS V2.10PAL CRC=00000000 00005053 [B15D755B8C6A4B5933802E5F227A183C] GoodName=Z64 BIOS V2.11NTSC CRC=00000000 00005053 [0CC1A139F9C3865FE698C64209C45253] GoodName=Z64 BIOS V2.11PAL CRC=00000000 00005053 [E76F0536CDAD4C6F89802E15A98AE985] GoodName=Z64 BIOS V2.12NTSC CRC=00000000 00005053 [CC2433DFB7738D5CB71A75B054E52DD5] GoodName=Z64 BIOS V2.12PAL CRC=00000000 00005053 [07C468E5050FC619791437930D740B10] GoodName=Z64 BIOS V2.12b (Nintendo Backup Crew Hack) CRC=00000000 00005053 [0170C86E42E15A364CDC6E176A63A500] GoodName=Z64 BIOS V2.12b3 CRC=00000000 00005053 [D65B99356296CA8F6B3273540203E0AA] GoodName=Z64 BIOS V2.12b4 CRC=00000000 00005053 [B6D6EDA244C308E63D36EEC607942605] GoodName=Z64 BIOS V2.13 CRC=00000000 00005053 [A4B138CAEDCE038D93C5B1FEDD897E7D] GoodName=Z64 BIOS V2.15 CRC=00000000 00005053 [4F557C3F71C0D04A54776450913E027F] GoodName=Z64 BIOS V2.16 CRC=00000000 00005053 [8EEE06C88613B1265721B26517B64F2C] GoodName=Z64 BIOS V2.16b CRC=00000000 00005053 [B29240BC2FFA6C46B83023F2226E3CDE] GoodName=Z64 BIOS V2.17 [h1] CRC=00000000 00005053 [0658D69EBA236FDF6DA5D491BDC96574] GoodName=Z64 BIOS V2.17 by zmod.onestop.net (ORB HDisk ZIP250 2.18zd Hack) CRC=00000000 00005053 [568D51E1D4602CD74AC3A2D9719A390A] GoodName=Z64 BIOS V2.17 by zmod.onestop.net (ORB HDisk ZIP250 Hack) CRC=00000000 00005053 [1630A446857F28D3068907F302B02114] GoodName=Z64 BIOS V2.17 CRC=00000000 00005053 [7344708B7E0FC0683BBA86D902B9603D] GoodName=Zelda 64 Boot Emu V1 by Crazy Nation (PD) [a1] CRC=9A7A9F14 05137CC7 [015A3F07366CEF93B5CB38B386E659F4] GoodName=Zelda 64 Boot Emu V1 by Crazy Nation (PD) CRC=9A7A9F14 05137CC7 [E419774A7113F1B82F6621EA512F10CF] GoodName=Zelda 64 Boot Emu V2 by Crazy Nation (PD) [a1] CRC=60005D15 65727EFF [01E2C444385597DC4FCF09E45C522B01] GoodName=Zelda 64 Boot Emu V2 by Crazy Nation (PD) CRC=60005D15 65727EFF [692A33B0D7456FC733A81AB83C20382B] GoodName=Zool - Majou Tsukai Densetsu (J) [!] CRC=1C010CCD 22D3B7FA Players=1 Mempak=Yes [4F8E5341B89E6C2069A319EF2FB58B16] GoodName=Zool - Majou Tsukai Densetsu (J) [f1] (PAL) CRC=7711DBA7 4856F7E0 RefMD5=692A33B0D7456FC733A81AB83C20382B [1DDE4D26CEDB2E8565AACB2C8098DF8D] GoodName=Neon64 GS V1.05 (Gameshark Version) (PD) CRC=03D7F021 8FDE0000 [775E6D9305BF219C0696063C809F2B48] GoodName=Neon64 GS V1.1 (Gameshark Version) (PD) CRC=3C0A8030 354A4E78 [4C3F1B48E7252391B337D9BAE404CF83] GoodName=Neon64 GS V1.2 (Gameshark Version) (PD) CRC=3C0A8030 354A5198 [81A2C7E1EC426D3AEE1C4B823A2BC7BF] GoodName=Neon64 GS V1.2 (Pro Action Replay Version) (PD) CRC=3C0A802D 354A3458 [90FAF5461E5F5CD5B67CE7891B9B055B] GoodName=Neon64 GS V1.2a (Gameshark Version) (PD) CRC=3C0A8030 354A51B0 [B9A06A029A842207A9E17AA40A702F7B] GoodName=Neon64 GS V1.2a (Pro Action Replay Version) (PD) CRC=3C0A802D 354A3470 [9BE795563DBA802DD566DF75D6106CFC] GoodName=Z64 BIOS V2.18 CRC=00000000 00005053 [4B2DBC0D448B7AD8569291E4E44821F0] GoodName=N64probe by MooglyGuy (PD) CRC=B216B9F1 AB27D881 [D7CB11A82EDAEE3F519346C7EAE201E9] GoodName=ObjectVIEWER V1.1 by Kid Stardust (PD) CRC=34E42466 F50868AC [A1D23D8C7A3194DCD0AC0CA1AF79136E] GoodName=TheMuscularDemo by megahawks (PD) CRC=B0565CCB BDA2C237 [DBF04773EC2B8ADF8A94DB7E3E461138] GoodName=Mupen64Plus Demo by Marshallh (GPL) CRC=DDBA4DE5 B107004A Status=5 Players=0 SaveType=None [46C9461B0B6F232C5A50CA795395D706] GoodName=DS1 Manager V1.1 by R. Bubba Magillicutty (PD) [T+Ita] CRC=868214B8 AB2BE6B7 [02E344EC824BBA4A4CFFCAC5FEADEA51] GoodName=F-ZERO Expansion Kit (N64DD) CRC=2129FFF8 AD000000 [685B2F0DECB5BE33D25145E55F24A6D3] GoodName=F-Zero X Expansion Kit (J) [CART HACK] CRC=BBFDEC37 D93B9EC0 Players=1 Rumble=Yes [5932D07D6AAA84B7D74F5251D8942C91] GoodName=F-Zero X Expansion Kit (U) [CART HACK] CRC=C6E39C0A D2726676 Players=1 Rumble=Yes [8D3D9F294B6E174BC7B1D2FD1C727530] GoodName=N64DD IPLROM (J) CRC=00000000 00000000 [83807A5437A2EA21E2133DBA1E410750] GoodName=Wonder Project J2 - Koruro no Mori no Jozet (J) [T-Eng0.05] CRC=3A4B5938 A26F989D RefMD5=0FF1F8628D8FE69582DB54572D2BEA79 [E0530F182EA3BB780A6264B1D06737A1] GoodName=Z64 BIOS V2.20cf CRC=00000000 00005053 [D3929AADF7640F8C5B4CE8321AD4393A] GoodName=Zelda no Densetsu - Mujura no Kamen (J) (GC) [!] CRC=8473D0C1 23120666 SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [15D1A2217CAD61C39CFECBFFA0703E25] GoodName=Zelda no Densetsu - Mujura no Kamen (J) (V1.0) [!] CRC=EC417312 EB31DE5F SaveType=Flash RAM Status=4 Rumble=Yes Players=1 [3E60CA693BABFF1F62CF8C0AEC338556] GoodName=Zelda no Densetsu - Mujura no Kamen (J) (V1.0) [b1] CRC=EC417312 EB31DE5F RefMD5=15D1A2217CAD61C39CFECBFFA0703E25 [0F6D3EDB5797A775757336549A8A9B94] GoodName=Zelda no Densetsu - Mujura no Kamen (J) (V1.0) [b1][o1] CRC=EC417312 EB31DE5F RefMD5=15D1A2217CAD61C39CFECBFFA0703E25 [E0CED30BF10F05EBAF1F1A27563E3E5D] GoodName=Zelda no Densetsu - Mujura no Kamen (J) (V1.0) [f1] CRC=EE7AF9EC A750B2D3 RefMD5=15D1A2217CAD61C39CFECBFFA0703E25 [0FA23CD30B68EB86548630FE635BB90E] GoodName=Zelda no Densetsu - Mujura no Kamen (J) (V1.0) [o1] CRC=EC417312 EB31DE5F RefMD5=15D1A2217CAD61C39CFECBFFA0703E25 [C38A7F6F6B61862EA383A75CDF888279] GoodName=Zelda no Densetsu - Mujura no Kamen (J) (V1.1) [!] CRC=69AE0438 2C63F3F3 RefMD5=15D1A2217CAD61C39CFECBFFA0703E25 ; 64DD Games ; [8D3D9F294B6E174BC7B1D2FD1C727530] GoodName=64DD IPL (JPN) [37C36E4286D36892A9FC70EAFE4104BE] GoodName=64DD IPL (USA) [8485643E5830CD67ED4C0A5FD49E2491] GoodName=Mario Artist Paint Studio (J) [88228E990B58A94E9B3460BEFF632304] GoodName=Mario Artist Talent Studio (J) [114AF722029D6386C3BFEA4CC8FA603C] GoodName=Mario Artist Communication Kit (J) [DA23EE561578B7DAD77ED72728B46D30] GoodName=Mario Artist Polygon Studio (J) [EBBA03F20096FC2BC178FC3A1F4EC2B6] GoodName=Sim City 64 (J) [9F797A9C704B5EBD04D6A2B036309AF2] GoodName=Nihon Pro Golf Tour 64 (J) [E8EB810D996E12CD6C47445F87A94C72] GoodName=Kyojin no Doshin 1 (J) [AFE059AE1210751B6C849CFB482C99DD] GoodName=Kyojin no Doshin 1 (J) (Store Demo) [26087E0750FC6DA0F3DE2A431E34BDDF] GoodName=Randnet Disk (J) [Rev. 00] [33CBC59786063285DC3C090E0ED312E3] GoodName=Randnet Disk (J) [Rev. 01] [FCCA9AF8C1174C40B478EA0E02673B16] GoodName=Kyojin no Doshin - Kaihou Sensen Chibikkochikko Dai Shuugou (J) [CB2FB00C3921245AE04BB38BA01ABE92] GoodName=F-ZERO X Expansion Kit (J) [D9EA905727B44F2774926CB03C2300A7] GoodName=Super Mario 64 Disk Version (J) (Spaceworld 1996 Demo) [84706E10026BD2EE9654DA5E9821598D] GoodName=Dezaemon 3D Expansion Disk (J) (Proto) SaveType=SRAM [7BB3974754A54BA27A93F96691DC4695] GoodName=Dezaemon 3D Expansion Disk (J) (Proto) SaveType=SRAM [40AA8EC52C5E025D6C6AD94CEBC2218F] GoodName=Dezaemon 3D Expansion Disk (J) (Proto) SaveType=SRAM [C108A9B1EB024F0D2317C05976BA49F2] GoodName=Dezaemon 3D Expansion Disk (J) (Proto) [a1] SaveType=SRAM [4D02F5A719BD455F67721C64B16AE0CB] GoodName=Mario Artist Paint Studio (J) (1999-02-11 Proto) CountPerOp=1 [A76B619EC832A7E2ABCFBDFEB5375E39] GoodName=Mario Artist Paint Studio (J) (1999-02-11 Proto) CountPerOp=1 mupen64plus-core-src-2.6.0/data/mupencheat.txt000066400000000000000000046644641464506436200213010ustar00rootroot00000000000000///* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // * Mupen64plus - mupencheat.txt * // * Mupen64Plus homepage: https://mupen64plus.org/ * // * Copyright (C) 2008 Gent * // * * // * This program is free software; you can redistribute it and/or modify * // * it under the terms of the GNU General Public License as published by * // * the Free Software Foundation; either version 2 of the License, or * // * (at your option) any later version. * // * * // * This program is distributed in the hope that it will be useful, * // * but WITHOUT ANY WARRANTY; without even the implied warranty of * // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * // * GNU General Public License for more details. * // * * // * You should have received a copy of the GNU General Public License * // * along with this program; if not, write to the * // * Free Software Foundation, Inc., * // * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Used and relicensed GPL with permission from Gent // Start Original Header // PJ64 1.7 Official Cheats Database (Project64.cht) Beta Version 1.7.0.13 // All Region Cheat Codes By Gent. // ---------------------------------------------------- // // This Cheat file is only to be used with Project64 version 1.7 // // ---------------------------------------------------- // End Original Header // // This file was converted to a different format from the original PJ64 cheat format. // // [Meta] // Author=Gent // Version=Official Beta Version 1.7.0.13 // Date=30th April 2008 // Homepage=http://www.pj64.net //--------------- (J) Region Cheat Codes --------------- crc 80F41131-384645F6-C:4A gn AeroGauge (J) (V1.1) //---- cn No Damage\Player 1 50000402 0000 8113D058 0000 cn No Damage\Player 2 50000402 0000 8113F0E8 0000 cn Unlock All Tracks and Vehicles 8008D1FC 0001 cn Freeze All Lap Timers 8013CD21 0001 8013CD25 0001 8013CD29 0001 cn Freeze Overall Timer cd All of the Freeze All Lap Timers must be on. These codes will Stop the others from racing against you in Grand Prix mode. To win a race in Grand Prix you must finish at least one lap in the qualify round, then complete all laps in race for first. 8013CD15 0001 cn Laps Of Race 8013CD0E ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"Never Ending Laps" cn Play As\Player 1 8013D015 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Level Select cd For this cheat to work,as soon as you put the cheat on you must turn it back off,if not you wont beable to quit a Race or even finish one. 8013D01B ???? 0000:"Canyon Rush",0001:"Bikini Island",0002:"China Town",0003:"Neo Arena",0004:"China Town Jam",0005:"Neo Speed Way" cn Play As\Player 2 8013D016 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Always 1st 8013CD60 0001 cn Music Modifier 80106CCC ???? 00FF:"Music On",0000:"Music Off" crc B00903C9-3916C146-C:4A gn AeroGauge - Kiosk (J) (V1.0) cn No Damage\Player 1 50000402 0000 8113CF08 0000 cn No Damage\Player 2 50000402 0000 8113EF98 0000 cn Unlock All Tracks and Vehicles 8008D0AC 0001 cn Freeze All Lap Timers 8013CBD1 0001 8013CBD5 0001 8013CBD9 0001 cn Freeze Overall Timer cd All of the Freeze All Lap Timers must be on. These codes will Stop the others from racing against you in Grand Prix mode. To win a race in Grand Prix you must finish at least one lap in the qualify round, then complete all laps in race for first. 8013CBC5 0001 cn Laps Of Race 8013CBBE ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"Never Ending Laps" cn Play As\Player 1 8013CEC5 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Level Select cd For this cheat to work,as soon as you put the cheat on you must turn it back off,if not you wont beable to quit a Race or even finish one. 8013CECB ???? 0000:"Canyon Rush",0001:"Bikini Island",0002:"China Town",0003:"Neo Arena",0004:"China Town Jam",0005:"Neo Speed Way" cn Play As\Player 2 8013CEC6 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Always 1st 8013CC10 0001 cn Music Modifier 80106B7C ???? 00FF:"Music On",0000:"Music Off" crc B6951A94-63C849AF-C:4A gn Akumajou Dracula Mokushiroku - Real Action Adventure (J) cn Infinite\Health 81389C3E 0064 cn Infinite\Throwing Weapon 81389C48 0064 cn Throwing Weapon Modifier 81389C42 ???? 0000:"Nothing",0001:"Knives",0002:"Exploding Potions",0003:"Cross",0004:"Axes" cn Press L To Levitate D0387D7F 0020 81350810 3FCB cn Have\All Items 50000501 0000 80389C4A 0001 50000301 0000 80389C51 0001 80389C5A 0001 80389C5B 0001 80389C5D 0001 50000E01 0000 80389C60 0001 cn Have\Invincibility 80342BFE 000B cn Infinite\Red Jewels 80389C49 0063 cn Status 80389C88 ???? 0001:"Good",0008:"Vamp",0011:"Poison",0022:"Good but depressed",0066:"Sto",001F:"V+P" cn Open All Doors and Gates,No Bosses 50002A02 0000 81389BD0 FFFF cn Infinite\Energy 80389C3F 0064 cn Infinite\Funds 80389C45 0001 81389C46 869F cn Have\Exp Points 80389C49 0063 cn Max Power Up 80389CED 0002 cn Never Get Poisoned 81389C88 0000 cn Level Select cd You must use this code on a saved game, because the intro to the first level will mess up the game. Now select the saved game, and hold down the GS button until the level loads. Some of the boss stages will not let you fight the boss unless you re-enter the area. Also, with the part of stage modifier, the second code modifies the part of the level that you are in, and 0000 is the level's start. 89389C90 ???? 0000:"Forest of Silence",0002:"Castle Wall",0003:"Villa",0004:"Inside Villa",0006:"Garden Maze",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",0010:"Tower of Execution",0011:"- Tower of Sorcery",0012:"- Tower of Science",0013:"- Duel Tower",0014:"- Fight With Death/Actrise",0015:"- Castle Keep",0016:"- Intro (Glitch)",0017:"- Clock Tower",0018:"- Final Dracula",001A:"- Fight With Maze Boss",001B:"- Room of Clocks",001C:"- ??",001D:"- ??" 89389C92 0000 cn Switch From cd This Switch From Cheat lets you switch characters on a saved game For example, if you are Reindhart and you want to be Carrie in the middle of your game save it and then enable this Cheat and press F1. when you start your saved game back up you'll be Carrie instead of Reindhart. 80389C3D ???? 0000:"Carrie to Reindhart",0001:"Reindhart to Carrie" crc A5533106-B9F25E5B-C:4A gn Akumajou Dracula Mokushiroku Gaiden-Legend of Cornell (J) cn Infinite\Keys\Clocktower A 801CC51F 000A cn Infinite\Keys\Clocktower B 801CC520 000A cn Infinite\Keys\Storeroom 801CC510 000A cn Infinite\Keys\Garden 801CC511 000A cn Infinite\Keys\Copper 801CC512 000A cn Infinite\Keys\Chamber 801CC513 000A cn Infinite\Keys\Execution 801CC514 000A cn Infinite\Keys\Deck 801CC515 000A cn Infinite\Keys\Rose Garden 801CC516 000A cn Infinite\Keys\Thorn 801CC517 000A cn Infinite\Keys\Clocktower C 801CC518 000A cn Infinite\Keys\Clocktower D 801CC519 000A cn Infinite\Keys\Art Tower 1 801CC51A 000A cn Infinite\Keys\Art Tower 2 801CC51B 000A cn Infinite\Keys\Control Room 801CC51C 000A cn Infinite\Keys\Wall 801CC51D 000A cn Infinite\Keys\Clocktower E 801CC51E 000A cn Infinite\Keys\Archives 801CC50E 000A cn Infinite\Keys\Left Tower 801CC50F 000A cn Infinite\Health 811CC4EA 2710 cn Infinite\Gold 811CC4F2 2710 cn Infinite\Specials\Special 1 801CC4F7 000A cn Infinite\Specials\Special 2 801CC4F8 000A cn Infinite\Specials\Special 3 801CC4F9 000A cn Infinite\Items\Roast Chicken 801CC4FA 000A cn Infinite\Items\Roast Beef 801CC4FB 000A cn Infinite\Items\Healing Kit 801CC4FC 000A cn Infinite\Items\Purifying 801CC4FD 000A cn Infinite\Items\Cure Ampoule 801CC4FE 000A cn Infinite\Items\Powerup 801CC4FF 000A cn Infinite\Items\The Contract 801CC504 000A cn Infinite\Items\Magical Nitro 801CC505 000A cn Infinite\Items\Mandragora 801CC506 000A cn Infinite\Items\Sun Card 801CC507 000A cn Infinite\Items\Moon Card 801CC508 000A cn Infinite\Items\Winch Lever 801CC509 000A cn Infinite\Items\Oldrey's Diary 801CC50A 000A cn Infinite\Items\Crest Half A 801CC50B 000A cn Infinite\Items\Crest Half B 801CC50C 000A cn Infinite\Items\Rose Brooch 801CC50D 000A cn Infinite\Items\Throwing Weapons 801CC4F5 0064 cn Infinite\Items\Red Jewels on Pick-Up 801CC4F5 0068 cn Infinite\Bullets cd For Henry 801D5753 0006 cn Wolfman Can Use Weapons cd For Cornell 801CC4E7 0002 cn Wolfman Can't Use Weapons cd For Cornell (Default) 801CC4E7 0004 cn Rapid Fire Gun (Henry-Hold B) cd For Henry, Hold B D11CA1A6 0040 801D5753 0006 cn Max Powerups 801CC7D3 0002 cn Stop Timer Input 811CC4D2 0001 cn Hard Mode Selected In A New Game cd With this code, you will not see the hard level status until you save and restart the game file. No special items are required to access this feature with this code turned on. 8032630F 0002 cn Weapon Modifier 811CC4EE ???? 0000:"Nothing",0001:"Knife",0002:"Potion",0003:"Cross",0004:"Axe" cn Level Modifier 801CC829 ???? 0000:"Forest Of Silence",0001:"Left Tower",0002:"Castle Wall",0003:"Villa",0004:"Villa",0005:"Villa",0006:"Villa",001A:"Villa",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",000A:"Castle Center",000B:"Castle Center",000C:"Castle Center",000D:"Castle Center",000E:"Castle Center",000F:"Castle Center",0010:"Foggy Lake",0011:"Foggy Lake",0012:"Foggy Lake",0013:"Cave Of Spiderwomen",0014:"Castle Keep",0015:"Castle Keep",0016:"Falls Into Space(?)",0017:"Clock Tower",0018:"Final Battle Site",0019:"Castle Center",001B:"Room Of Clocks",001C:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",002B:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",001D:"Tower Of Sorcery",001E:"Tower Of Execution",001F:"Tower Of Execution",0020:"Tower Of Execution",0021:"Tower Of Science",0022:"Tower Of Science",0023:"Tower Of Ruins",0024:"Tower Of Ruins",0025:"Art Tower",0026:"Art Tower",0027:"Dual Tower",0028:"Clock Tower",0029:"Clock Tower",002A:"Outer Wall",002C:"Fall From Sky Ouside Of Castlevania Opening",002D:"Another Free Fall. Forest Where Girl Runs In Opening",002E:"Black Room(?)" cn Inter-Level Modifier 801CC82B ???? 0000:"Forest Of Silence",0001:"Left Tower",0002:"Castle Wall",0003:"Villa",0004:"Villa",0005:"Villa",0006:"Villa",001A:"Villa",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",000A:"Castle Center",000B:"Castle Center",000C:"Castle Center",000D:"Castle Center",000E:"Castle Center",000F:"Castle Center",0010:"Foggy Lake",0011:"Foggy Lake",0012:"Foggy Lake",0013:"Cave Of Spiderwomen",0014:"Castle Keep",0015:"Castle Keep",0016:"Falls Into Space(?)",0017:"Clock Tower",0018:"Final Battle Site",0019:"Castle Center",001B:"Room Of Clocks",001C:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",002B:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",001D:"Tower Of Sorcery",001E:"Tower Of Execution",001F:"Tower Of Execution",0020:"Tower Of Execution",0021:"Tower Of Science",0022:"Tower Of Science",0023:"Tower Of Ruins",0024:"Tower Of Ruins",0025:"Art Tower",0026:"Art Tower",0027:"Dual Tower",0028:"Clock Tower",0029:"Clock Tower",002A:"Outer Wall",002C:"Fall From Sky Ouside Of Castlevania Opening",002D:"Another Free Fall. Forest Where Girl Runs In Opening",002E:"Black Room(?)" cn Cut Scene Modifier cd With this code, you must use the appropiate level mod before you attemp to run these cut scenes. Not doing so will ruin the cut scene as the graphics will be glitched. 801CC843 0009 801CC83B ???? 0003:"Castle Drawbridge Lowers",0004:"Character Enters Castle",0005:"(?)",000A:"(?)",000C:"(?)",0020:"(?)",0021:"(?)",0022:"(?)",0006:"Vampire In Main Entrance Hall Of Villa",0007:"One Of The Working Gears Cut Scenes",0008:"\"I Smell Poison\" From Underground Waterway",0009:"Castle Gate Closes In Villa Upon Entering Villa",000B:"Renon Appears For First Time",000D:"Village Vampire In Upstairs Villa",000E:"Malus Appears For The First Time",000F:"Malus Leaves Garden",0010:"Character In Boat On Foggy Lake",0011:"Seal Removed From Wall In Arena",0012:"Bleeding Statue",0013:"Cosmic Lights",0014:"Explosion At Wall In Arena",0015:"Explosion At Wall In Castle That Leads To Hidden Room",0016:"Malus Appears Again In Upstairs Room Of Castle",0017:"Bull Awakens",0018:"Vincent The Vampire",0019:"One Of The Working Gears Cut Scenes",001A:"Gate Opens In Forest Of Silence",001B:"Meet Renon For The Last Time In Castle Keep.",001C:"This Cut Scene Runs Cut Scene 27 And 2E",001E:"Castle Keep Destructs",001F:"Malus On Flying Horse Outside Castle Keep",0024:"Spider People In Tunnel",0025:"Rosa In Garden",0027:"Castel Destruction",0028:"Space Warp",0029:"Castle Destruction",002A:"Malus Is Saved By Reinhardt",002B:"Malus And Reinhardt On Horse",002E:"Rosa Returns",0030:"Ada, Henry And Cornell At Game End",0031:"Scrolling Text About Castle And Henry",0033:"Vampire In Basement",0034:"Vampire In Villa Basement Destroyed, Woman Vampire Rises",0035:"Finds Hidden Path In Villa Basement",0037:"Lever & Gear In Castle",0038:"Harpie",0039:"Harpie Destroyed",0044:"Death(Grim Reaper)",0045:"Death Is Destroyed",0046:"Castle Drawbridge Closes And Ortega Appears",0047:"Thirsty Man",0048:"Cornell Meets Henry In Garden",0049:"Cornell And Henry Part In Garden",0051:"Monster Dracula Appears",0052:"Actrise Appears In Castle Center",0054:"Actrise Appears Again With Cousin Fernandes Before Fight With Carrie",0055:"Cousin Fernandes Is Destroyed",0056:"Actrise Appears Again Before Fight With Carrie",0057:"Actrise Defeated By Carrie" cn Enable All Characters 8031CBF3 0004 cn Character Modifier 8031CBDB ???? 0005:"Henry",0006:"Reinhardt",0007:"Carrie" cn Status Modifier 801CC534 ???? 0000:"Never Get Poisoned or Vamped",0001:"Normal",0004:"Vamp",0008:"Poison",000C:"Vamped & Poisoned",00FF:"Instant Death" cn Max Weapon Power-Up 801CC7D7 0002 cn Day Modifier For Adult Henry 801CC4CF ???? 0000:"7 Days",0001:"6 Days",0002:"5 Days",0003:"4 Days",0004:"3 Days",0005:"2 Days",0006:"1 Day",0007:"0 Days" cn Infinite\Health Young Henry D11CA1A6 0010 813A6D10 2800 crc 6C45B60C-DCE50E30-C:4A gn Airboarder 64 (J) cn Infinite Turbo\Player 1 80166019 0009 cn Infinite Turbo\Player2 80167991 0009 cn Infinite Time\Street Work & Coin 801137E9 0028 cn Infinite Time\Attack Time Time 000000 811137EA 0000 cn Infinite Time\Time Attack 801137EB 0000 cn Access All Boards & Characters 800500C1 000C cn Maxed Out Turbo Bar 811656E8 429F 80166017 0051 cn Class Score Select 8016609E ???? 0020:"Class C",0040:"Class B",0064:"Class A",00FF:"Class S" cn Coin Perfect Select cd this is for Coin Mode to get Perfect Coin Collection Score straight away when you enter the level 801660B3 ???? 0014:"Green Park Level 1",001A:"Green park Level 2",002B:"Green park Level 3",004A:"Lost Forest Level 1",0059:"Lost Forest Level 2",0080:"Lost Forest Level 3",007D:"Snow Festival 64 Levels 1 2 & 3",006F:"Sunset Island Level 1",0074:"Sunset Island Level 2",0081:"Sunset Island Level 3",006E:"Giant House Level 1",0077:"Giant House Level 2",0072:"Giant House Level 3" cn Options\Music Modifier 800500A9 ???? 00FF:"BGM On",0000:"BGM Off" cn Options\Sound Effects Modifier 810500AA ???? 00FF:"SE On",0000:"SE Off" cn Options\Camera Type Modifier 810500A6 ???? 0000:"Roll On Near",0001:"Roll On Mid",0002:"Roll On Far",0003:"Roll Off Near",0004:"Roll Off Mid",0005:"Roll Off Far" cn Options\DJ Function Modifier 810500AC ???? 0001:"DJ Function On",0000:"DJ Function Off" cn All Street Work Levels Unlocked 50007801 0000 80050170 ???? 0001:"Courses unlocked",0003:"Courses unlocked with C rank",0004:"Courses unlocked with B rank",0005:"Courses unlocked with A rank",0006:"Courses unlocked with S rank" crc E340A49C-74318D41-C:4A gn Baku Bomberman (J) cn Invincible\Player 1 800AEE01 0001 cn Have\Pumped up Red Remote Bombs 802AC653 0004 cn Infinite\Lives 802AB857 0063 cn Infinite\Gems 802AB85F 0063 cn Infinite\Credits 802AB85B 0009 cn Infinite\Time 802AB873 0001 cn Carry 20 Bombs At A Time 800AEE0F 0014 cn Infinite\Energy\Player 1 800AEE07 0002 cn Infinite\Energy\Player 2 800AEECF 0002 cn Infinite\Energy\Player 3 800AEF97 0002 cn Infinite\Energy\Player 4 800AF05F 0002 crc E73C7C4F-AF93B838-C:4A gn Baku Bomberman 2 (J) cn Infinite\Money 810A9BB2 FFFF cn Infinite\Bombs 800AB5B8 0003 cn Have\Max Fire Level 800AB593 0003 cn Infinite\Health 800AB5BF 0005 cn Infinite\Continue Time 810B3B36 0090 cn Have\Fire Bombs 800AB59B 0003 cn Have\Kick Bombs Anytime 800AB5A3 0003 cn Flashing Invincible cd This cheat Makes you Flash But you cant be harmed,Once out of danger Turn the cheat off to stop the flashing.also do not put this on if you have already been hurt or you will stay on the floor. 800AB5C7 000A crc 5168D520-CA5FCD0D-C:4A gn Banjo to Kazooie no Dai Bouken (J) cn Infinite\Eggs 80386AA7 00FF cn Infinite\Lives 80386ACB 00FF cn Infinite\Jiggies 80386B0B 00FF cn Infinite\Notes cd Just collect one Note to Have 255 Notes in all Worlds. 80386B32 00FF 80386AA2 0001 cn Infinite\Health 80386AC3 0008 80386AC7 0008 cn Infinite\Air 81386ACE 0E10 cn Infinite\Gold Feathers 80386AB3 00FF cn Infinite\Red Feathers 80386AAF 00FF cn Infinite\Always Have All Jinjos 80386ABB 00FF cn Have Zero Time all Levels 50000B04 0000 81386B44 3000 cn Infinite\Mumbo Tokens 80386B07 00FF crc 514B6900-B4B19881-C:4A gn Banjo to Kazooie no Dai Bouken 2 (J) cn Infinite\Energy\Banjo and Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 81115A04 0A0A cn Infinite\Air 80125222 42C8 cn Infinite\Energy\Snowball cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 80115907 0005 cn Infinite\Energy\Bee cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 80115913 000A 80115914 000A cn Infinite\Energy\Washing Machine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 81115916 0A0A cn Infinite\Energy\Stony cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 80115919 000A 8011591A 000A cn Infinite\Energy\Banjo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 8011591F 000A 80115920 000A cn Infinite\Energy\Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 81115922 0A0A cn Infinite\Energy\Submarine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 80115925 000A 80115926 000A cn Infinite\Energy\Mumbo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 81115928 0A0A cn Infinite\Energy\Detonator cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 8111592E 0A0A cn Infinite\Energy\T-Rex Baby cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 80115329 0063 8011593F 000A 80115940 000A cn Play As cd To use this cheat, put the cheat on, then press L as you walk through a door to become that chosen character D0080845 0020 801211FC ???? 0001:"Banjo and Kazooie",0002:"Snowball",0006:"Bee",0007:"Washing machine",0008:"Stony",000A:"Banjo",000B:"Kazooie",000C:"Submarine",000D:"Mumbo",000E:"Golden Goliath",000F:"Detonator",0010:"Truck",0012:"T-rex baby",0013:"T-rex daddy" cn Instant Warp\Options\Spiral Mountain cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0000:"AD Grunty's Old Lair",0000:"AE Behind The Waterfall",0000:"AF Top Of Castle",0001:"73 Banjo's house" 801217F3 0001 cn Instant Warp\Options\Jinjo Village cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0001:"42 Jinjo Village",0001:"44 King Jingalings throne room",0001:"43 Bottles house",0001:"45 Green Jinjo's House",0001:"46 Black Jinjo's House",0001:"47 Yellow Jinjo's House",0001:"48 Blue Jinjo's House",0001:"4A Brown Jinjo's House",0001:"4B Orange Jinjo's House",0001:"4C Purple Jinjo's House",0001:"4D Red Jinjo's House",0001:"4E White Jinjo's House" 801217F3 0001 cn Instant Warp\Options\Mayahem Temple cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0000:"B6 Humba's Wigwam",0000:"B7 Mumbo's skull",0000:"B8 The Temple",0000:"B9 Prison Compound",0000:"BC Code chamber",0000:"C4 Jade Snake Grove",0000:"C5 Treasure Chamber",0000:"C6 Kickball Arena",0001:"77 Targitzan's Slighty Sacred Temple",0001:"78 Inside Targitzans Temple",0001:"79 Targitzan Temple Lobby",0001:"7A Targitzan's Temple Boss",0001:"7F Mayan Kickball Arena",0001:"66 Multi",0001:"67 Still",0000:"C8 Kickball Arena",0000:"C9 Kickball Arena" 801217F3 0001 cn Instant Warp\Options\Glitter Gulch Mine cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0000:"C7 Mine",0000:"CA Fuel depot",0000:"CB Crushing shed",0000:"CC Flooded caves",0000:"CD Water storage",0000:"CE Waterfall cavern",0000:"CF Power hut basement",0000:"D0 Chuffy's cab",0000:"D1 Inside chuffy's boiler boss",0000:"D2 Gloomy caverns",0000:"D3 Generator caverns",0000:"D4 Power hut",0000:"D5 Wumba's wigwam",0000:"D7 Train station",0000:"D8 Prospectors hut",0000:"D9 Mumbo's hut",0000:"DA Toxic gas cave",0000:"DB Canary cave",0000:"DC Ordnance storage",0000:"E9 Humba",0001:"26 Water supply pipe",0001:"63 Ordnance Storage entrance",0001:"64 Ordnance Storage game",0001:"65 Ordnance Storage game Multi",0001:"6F Testing",0001:"70 Testing",0001:"71 Mumbo's skull" 801217F3 0001 cn Instant Warp\Options\Witchy World cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0000:"D6 Witcy World",0000:"DD Dodgem dome lobby",0000:"DE Dodgem challenge \"1 vs 1\"",0000:"DF Dodgem challenge \"2 vs 1\"",0000:"E0 Dodgem challenge \"3 vs 1\"",0000:"E1 Crazy castle stockade",0000:"E2 Crazy castle lobby",0000:"E3 Crazy castle pump room",0000:"E4 Balloon burst game",0000:"E5 Hoop hurry game",0000:"E6 Star spinner",0000:"E7 The inferno",0000:"EA Cave of horrors",0000:"EB Haunted cavern",0000:"EC Train station",0001:"24 Saucer of Peril",0001:"3B Crazy castle stockade \"sop\"",0001:"3C Star spinner \"sop\"",0001:"76 Mumbo's skull" 801217F3 0001 cn Instant Warp\Options\Jolly Roger's Lagoon cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0000:"ED Jolly's",0000:"EE Pawno's emporium",0000:"EF mumbo's skull",0000:"F4 Ancient Swimming Baths",0000:"F6 Electric Eels lair",0000:"F7 Seaweed Sanctum",0000:"F8 Inside the big fish",0000:"FA temple of the fishes",0001:"A8 Atlantis",0001:"A9 Seabottom",0001:"81 sea bottom cavern",0001:"82 submarine multi",0001:"A7 Jolly Roger's Lagoon",0000:"FF Blubber's wave race hire" 801217F3 0001 cn Instant Warp\Options\Terrydacty Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0001:"12 Terrydacty Land",0001:"13 Terry's nest",0001:"14 Train station",0001:"15 Oogle boogles cave",0001:"16 Inside the mountain",0001:"17 River passage",0001:"18 Styracosaurus family cave",0001:"19 Unga bunga's cave",0001:"1A Stomping plains",0001:"1B Bonfire caverns",0001:"1E Humba's Wigwam",0001:"23 Inside chompa's belly",0001:"83 Chompa's belly multi" 801217F3 0001 cn Instant Warp\Options\Grunty Industries cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0001:"00 Outside",0001:"01 Inside",0001:"02 Train station",0001:"03 Workers quarters",0001:"04 Trash compactor",0001:"05 Elevator shaft",0001:"06 Floor 2",0001:"07 Floor 2 \"electromagnet chamber\"",0001:"08 Floor 3",0001:"09 Floor 3 \"boiler plant\"",0001:"0A Floor 3 \"packing room\"",0001:"0B Floor 4",0001:"0C Floor 4 \"cable room\"",0001:"0D Floor 4 \"quality control\"",0001:"0E Floor 5",0001:"0F Basement",0001:"10 Basement \"repair depot",0001:"11 Basement \"waste disposal\"",0001:"25 Water supply pipe",0001:"72 Mumbo's skull",0001:"62 Floor 4 \"clinkers cavern\"",0001:"87 Sewer entrance" 801217F3 0001 cn Instant Warp\Options\Hailfire Peaks cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0001:"27 Lava side",0001:"28 Icy side",0001:"29 Lava train station",0001:"2A Ice train station",0001:"2B Chilli billi",0001:"2C Chilly willy",0001:"2D Colosseum kickball stadium lobby",0001:"31 Boggy's igloo",0001:"32 Icicle grotto",0001:"33 Inside the volcano",0001:"68 Icy side still" 801217F3 0001 cn Instant Warp\Options\Cloud Cuckoo Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0001:"36 Cloud Cuckoo Land 1",0001:"37 Inside the trashcan",0001:"38 Inside the cheesewedge",0001:"39 Zubba's nest",0001:"3A Central cavern",0001:"3D Inside the pot o gold",0001:"3E Mumbo's skull",0001:"3F Mingy jongo's skull",0001:"40 Humba wumba's wigwam",0001:"61 Cloud Cuckoo Land 2",0001:"88 Zubba's nest multi",0001:"85 Trash can mini" 801217F3 0001 cn Instant Warp\Options\Isle O Hags cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0001:"4F Wooded Hollow",0001:"50 Heggy's egg shed",0001:"51 Jiggywiggy's temple",0001:"52 Plateau",0001:"53 Plateau \"Honey B's Hive\"",0001:"54 Pine Grove",0001:"55 Cliff top",0001:"56 Cliff top Mumbo's skull",0001:"5A wasteland",0001:"5B inside another digger tunnel",0001:"5C Quagmire" 801217F3 0001 cn Instant Warp\Options\Cauldron Keep cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0001:"5D Cauldron Keep",0001:"5E The gatehouse",0001:"5F Tower of Tragedy Quiz",0001:"60 Gun chamber",0001:"6A Gun room still",0001:"7B Crazy Castle Stockade balloon burst multi",0001:"7C Crazy Castle Stockade Jump the hoops multi",0001:"7D Grunty Industries packing game",0001:"80 Colosseum kickball arena",0001:"86 Dodgems" 801217F3 0001 cn Instant Warp\Options\Not sure cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D1080844 0000 811217F0 ???? 0000:"FC Lord woo fak fak",0000:"F9 Mr Patch",0001:"21 Inside Chuffy's wagon",0001:"34 Mumbo's Skull",0001:"35 Humba Wumba's wigwam 1",0001:"57 Humba Wumba's wigwam 2",0001:"9B Jingalings Zombified Palace",0001:"A6 Smuggler cavern",0001:"41 Inside the digger tunnel",0001:"43 Bottles house",0001:"69 Bottles house still",0001:"8A HAG Inside",0001:"9A HAG1 Final Boss" 801217F3 0001 cn Beta Bottles Revenge Mode cd Bottles Revenge is a Beta mode from Banjo Tooie that the RWP team recently uncovered after an extraordinary amount of effort. Bottles the Spirit transforms into Bottles the Devil and posses enemies nearby and allows a second player hooked up to Pad 2 to play as that Posses character to try to foil Banjos Plans. As player one goes about its business, player two uses every enemy nearby to try to nab Banjo and take away some life. This mode is incredible, and you can control almost every enemy in the game: slot machines, flying creatures, uggers, zubbas...and this is just the beginning. (Congrats Rare Witch Project) 801255C2 0001 80080881 0002 crc 91691C3D-F4AC5B4D-C:4A gn Transformers - Beast Wars Metals 64 (J) cn Infinite\Health\Player 1 8112A576 270F cn Infinite\Stun Meter\Player 1 8012A579 00FF cn Infinite\Health\Player 2 8114AAF6 270F cn Infinite\Stun Meter\Player 2 8014AAF9 00FF cn Play As\Player 1 801BBA54 ???? 0000:"Optimus Primal",0001:"Rattrap",0002:"Cheetor",0003:"Airazor",0004:"Megatron",0005:"Tarantulas",0006:"Waspinator",0007:"Terrorsaur" cn Play As\Player 2 801BBA55 ???? 0000:"Optimus Primal",0001:"Rattrap",0002:"Cheetor",0003:"Airazor",0004:"Megatron",0005:"Tarantulas",0006:"Waspinator",0007:"Terrorsaur" crc 65234451-EBD3346F-C:4A gn Blast Dozer (J) cn Infinite\Hydraulics Sidesweeper 803EDCE1 0063 cn Infinite\Missiles Motor Bike 803F8C53 0063 cn Infinite\Boosts Buggy Vehicle 803EE491 0064 cn Sideswipe\Can Go In Water 803EDCE2 0063 cn Sidesweep\Can Go Through Anything 803EDCE2 FFFF cn J-Bomb Floats Through Anything 803F7C5A 0001 cn Rapid Fire\Ballista 803F8C5D 0000 cn Rapid Fire\Sideswipe 803EDCE6 0000 cn Drive Through Anything\Ballista 803F8BF8 0001 cn Drive Through Anything\Dump Truck 813EEBE8 0101 cn Drive Through Anything\Red, White, & Blue Car 813EEFC8 0101 cn Drive Through Anything\Skyfall 813EE438 0101 cn Drive Through Anything\Police Car 813F8FD8 0101 cn Drive Through Anything\Red Car 813FC658 0101 cn Drive Through Anything\Van 813F93A8 0101 crc DF6FF0F4-29D14238-C:4A gn Bomberman 64 - Arcade Edition (J) cn Have\Max Fire 8024A39E 00FF cn Have\Max Bombs 8024A39F 00FF cn Bomb Select 8024A3A1 ???? 0002:"Power Bomb",0003:"Jelly Bomb",0004:"Shock Wave Bomb",0005:"Blue Remote Bomb",0006:"Red Beem Bomb",0007:"Invisible Mine Bomb",001D:"Crazy Bomb",0000:"Clear All Special Bombs." cn Walk through\Blocks cd Walk through Blocks like they are not there.Turn cheat to off to go back to normal. 8024A3A5 ???? 0000:"Off",0001:"On" cn Bomberman Speed 8024A3A0 ???? 0004:"Slow",0008:"Normal",000E:"Fast",0010:"Turbo" cn Have\Infinite\Kick 8024A3A6 0002 cn Invincible cd Enemies & Bomb Blasts cant harm you.But if you walk & keep laying Bombs it will most likly freeze.so try to avoid constant bombing while walking.Turn cheat to off to go back to normal. 8024A3A8 ???? 0000:"Off",0001:"On" cn Walk through\Bombs cd Walk through Bombs like they are not there.Turn cheat to off to go back to normal. 8024A3A6 ???? 0000:"Off",0001:"On" cn Infinite\Health Hearts 8024A3AE 00FF cn Infinite\Lives 802E1CE7 00FF cn Infinite\Timer 800FDD72 002A crc 67FF12CC-76BF0212-C:4A gn Bomberman Hero (J) cn Full\Bomb Power 80165239 0003 cn Full\Fire Power 8016523A 0003 cn Infinite\Health 8016523E 0004 cn Infinite\Lives 8016523D 0009 cn Extra Gems D016523B 0000 8016523B 004B cn Max\Bombs 80165239 0008 cn Press L to Levitate cd Press L to levitate & let go to come back down D005A2F5 0020 81154178 41CB D005A2F5 0020 D0154154 0000 80154154 0040 cn Max\Score 80177601 00FF 80177602 00FF cn Max\Explosion 8016523A 0008 crc D7C762B6-F83D9642-C:4A gn Buck Bumble (J) cn Have All\Guns & Infinite Ammo cd Press C Left to receive all Guns 81101DFA 0001 50000B04 0000 810EB156 03E7 cn Infinite\Health cd If you fall into Water just turn off the Infinite Health & put back on after. 810EB148 42D8 cn Infinite\99 Lives 810EB4C0 0005 cn Have All\Keys 810EB150 0101 800EB152 0001 cn Max Bonus 810EB4BA 270F crc A4F2F521-F0EB168E-C:4A gn Chameleon Twist (J) cn Extra Crowns 8024790B 0015 cn Infinite Health 80168E73 000A cn Extended Tongue 8132790E FFFF cn Level Select cd When you press Pause in-game and Stage Quit yo will go to the Stage Screen this cheat lets you choose what Stage you would like to go to but make sure you turn the cheat off and press A to continue to that stage. 8029BF7B ???? 0000:"Stage 1",0001:"Stage 2",0002:"Stage 3",0003:"Stage 4",0004:"Stage 5",0005:"Stage 6",0006:"Stage 7" crc 0549765A-93B9D042-C:4A gn Chameleon Twist 2 (J) cn Infinite Health 80187BBD 000F cn Max Collectable Items 80160641 0014 cn Have 6 Carrots 80160659 007E cn Have All\Levels 80160648 003F cn Have All\Costumes 8016065A 00FE cn Have All\Collectibles\Stage 1 80160650 0014 cn Have All\Collectibles\Stage 2 80160651 0014 cn Have All\Collectibles\Stage 3 80160652 0014 cn Have All\Collectibles\Stage 4 80160653 0014 cn Have All\Collectibles\Stage 5 80160654 0014 cn Have All\Collectibles\Stage 6 80160655 0014 cn Press L To levitate cd Press L To Levitate & Let go to land D0187BF5 0020 81187B20 4200 crc 2BCCF9C4-403D9F6F-C:4A gn Choro Q 64 (J) cn Super Speed cd This is Turbo fast,So to slow it down a little more keep the B button pressed down 81213568 4800 cn Always 1st 802133B6 0001 cn Class Select cd This code is useful because you can play Class AA without having to beat a level! 80206857 ???? 0000:"Class C",0001:"Class B",0003:"Class AA",0004:"1 Play",0005:"2 Play",0006:"3 Play",0007:"4 Play" crc 079501B9-AB0232AB-C:4A cn All Stuff Available For Player 1 cd This modifies your save file. That will make all the multiplayer stages available, as well as unlocking every part. The actual breakdown is: 50003802 0000 810F4230 FFFF cn All Equipment Unlocked 50001402 0000 810F40B0 FFFF cn All Equipment Registered 50001402 0000 810F40D8 FFFF cn All Equipment Unhighlighted 50001402 0000 810F4100 FFFF cn All Help Notes Available For Player 1 50000602 0000 810F409C FFFF cn Side Invincible\Player 1 811FC00C 447A cn Side Invincible\Player 2 811FC034 447A crc 7188F445-84410A68-C:4A gn Dance Dance Revolution - Disney Dancing Museum cn Maximum Song Score\Player 1 8108A260 3B9A 8108A262 C9FF cn Maximum Song Score\Player 2 8108A264 3B9A 8108A266 C9FF cn Maximum Total Score\Player 1 810854E0 3B9A 810854E2 C9FF cn Maximum Total Score\Player 2 81085518 3B9A 8101551A C9FF cn Maximum Dance Gauge\Player 1 810854DC 03E8 cn Maximum Dance Gauge\Player 2 81085514 03E8 cn Unlock All Songs 8015621D 00FF 8115621E FFFF cn Unlock All Puzzles 50001902 0000 81156228 FFFF cn Can Skip End Credits 8015627F 0001 cn Endless Mode 800854CD 0000 cn Results\999 Perfect Steps\Player 1 8108A21E 03E7 cn Results\999 Perfect Steps\Player 2 8108A236 03E7 cn Results\999 Great Steps\Player 1 8108A222 03E7 cn Results\999 Great Steps\Player 2 8108A23A 03E7 cn Results\0 Good Steps\Player 1 8108A226 0000 cn Results\0 Good Steps\Player 2 8108A23E 0000 cn Results\0 Boo Steps\Player 1 8108A22A 0000 cn Results\0 Boo Steps\Player 2 8108A242 0000 cn Results\0 Miss Steps\Player 1 8108A22E 0000 cn Results\0 Miss Steps\Player 2 8108A246 0000 crc 8979169C-F189F6A0-C:4A gn Dezaemon 3D (J) cn Infinite\99 Lives 8023648D 0063 cn Unlock Ramsie Mini-Game 801FF43E 0001 cn Max Score 80249F91 00FF cn Infinite\Speed 8024B6BC ???? 0000:"Normal",0001:"Slow",0002:"Medium",0003:"Fast",0007:"Warp Drive" cn Infinite\Stream Laser 80236CD0 ???? 0000:"2 Stream Laser",0001:"4 Stream Laser",0002:"6 Stream Laser" cn Infinite\Shield 80250971 ???? 0001:"On",0000:"Off" cn Infinite\99 R Button Bombs 8024BD89 0063 crc 7AA65B36-FDCEE5AD-C:4A gn Doom 64 (J) cn Always Have\Gun 80063B33 0001 cn Always Have\Shotgun 80063B37 0001 cn Always Have\Double Shotgun 80063B3B 0001 cn Always Have\Chain Gun 80063B3F 0001 cn Always Have\Missile Launcher 80063B43 0001 cn Always Have\Chainsaw 80063B2B 0001 cn Always Have\Plasma Rifle 80063B47 0001 cn Always Have\BFG 9000 80063B4B 0001 cn Always Have\Have Rocket Launcher 80063B41 0001 cn Always Have\Laser Weapon 80063B4D 0001 cn Always Have\Bio Suite 80063AF3 ???? 00FF:"On",0000:"Off" cn Infinite\Armor 80063ADF 00FF cn Always Have\Rapid Fire 81063BAA 0B94 cn Invincible 80063B7B 0002 cn Turn Map Markers On 80063B7B 0004 cn Invincible And Map Markers 80063B7B 0006 cn Berserk Mode 80063AEB 00FF cn [Max Brightness] cd Enable this cheat on rom load to have Max Brightness (internal) and then put Jabo d3d8 on 160% Max for a extra brightness Boost. 8005B598 0064 cn Have All\Weapons 50000A04 0000 81063B2A 0001 cn Infinite\Ammo All Weapons 50000404 0000 81063B52 013C cn Have All\Keys 50000504 0000 81063AFE FFFF cn Enable Cheat Menu 8005B043 0001 crc BFF7B1C2-AEBF148E-C:4A gn Doraemon - Mittsu no Seireiseki (J) cn Infinite\Lives 800F38C5 000A cn Infinite\Energy 800FB897 00FF cn Infinite\Bells 800F38C3 ???? 0063:"99 Bells",0000:"No Bells" crc BD8E206D-98C35E1C-C:4A gn Dobutsu no Mori (J) cn Hours 80136FBE ???? 0000:"00 AM",0001:"01 AM",0002:"02 AM",0003:"03 AM",0004:"04 AM",0005:"05 AM",0006:"06 AM",0007:"07 AM",0008:"08 AM",0009:"09 AM",000A:"10 AM",000B:"11 AM",000C:"00 PM",000D:"01 PM",000E:"02 PM",000F:"03 PM",0010:"04 PM",0011:"05 PM",0012:"06 PM",0013:"07 PM",0014:"08 PM",0015:"09 PM",0016:"10 PM",0017:"11 PM" cn Minutes 80136FBD ???? 0000:"00",0005:"05",000A:"10",000F:"15",0014:"20",0019:"25",001E:"30",0023:"35",0028:"40",002D:"45",0032:"50",0037:"55",003B:"59" cn Day 80136FBF ???? 0001:"Monday 1st",0002:"Tuesday 2nd",0003:"Wednesday 3rd",0004:"Thursday 4th",0005:"Friday 5th",0006:"Saturday 6th",0007:"Sunday 7th",0008:"Monday 8th",0009:"Tuesday 9th",000A:"Wednesday 10th",000B:"Thursday 11th",000C:"Friday 12th",000D:"Saturday 13th",000E:"Sunday 14th",000F:"Monday 15th",0010:"Tuesday 16th",0011:"Wednesday 17th",0012:"Thursday 18th",0013:"Friday 19th",0014:"Saturday 30th",0015:"Sunday 21st",0016:"Monday 22nd",0017:"Tuesday 23rd",0018:"Wednesday 24th",0019:"Thursday 25th",001A:"Friday 26th",001B:"Saturday 27th",001C:"Sunday 28th",001D:"Monday 29th",001E:"Tuesday 30th",001F:"Wednesday 31st" cn Month 80136FC1 ???? 0001:"Jan",0002:"Feb",0003:"March",0004:"April",0005:"May",0006:"June",0007:"July",0008:"Aug",0009:"Sept",000A:"Oct",000B:"Nov",000C:"Dec" cn Time Passes 80136FD2 ???? 0000:"Time Normal",0001:"Mins Like Seconds",0005:"Hours & Mins Medium",0010:"Hours & Mins Fast",00FF:"Time Zooms By" cn Max Cash 813BC34C FFFF cn Item Select 81126EE8 ???? 1011:"Tall Red Cupboard",1C00:"Pet Cage",1CA6:"Fish Tank (Fish Included!)",1D2B:"Orange NES Game",1D2F:"Grey NES Game",1D33:"Red NES Game",1D37:"Light Blue NES Game",1D3A:"Yellow NES Game",1D3E:"Purple NES Game",1D42:"Blue NES Game",1D47:"Stereo NES Colour",1D4C:"Record Player",1D50:"JukeBox",1DA0:"Grandfather Clock",1DA6:"Stereo Kinda Thing",1DA9:"Stereo",1DAC:"CD Player",1DB3:"Alarm Clock",1EA1:"Lamp",1EA5:"Snowman Fridge",1EAB:"Round Snowman Table",1EAF:"Snowman Bed",1EB0:"Snowman Seat",2100:"1000 Bag",2100:"1000 Bag",2101:"10000 Bag",2101:"10000 Bag",2102:"30000 Bag",2102:"30000 Bag",2103:"100 Bag",2103:"100 Bag",2410:"Nook's Shirt",2410:"Nook's Shirt",2514:"Flat Shell",2514:"Flat Shell",2515:"Pointy Shell",2515:"Pointy Shell",2804:"Orange,2804 Orange" crc 056EAB63-C215FCD5-C:4A gn Dual Heroes (J) cn Infinite\Energy\Player 1 81224DC4 00FF cn Infinite\Energy\Player 2 81224DC6 00FF cn Infinite\Time 81224DCC 00FF cn Never Wins\Player 1 80224DB5 0000 cn Never Wins\Player 2 80224DB7 0000 crc E13AE2DC-4FB65CE8-C:4A gn Eltale Monsters (J) cn Have All Elements 8107A9F4 3232 8107A9F6 3232 cn Infinite Health 8107A9D4 01F4 8107A9D6 01F4 cn Infinite Magic Points 8107A9D8 01F4 8107A9DA 01F4 cn Super Agility 8107A9DE 01F4 cn Super Defense 8107A9DC 01F4 crc 399B9B81-D533AD11-C:4A gn Extreme-G XG2 (J) cn Max Points 80183DD3 0064 cn Infinite\Nitros 81170F02 0003 81170F06 0003 cn Infinite\Shield 81170F2C 42C8 cn Access\All Tracks 50000BD8 0000 80183327 0001 cn Access\All Superbikes 50000304 0000 80183D6F 0001 cn Access\All Secret Characters 50000C04 0000 80183D6F 0001 cn Always 1st 80171063 0001 cn [Screen Hud Clear] cd This Fixes the Problem on all Plugins that have Hud covering the Screen.Let the game load 1st before Putting this code on,Or it will give an error and Freeze 80092D1B 0004 crc 147E0EDB-36C5B12C-C:4A gn Neon Genesis Evangelion (J) cn (Press GS)\To Refill Health cd Don't Press GS after the Enemy is killed, only during the fight! 891F0F18 42C8 891F0F1A 0000 cn (Press GS)\To Kill Enemy cd Don't Press GS after the Enemy is killed, only during the fight! and only use on Press GS Cheat at a time 891F2454 0000 891F2456 0000 891F2458 0000 891F245A 0000 cn (Press L)\ For One Hit Kill cd Don't Press L after the Enemy is killed, only during the fight! D0149DD5 0020 811F2458 0000 D0149DD5 0020 811F245A 0000 cn (Press R)\For Level Warp cd Press Reset and enjoy! D00D5115 0015 800D5115 ???? 002B:"Level 01",002F:"Level 02",0033:"Level 03",0037:"Level 04",003B:"Level 05",003D:"Level 06",0040:"Level 07",0043:"Level 08",0046:"Level 09",0049:"Level 10",004C:"Level 11",004F:"Level 12",0051:"Level 12.5",0053:"Level 13",0018:"Credits 1",0019:"Credits 2",001A:"Credits 3" cn Secret Beta 2 Player Test Mode cd Press Reset and enjoy! Secret 2 Player Test Mode? The Second Player doesn't move ;( D00D5115 0015 800D5115 0055 crc 4D3E622E-9B828B4E-C:4A gn F-Zero X (J) cn Always 1st Place 802C4BC2 0001 cn Infinite Lives 800E5AA9 0005 cn Unlock Everything 800CD428 0001 cn Player 1\Infinite Shield 812C4B48 4336 812C4B4C 4336 cn Have Boost From Start D02C4DAC 003F 802C4925 0050 cn Time Always 00.00.00 1st Place 802C4BC0 0000 802C4BC2 0001 crc 49E46C2D-7B1A110C-C:4A gn Fighting Cup (J) cn Start with Stars Modifier\Player 1 D0208E17 0000 80208E17 ???? 0000:"No Stars",0006:"Max Stars" cn Start with Stars Modifier\Player 2 D020ACDF 0000 8020ACDF ???? 0000:"No Stars",0006:"Max Stars" cn Have 1 Star\Ryuji 80306A0E 0001 cn Have 1 Star\Bob 80306A0F 0001 cn Have 1 Star\Pierre 80306A10 0001 cn Have 1 Star\Meiling 80306A11 0001 cn Have 1 Star\Leon 80306A12 0001 cn Have 1 Star\Abdul 80306A13 0001 cn Have 1 Star\Ninja 80306A14 0001 cn Have 1 Star\Tomahawk 80306A15 0001 cn Have 1 Star\Valerie 80306A16 0001 cn Infinite Health\Player 1 80208F61 0000 80203E83 0000 cn Infinite Health\Player 2 80203E87 0000 8020AE29 0000 cn Start on stage 100 on Survival to get Joker 802EED3B 0063 cn Stop timer for Fastest to get Robot 810AD29C 3F80 crc 28D5562D-E4D5AE50-C:4A gn Fire Electric Pen (J) cn Freeze Timer cd Only enable this cheat once the Timer Go moves to 80. Once the level has ended or you have died disable and enable on 80. 800760CB 0001 crc 70B0260E-6716D04C-C:4A gn GAUNTLET LEGENDS cn Infinite\Max Health 810C5C54 0000 810C5C56 270F 810C5C64 0000 810C5C66 270F cn Infinite\Money 810C5CF6 FFFF cn Max Strength 810C5C04 0000 810C5C06 FFFF cn Max Speed 810C5C14 0000 810C5C16 FFFF cn Max Magic 810C5C24 0000 810C5C26 FFFF cn Max Armour 810C5C34 0000 810C5C36 FFFF cn Infinite\Turbo 800FD30F 0064 cn Level 99 810C5C44 0000 810C5C46 0063 cn Infinite\Special Weapons 800C5FF7 0009 800C5D37 0009 800C5D67 0009 800C5DE7 0009 800C5EB7 0009 cn Always Shoot 5-Way 800FD198 0200 cn Always Shoot 3-Way 800FD19A 0002 cn Always Shoot Rapid Fire 800FD19A 1000 cn Have Window Schards 8104EFCA 000F cn Have Rune Stones 8104EFC6 1FFF cn Infinite\Item On Pickup 50010100 0000 810C5BF6 FFFF cn Infinite\Keys On Pickup 800C5C97 0006 crc 0DE2CE36-D41D29E6-C:4A gn Hybrid Heaven (J) cn Have All\Keys 50000410 0000 80181C70 0063 50000410 0000 80181C78 0063 cn Infinite\Weapons & Items 50000610 0000 80181C10 0063 50000610 0000 80181C18 0063 cn Infinite\Refresh Items 50000D10 0000 80181B48 0063 50000C10 0000 80181B50 0063 cn Infinite\Max Body Stats 81181788 270F 811817C8 0063 50000C02 0000 81181790 270F 50000502 0000 811817C0 270F 50000602 0000 811817E8 270F 50000602 0000 811817F6 270F cn Infinite\Max Health 81181780 270F 81181782 270F cn Level 999 811817C8 270F cn Press L To Levitate D005D8D1 0020 8124C710 3FCB crc 519EA4E1-EB7584E8-C:4A gn KING HILL 64 cn Max\50000 Stunt Points 8108C978 C350 cn Low Timer 8008C8A4 0000 8008C8A6 0000 cn Have\All Characters 8108C9B8 07FF cn Have\All Difficulties 8108C9B0 0700 cn Have\All Tracks 8108C9BC BFFE cn Have\All Boards 8108C9C4 0003 8108C9C6 FFFF crc 6BFF4758-E5FF5D5E-C:4A gn Mario Kart 64 (J) (1.0) cn Infinite Items\2 player Mode\Player 1 80163655 ???? 80163682 ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\2 player Mode\Player 2 80163735 ???? 80163762 ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 1 80163815 ???? 80163842 ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 2 801638F5 ???? 80163922 ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 3 801639D5 ???? 80163A02 ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 4 80163AB5 ???? 80163AE2 ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Have Bonus Mode and All Gold Cups 8018C728 ???? 8018C729 ???? 8018C72A ???? 8018C72B ???? 0000:"Off",00FF:"On" cn Press GS\For Full Debug Menu cd Press GS at the Press Start Menu to access the Debug Menu 8818C80F 0002 cn Press L To Levitate\Player 1 D00F73C5 0020 810F7478 4000 cn Press L To Levitate\Player 2 D00F73D5 0020 810F8250 4000 cn Press L To Levitate\Player 3 D00F73E5 0020 810F9028 4000 cn Press L To Levitate\Player 4 D00F73F5 0020 810F9E00 4000 crc C9C3A987-5810344C-C:4A gn Mario Kart 64 (J) (1.1) cn Have Bonus Mode and All Gold Cups 8018B4D8 ???? 8018B4D9 ???? 8018B4DA ???? 8018B4DB ???? 0000:"Off",00FF:"On" cn Press GS\For Full Debug Menu cd Press GS at the Press Start Menu to access the Debug Menu 8818B5BF 0002 cn Press L To Levitate\Player 1 D00F61B5 0020 810F6268 4000 cn Press L To Levitate\Player 2 D00F61C5 0020 810F7040 4000 cn Press L To Levitate\Player 3 D00F61D5 0020 810F7E18 4000 cn Press L To Levitate\Player 4 D00F61E5 0020 810F8BF0 4000 crc ADA815BE-6028622F-C:4A gn Mario Party (J) cn Top Left Character\Coin Options cd If you want to have full 255 Coins,1st use the 100 Option then put on 255. this will stop the numbers from changing & spoiling the result. 800F2709 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Left Character\Star Options 800F270D ???? 0000:"0 Stars",0064:"99 Stars" cn Top Right Character\Coin Options 800F2739 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Right Character\Star Options 800F273D ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Left Character\Coin Options 800F2769 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Left Character\Star Options 800F276D ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Right Character\Coin Options 800F2799 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Right Character\Star Options 800F279D ???? 0000:"0 Stars",0064:"99 Stars" cn Top Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D5782 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Top Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D57C6 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D580A ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D584E ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Mini Game\Unlimited 99 lives 800F2C03 0063 cn Mini Game\Max 99 Coins 800F2C0C 0063 crc 3A6C42B5-1ACADA1B-C:4A gn Mario Tennis 64 (J) cn Have All\Characters Available 8105DEB8 FFFF cn Have All\Courts Available 8105DEBC FFFF cn Score\Player 1 8014B1DA ???? 0000:"0",0001:"15",0002:"30",0003:"40" cn Score\Player 2 8014B1DB ???? 0000:"0",0001:"15",0002:"30",0003:"40" crc 736AE6AF-4117E9C7-C:4A gn Mickey no Racing Challenge USA (J) cn Play As 800D3161 ???? 0000:"Mickey Mouse",0001:"Daisy Duck",0002:"Goofy",0003:"Pete",0004:"Minnie Mouse",0005:"Donald Duck",0006:"Huey",0007:"Dewey",0008:"Louie",0009:"Lugwig Von Drake" cn Traffic Troubles\Indianapolis\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018E892 0063 cn Traffic Troubles\San Fransisco\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80191B62 0063 cn Traffic Troubles\New Mexico\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018FD52 0063 cn Traffic Troubles\Grand Canyon\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80193252 0063 cn Motor Way Mania\Los Angeles\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018DCF2 0063 cn Motor Way Mania\Alaska\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018E482 0063 cn Motor Way Mania\Las Vegas\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80192B12 0063 cn Motor Way Mania\Philadelphia\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80193992 0063 cn Freewayphobia\Dakota\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018D212 0063 cn Freewayphobia\Seattle\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018FDF2 0063 cn Freewayphobia\New York\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018F512 0063 cn Freewayphobia\Chicago\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80192042 0063 cn Victory Vehicles\Yellowstone\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018D4C2 0063 cn Victory Vehicles\Washington DC\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80197662 0063 cn Victory Vehicles\Everglades\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018FC22 0063 cn Victory Vehicles\Malibu\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801916B2 0063 cn Frantic Finale\Hawaii\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80192072 0063 cn Frantic Finale\Oregon\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018EA42 0063 cn Frantic Finale\Texas\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018F1E2 0063 cn Frantic Finale\Colorado\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80191992 0063 cn Level Select 801876B9 ???? 0000:"Traffic Troubles",0001:"Motor Way Mania",0002:"Freewayphobia",0003:"Vitory Vehicles",0004:"Frantic Finale",0005:"Time Trial",0006:"Practice",0007:"Contest",0008:"Options" cn Difficulty Select 8007C000 ???? 0000:"Amateur",0001:"Intermediate",0002:"Professional",0003:"Mirror Mode" cn Unlock Everything cd This will unlock all characters, tracks, mirror mode, all in-game cheats, postcards, pluto's collar and give you all Trophies for every track and difficulties. To have this cheat save to mempak, enable it and then go into the Options Menu and disable the cheat. Go to the Wide-Screen Settings and Change it to Wide-Screen [16.9] and then the B button to get back to Wide-Screen Settings, now go back into Wide-Screen [16.9] and change it back to Normal [4.3].and press the B button until you come back to the main Options Menu.Close the game and load it again to see everything saved to the Mempak and unlocked. 800D3208 008F 800D3209 0094 800D320A 0003 800D320C 0001 800D320F 0080 50000502 0000 800D3210 0009 50000502 0000 800D3211 0024 800D321A 0015 800D321B 007F 800D321C 0001 800D321D 00FF 800D321E 0004 800D321F 0022 cn Always 1st & final time 00:00.00 cd All Levels 50000301 0000 801CE6E9 0000 crc 96747EB4-104BB243-C:4A gn Perfect Dark (J) cn Have All Weapons\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80206B60 0007 801EDB60 0007 801D4B60 0007 cn Infinite\Ammo\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 802062EF 00FF 801ED2EF 00FF 801D42EF 00FF 80205B4B 00FF 801ECB4B 00FF 801D3B4B 00FF cn Infinite\Health\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 812053CC 3F80 811EC3CC 3F80 811D33CC 3F80 cn Infinite\Shield\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 812053E0 3F80 811E35A0 3F80 811CA5A0 3F80 cn Have All\Weapons\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 802087D0 0007 801EF7D0 0007 801D67D0 0007 cn Infinite\Ammo\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80207F5F 00FF 801EEF5F 00FF 801D5F5F 00FF 802077BB 00FF 801EE7BB 00FF 801D57BB 00FF cn Infinite\Health\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8120703C 3F80 811EE03C 3F80 811D503C 3F80 cn Infinite\Shield\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 811FE210 3F80 811E5210 3F80 811CC210 3F80 cn All levels Compleate cd This activate's solo missions, give all medals on solo missions, activate cheats, activate cinemas, and who knows what else. I just don't have the time to identify these codes. I know that some of this is creditted to Zap2. I don't have the time to cut those codes out. 50003201 0000 800A2940 0001 50003201 0000 800A2972 0001 50003201 0000 800A29A4 0001 crc 09CC4801-E42EE491-C:4A gn Pilot Wings64 (J) crc EC0F690D-32A7438C-C:4A gn Pocket Monsters Snap (J) cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C18E2 0006 crc 94807E6B-60CC62E4-C:4A gn Puyo Puyo Sun 64 (J) cn Maximum Score\Player 1 811632CC 05F5 811632CE E0FF cn Maximum Score\Player 2 811632D0 05F5 811632D2 E0FF cn No Warning Icons\Player 1 80164EA3 0000 cn No Warning Icons\Player 2 80164EA7 0000 cn Instant 7th Step of Chain\Player 1 D0163A2B 0001 80163A2B 0007 cn Instant 7th Step of Chain\Player 2 D0163E5B 0001 80163E5B 0007 cn Options Complete Demo Viewer 8016320B 0007 8116320C FFFF 8116320E FFFF cn Mode Total Continues 0 801632AF 0000 801632C7 0000 cn Endless Mode\Player Level 99 Player 1 801632E7 0063 cn Endless Mode\Player Level 99 Player 2 801632EB 0063 cn Nazo Puyo Mode\All Practice Stages Cleared 4 50000402 0000 811631E8 FFFF cn 1P Mode\Stage Select D0162FEB 0001 80162FEB ???? 000D:"Satan Arle game",0008:"Satan Schezo game",000E:"Car-kun Arle game",0009:"Car-kun Schezo game" crc 9F1ECAF0-EEC48A0E-C:4A gn Rakuga Kids (J) cn Infinite Energy\Player 1 800AC339 ???? 0000:"None",0040:"Max" cn Infinite Energy\Player 2 800AC429 ???? 0000:"None",003F:"Max" cn Super Attacks\Player 1 800AC33D ???? 0000:"None",0003:"3" cn Super Attacks\Player 2 800AC42D ???? 0000:"None",0003:"3" cn Infinite Match Time 800AB433 0000 cn Unlock Extras 800ACA05 00FF 800ACA07 00FF crc B6BC0FB0-E3812198-C:4A gn Sin and Punishment - Tsumi To Batsu (J) cn All Levels\Unlock All\Levels - Options Menu 80075DD6 FFFF 80075DD7 FFFF cn All Levels\Unlock All\Option Menu Items 80075DD8 FFFF 80075DD9 FFFF cn All Levels\Infinite\Energy 800D5A9B 00FF cn All Levels\Infinite\Time 800D5A97 0063 cn All Levels\Infinite\Max Credits 80075DDC 00FF cn Level\0-0\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 8010BB2B 0001 cn Level\1-1\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 801657FB 0001 cn Level\1-2\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 801BCFBB 0001 cn Level\1-3\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 8011270B 0001 cn Level\2-1\Invincible 801BD2BB 0001 cn Level\2-2\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 801B913B 0001 cn Level\2-3\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 801A7D0B 0001 cn Level\3-1\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 8015890B 0001 cn Level\3-2\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 801B938B 0001 cn Level\3-3\Invincible cd Only use one Ivincible level Code at a time for that specific level and only use for that specific level Cheat 81100E08 C350 cn Level\0-0\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time and only use for that specific level Cheat 8010BB0C 0000 cn Level\1-1\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801657DC 0000 cn Level\1-2\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801BCF9C 0000 cn Level\1-3\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801126EC 0000 cn Level\2-1\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801BD29C 0000 cn Level\2-2\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801B911C 0000 cn Level\2-3\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801A7CEC 0000 cn Level\3-1\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801588EC 0000 cn Level\3-2\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801B936C 0000 cn Level\3-3\Infinite Air Jumping cd Only use one Infinite Air Jumping level Code at a time for that specific level and only use for that specific level Cheat 801013CC 0000 crc 66572080-28E348E1-C:4A gn Super Robot Spirits (J) cn Infinite Hp 802016A7 0000 cn Infinite Sp 802016AB 005A cn Infinite Time 80260BDE 0000 cn Player 2 Health Mod 80206AF7 ???? 0000:"Infinite Health",00C8:"Instant Death" cn Play As 801B9D5C ???? 0000:"FINAL BOSS",0001:"R1",0002:"DAITARN 3",0003:"DANCOUGAR",0004:"SHINING GUNDAM",0005:"DUNBINE",0006:"WALKER GALLIER",0007:"VOLTES V",0008:"1st BOSS" crc 67D20729-F696774C-C:4A gn All Star! Dairantou Smash Brothers (J) cn Give Kirby A Wierd Blow-Up 8025C118 000A cn Story Mode\Skip Straight To Master Hand 800A2AA7 000D cn Story Mode\Infinite Time 810A2AEE 43CB cn Story Mode\Player 1\Infinite Lives 800A2B03 0004 cn Story Mode\Player 2\Infinite Lives 800A2B77 0004 cn Story Mode\Player 3\Infinite Lives 800A2BEB 0004 cn Story Mode\Player 4\Infinite Lives 800A2C5F 0004 cn Story Mode\Player 1\Low % Health 810A2B46 0000 cn Story Mode\Player 2\Low % Health 810A2BBA 0000 cn Story Mode\Player 3\Low % Health 810A2C2E 0000 cn Story Mode\Player 4\Low % Health 810A2CA2 0000 cn Story Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code could also result freezing at the end of the Level. 800A2AFB ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A2B6F ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A2BE3 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A2C57 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 1\Kirby B Button Move\Hyrule Castle 80266ACF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Yoshi's Island 80266E0F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Sector Z 8026F0B7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Peach's Castle 80261D5F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Saffron City 80271A57 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Congo Jungle 8026EA8F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Kirby's Dreamland 8026BAFF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Planet Zebes 8026DF67 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Metal Mario Stage 80261557 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Fighting Polygon Team 802606DF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Master Hand Stage 8026FC0F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Infinite Time 810A2CDE 43CB cn VS. Mode\Player 1\Low % Health 810A2D36 0000 cn VS. Mode\Player 2\Low % Health 810A2DAA 0000 cn VS. Mode\Player 3\Low % Health 810A2E1E 0000 cn VS. Mode\Player 4\Low % Health 810A2E92 0000 cn VS. Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A2CEB ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A2D5F ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A2DD3 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A2E47 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 1\Kirby B Button Move\Hyrule Castle 802619AF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Yoshi's Island 8026C277 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Sector Z 80269F47 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn P1 Press Down On D-Pad To Make Items Appear In Random Spots D109CF64 0400 8118B062 0001 cn Have All Characters 810A28F8 0FF0 cn VS. Mode\Have Mushroom Kindom 800A28F7 00FF cn Story Mode\Always Get Pacifist (60,000 Points) 810A2B2E 0000 cn Bonus Stage Character Modifier (Training Mode) cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 8018D193 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" crc 84FC04FF-B1253CE9-C:4A gn Snowbow Kids (J) cn Infinite\Tools Options 801215B5 ???? 0001:"Fan",0002:"Ghost",0003:"Pan",0004:"Rock",0005:"Mouse",0006:"Board" cn Infinite\Lucky Dip cd "Lucky Dip is Infinite Usage Of What Ever You Get From Each Red Box" 801215B4 0003 cn 999 Trick Game Pts cd Press the A Button to stop Count,or it will continue to grow without stoping. 81121360 03E7 cn 1 Lap Race D01215A8 0000 801215A8 0009 cn Infinite\Cash 8012160A C350 cn Enable Sinobin 8110A17E 0100 cn Access Gold Medals 50006002 0000 810EBD42 0101 crc A7941528-61F1199D-C:4A gn Chou Snowbow Kids (J) cn All Gold Medals 50000502 0000 81259130 0101 cn Max Coins 8125A5BE 270F 8025A5BF 00C8 cn Infinite\Trick Game 300 Points 8125A7F2 012C cn Infinite\Tools Options 8025A624 ???? 0001:"Frying Pan",0002:"Ghost",0003:"Super Ghost",0004:"Fan",0005:"Rocket",0006:"Invisible",0007:"Rock",0008:"Rat Face",0009:"Super Rat Face",000A:"Wings" cn Infinite\Weapons Options 8025A622 ???? 0001:"Slap Stick",0002:"Parachute",0003:"Freeze Shot",0004:"Snowman",0005:"Bomb",0006:"Whirlwind" 8025A623 0009 cn Open Extra Characters & Snowboards cd Battle Mode Only 8125916E 0101 80259170 0001 8025915C 0001 8125915E 0101 81259160 0101 crc 61F5B152-046122AB-C:4A gn Star Wars Episode I - Racer (J) cn No Damage 800A8047 0001 cn Always 1st 8011C25D 0001 cn Have All Tracks Completed 811170DA FFFF 811170DC 3FFF 811170DE 3FFF 811170E0 3FFF 811170E2 00FF cn Have All Characters 801170E2 007D 811170E4 FFFF cn Unlock All Tracks 801170D8 00FF 801170D9 00FF 801170DA 00FF 801170DB 00FF 811170D8 FFFF crc 4EAA3D0E-74757C24-C:4A gn Super Mario 64 (J) cn Mario's Cap\Off Options cd Here you can Choose Options with Mario without His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 80339E07 ???? 0001:"Mario No Cap",0002:"Invisible Mario",0004:"Metal Mario",0008:"Flying Mario",000A:"Invisible Flying Mario",000D:"Metal Flying Mario",000F:"Invisible Metal Flying Mario" cn Mario's Cap\On Options cd Here you can Choose Options with Mario with His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 80339E07 ???? 0012:"Invisible Mario",0015:"Metal Mario",0016:"Invisible Metal Mario",0019:"Flying Mario" cn Funny Mario Options\Mario's Cap\Off & in His Hand cd Here you can Choose Options with Mario with His Cap off & in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 80339E07 ???? 0020:"Cap In Hand",0022:"Invisible Mario Cap In Hand",0024:"Metal Mario Cap In Hand",0026:"Invisible Metal Mario Cap In Hand",0028:"Flying Mario Cap In Hand" cn Funny Mario Options\Mario's Cap\On & An Extra in His Hand cd Here you can Choose Options with Mario with His Cap on & An Extra in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 80339E07 ???? 0030:"Cap In Hand",0032:"Invisible Mario Cap In Hand",0034:"Metal Mario Cap In Hand",0036:"Invisible Metal Mario Cap In Hand",0038:"Flying Mario Cap In Hand" cn Infinite\Energy & Breath 80339EAE 0008 cn Infinite\Lives 80339EAD 0064 cn Have\Level Select 8032C64C 0001 cn Don't Hurt Mario\Monsters A0339E27 0001 cn Have\Debug Mode 8032C658 ???? 0001:"On",0000:"Off" cn Press GS for 255 Coins 89339EA8 00FF cn Press L To Levitate cd Press L to levitate & Let go to land D0339C31 0020 81339E4C 4220 D0339C31 0020 81339E0C 0300 D0339C31 0020 81339E0E 0880 cn Have All\175 Stars cd I have Managed to put a Have 175 Stars Option in for you,once the Code is activated, you will see it as a new option in Save Slot A. 80207B0B 00FF 50000D02 0000 81207B0C FFFF cn Have All\Maxed Out Coin Records For All Levels 80207B25 00FF 81207B26 FFFF 81207B28 FFFF 81207B2A FFFF 81207B2C FFFF 81207B2E FFFF 81207B30 FFFF 81207B32 FFFF crc D6FBA4A8-6326AA2C-C:4A gn Super Mario 64 Shindou Edition (J) cn Funny Mario Options\Limbo Mario cd Only Use This Code On Its Own,Do not use with any other Funny Mario Options. 8031DC0C 00C0 cn Funny Mario Options\Runs Backwards cd Only Use This Code On Its Own,Do not use with any other Funny Mario Options. 8031DC0E 0080 cn Mario's Cap\Off Options cd Here you can Choose Options with Mario without His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 8031D9C7 ???? 0001:"Mario No Cap",0002:"Invisible Mario",0004:"Metal Mario",0008:"Flying Mario",000A:"Invisible Flying Mario",000D:"Metal Flying Mario",000F:"Invisible Metal Flying Mario" cn Mario's Cap\On Options cd Here you can Choose Options with Mario with His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 8031D9C7 ???? 0012:"Invisible Mario",0015:"Metal Mario",0016:"Invisible Metal Mario",0019:"Flying Mario" cn Funny Mario Options\Mario's Cap\Off & in His Hand cd Here you can Choose Options with Mario with His Cap off & in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 8031D9C7 ???? 0020:"Cap In Hand",0022:"Invisible Mario Cap In Hand",0024:"Metal Mario Cap In Hand",0026:"Invisible Metal Mario Cap In Hand",0028:"Flying Mario Cap In Hand" cn Funny Mario Options\Mario's Cap\On & An Extra in His Hand cd Here you can Choose Options with Mario with His Cap on & An Extra in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 8031D9C7 ???? 0030:"Cap In Hand",0032:"Invisible Mario Cap In Hand",0034:"Metal Mario Cap In Hand",0036:"Invisible Metal Mario Cap In Hand",0038:"Flying Mario Cap In Hand" cn Infinite\Energy & Breath 8031DA6E 0008 cn Infinite\Lives 8031DA6D 0064 cn Don't Hurt Mario\Monsters A031D9E7 0001 cn Funny Mario Options\Ostrich Mario cd Only Use This Code On Its Own,Do not use with any other Funny Mario Options. 8031DC0C 0070 cn Press GS For 255 Coins cd Press GS Once on a Level To Get that amount of Coins 8931DA68 00FF cn Have All\175 Stars cd I have Managed to put a Have 175 Stars Option in for you,once the Code is activated, you will see it as a new option in Save Slot A. 80203F0B 00FF 50000D02 0000 81203F0C FFFF cn Have All\Maxed Out Coin Records For All Levels 80203F25 00FF 50000702 0000 81203F26 FFFF cn Have\Level Select 8030CCBC 0001 crc 9CE02E22-206EF1B0-C:4A gn Super Speed Race 64 (J) cn Always 1st Place 81098A58 0001 cn Freeze\Lap Timer cd Single and Chapionship Race Modes 800967E5 0000 800967E7 0000 cn Freeze\Pit Timer cd Single and Chapionship Race Modes 800968A5 0000 800968A7 0000 cn Car Select 800C50B1 ???? 0000:"Car 1",0001:"Car 2",0002:"Car 3",0003:"Car 4",0004:"Car 5",0005:"Car 6",0006:"Car 7",0007:"Car 8",0008:"Car 9",0009:"Car 10",000A:"Car 11",000B:"Car 12",000C:"Car 13",000D:"Car 14",000E:"Car 15",000F:"Car 16",0010:"Car 17",0011:"Car 18" cn 1 Lap To Race cd In Single and Chapionship Modes use the Laps In Race Cheat or use the in game setting to choose how many laps you want per race and them use this cheat and amount of Laps to have only have 1 left if needed. 80098A5D ???? 0003:"3 of 3 Laps",0006:"6 of 6 Laps",0009:"9 of 9 Laps",000C:"12 of 12 Laps",000F:"15 of 15 Laps",0012:"18 of 18 Laps",0015:"21 of 21 Laps",0018:"24 of 24 Laps",001B:"27 of 27 Laps",001E:"30 of 30 Laps" cn Freeze\Timer Challenge Timer cd Timer Challenge 800C4F87 0050 cn Laps\In Race\Chapionship Race Mode 800C4ED3 ???? 0003:"3 Laps In Race",0006:"6 Laps In Race",0009:"9 Laps In Race",000C:"12 Laps In Race",000F:"15 Laps In Race",0012:"18 Laps In Race",0015:"21 Laps In Race",0018:"24 Laps In Race",001B:"27 Laps In Race",001E:"30 Laps In Race" cn Laps\In Race\Single Race Mode 800C4ED1 ???? 0003:"3 Laps In Race",0006:"6 Laps In Race",0009:"9 Laps In Race",000C:"12 Laps In Race",000F:"15 Laps In Race",0012:"18 Laps In Race",0015:"21 Laps In Race",0018:"24 Laps In Race",001B:"27 Laps In Race",001E:"30 Laps In Race" cn Pit Stops\Championship 800C4F13 ???? 0000:"Off",0001:"On" cn Pit Stops\Single Race Mode 800C4F11 ???? 0000:"Off",0001:"On" cn Weather\Championship 800C4F33 ???? 0000:"Dry",0001:"Wet",0003:"Night" cn Weather\Single Race Mode 800C4F31 ???? 0000:"Dry",0001:"Wet",0003:"Night" cn Track Direction\Championship 800C4EF3 ???? 0000:"Normal",0001:"Reverse" crc 916AE6B8-8817AB22-C:4A gn Tokisora Senshi Turok (J) cn Infinite\Body Armor 8112FD96 5B23 8012FDD7 0001 cn Infinite\Air 81129030 AAE1 811E85EA F1FF cn Have All\Level Keys 8012FDE3 0007 8012FDE7 0007 8012FDEB 0007 8012FDEF 0007 8012FDF3 0007 8012FDF7 0007 8012FDFB 0007 cn Have All\Weapons 8012FDA7 0001 8012FDAB 0001 8012FDAF 0001 8012FDB3 0001 8012FDB7 0001 8012FDBB 0001 8012FDBF 0001 8012FDC3 0001 8012FDC7 0001 8012FDCB 0001 8012FDCF 0001 8012FDD3 0001 cn Infinite\Ammo 8012FD7F 00FF 8012FD93 00FF 8012FD83 00FF 8012FD63 00FF 8012FD8B 00FF 8012FD67 00FF 8012FD8F 00FF 8012FD6B 00FF cn Diffuculty Modifier 8011252F ???? 0000:"Easy",0001:"Normal",0002:"Hard" cn Infinite\Health 812C15F4 013C cn Have\Backpack 8012FD9B 0001 8012FDDB 0001 cn Infinite\Lives 8012FF0B 00FF cn Have\Cheat Menu 811205F0 FFFF 811205F2 FFFF cn Have All\Gems 8012FF07 00FF crc 5C9191D6-B30AC306-C:4A gn Wave Race 64 (J) cn Misses Don't Count 801D053F 0000 cn Infinite Time Stunt Mode 801D06CE 00FF cn Super Speed 801D0537 0005 D0161DC1 0010 801D0537 0020 cn 99 Points 801D8E13 0063 cn Infinite Course Out Time 801D06F3 00FF cn Maximum Power\Player 1 801D0537 0005 cn Maximum Power\Player 2 801D0B5A 0005 801D0DFA 0005 cn Only Play Glacier Coast 800E84C3 0007 cn Always First Place 801D040F 0000 crc 535DF3E2-609789F1-C:4A gn Wave Race 64 Shindou Edition (J) (V1.2) cn Misses Don't Count 801C399F 0000 cn Infinite Time Stunt Mode 801C3B2E 00FF cn Super Speed 801C3997 0005 D0155221 0010 801C3997 0020 cn 99 Points 801CC273 0063 cn Infinite Course Out Time 801C3B53 00FF cn Maximum Power\Player 1 801C3997 0005 cn Maximum Power\Player 2 801C3FBA 0005 801C425A 0005 cn Always First Place 801C386F 0000 crc DCB6EAFA-C6BBCFA3-C:4A gn Wetrix (J) cn Infinite Lakes 811AC9FE 0009 cn Mega Score 801ACA18 00FF 801DBDC4 00FF cn Always Empty Drain 801ACA51 0000 811ACA52 0000 811ACA54 0000 cn Always Berserk Mode 801ACA6F 00FF cn Stop Level Timer 801ACA72 00FF cn Practice Lessons Open 810C3AEA 0008 cn Always Drop\Player 1 801ACA7B ???? 0000:"Bar",0001:"T",0002:"Corner",0003:"Square",0004:"Down Square",0005:"Down Bar",0006:"Big Water",0007:"Medium Water",0008:"Small Water",0009:"Smallest Water",000A:"Bomb",000B:"Fireball" cn Always Drop\Player 2 801DD1FB ???? 0000:"Bar",0001:"T",0002:"Corner",0003:"Square",0004:"Down Square",0005:"Down Bar",0006:"Big Water",0007:"Medium Water",0008:"Small Water",0009:"Smallest Water",000A:"Bomb",000B:"Fireball" cn Infinite Ducks 801ACA0B 0009 crc 12737DA5-23969159-C:4A gn WWF Wrestlemania 2000 (J) cn Have All Characters 81094BDA FFFF cn Infinite Create-A-Wrestler Attribute Points 8011069B 001E cn Timer Is Always 00:00 80164F2F 0000 cn Max Attributes 80110691 0032 80110693 0032 80110695 0032 80110697 0032 80110699 0032 cn Weapon Select\Player 1 8115D0B6 0300 8115CC10 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 8115CC12 0000 8015CCD0 0000 cn Weapon Select\Player 2 8115D54A 0300 8115CC40 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 8015CC42 0001 8015CCD1 0001 cn Weapon Select\Player 3 8115D9DE 0300 8115CC70 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 8015CC72 0002 8015CCD2 0002 cn Weapon Select\Player 4 8115DE72 0300 8115CC98 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 8115CC9A 0003 8015CCD3 0003 cn Always Special\Player 1 8015D0B5 0004 cn Always Special\Player 2 8015D549 0004 cn Always Special\Player 3 8015D9DD 0004 cn Always Special\Player 4 8015DE71 0004 cn Specials Don't Run Out 81120C14 2400 cn Max Spirit\Player 1 8015D075 00FF cn Always Normal Spirit\Player 1 8015D075 0032 cn No Spirit\Player 1 8015D075 0000 cn Max Spirit\Player 2 8015D509 00FF cn Always Normal Spirit\Player 2 8015D509 0032 cn No Spirit\Player 2 8015D509 0000 cn Max Spirit\Player 3 8015D99D 00FF cn Always Normal Spirit\Player 3 8015D99D 0032 cn No Spirit\Player 3 8015D99D 0000 cn Max Spirit\Player 4 8015DE31 00FF cn Always Normal Spirit\Player 4 8015DE31 0032 cn No Spirit\Player 4 8015DE31 0000 cn Ultimate Codes\Player 1 8015D074 0064 cn Ultimate Codes\Player 2 8015D508 0064 cn Ultimate Codes\Player 3 8015D99C 0064 cn Ultimate Codes\Player 4 8015DE30 0064 cn Easy Pins & Longer Submissions\Player 2 8015D508 0064 cn Easy Pins & Longer Submissions\Player 3 8015D99C 0064 cn Easy Pins & Longer Submissions\Player 4 8015DE30 0064 cn Easy Pins & Longer Submissions\Player 1 8015D074 0064 crc EC417312-EB31DE5F-C:4A gn Zelda no Densetsu 2 - Mujura no Kamen (J) (v1.0) cn Have All\Quest Status Items 801EF51D 0005 811EF51E F7CF cn Infinite\Rupees 811EF49A 03E7 cn Infinite\Max & Double Magic Meter 801EF499 0060 811EF4A0 0101 cn Infinite\Arrows 801EF501 0063 cn Infinite\Bombs 801EF506 0063 cn Infinite\Bombchus 801EF507 0063 cn Infinite\Deku Sticks 801EF508 0063 cn Infinite\Deku Nuts 801EF509 0063 cn Infinite\Magic Beans 801EF50A 0063 cn Infinite\Powder Kegs 801EF50C 0063 cn Have\Ocarina of Time 801EF4D0 0000 cn Have\Hero's Bow 801EF4D1 0001 cn Have\Arrows\Fire Arrow 801EF4D2 0002 cn Have\Arrows\Ice Arrow 801EF4D3 0003 cn Have\Arrows\Light Arrow 801EF4D4 0004 cn Have\Bombs 801EF4D6 0006 cn Have\Bombchu 801EF4D7 0007 cn Have\Deku Sticks 801EF4D8 0008 cn Have\Deku Nuts 801EF4D9 0009 cn Have\Magic Beans 801EF4DA 000A cn Have\Powder Kegs 801EF4DC 000C cn Have\Pictograph 801EF4DD 000D cn Have\Lens of Truth 801EF4DE 000E cn Have\Hookshot 801EF4DF 000F cn Have\Great Fairy's Sword 801EF4E0 0010 cn Have\Bottle Modifier\1 801EF4E2 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\2 801EF4E3 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\3 801EF4E4 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\4 801EF4E5 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\5 801EF4E6 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\6 801EF4E7 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn All Equipment Upgrades 801EF4CD 0023 811EF51A 201B cn Have All\Masks 801EF4E8 005A 801EF4E9 0055 801EF4EA 0063 801EF4EB 0061 801EF4EC 005C 801EF4ED 004E 801EF4EE 0056 801EF4EF 0062 801EF4F0 0054 801EF4F1 005E 801EF4F2 0064 801EF4F3 004F 801EF4F4 0058 801EF4F5 0059 801EF4F6 0053 801EF4F7 005B 801EF4F8 0052 801EF4F9 0050 801EF4FA 005F 801EF4FB 005D 801EF4FC 0057 801EF4FD 0060 801EF4FE 0065 801EF4FF 0051 cn Replace Sword With 801EF4AC ???? 0002:"Fire Arrow w/ Bow",0003:"Ice Arrow w/ Bow",0004:"Light Arrow w/ Bow",0000:"Hero's Bow",0010:"Deity Link's Sword" cn Infinite\Health 811EF496 0140 cn Infinite\Hearts Options 811EF494 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D01FB9E1 0000 801EF462 ???? 0000:"Mama's House non Beta",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0003:"Southern Swamp Mr Tingle Entry",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",002E:"Woodfall Temple non Beta",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",0038:"Path to Romani Ranch non Beta",004A:"outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",0074:"Cave Portal to Last Boss Field",007F:"Waterfall Sothern Swamp",008A:"Giant Turtle In the Temple non beta",008B:"Room of Miau & Tijo Zora Great Hall",0094:"Recieving Gorans Mask non Beta",0095:"?",0096:"Hungry Goran in the Snow",00A2:"Statue in Stone Tower",00A6:"Stone Tower non Beta",00B9:"Recieving Deku Mask non Beta",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water",00FF:"Vamps House In Ikana Canyon" cn Press L To Levitate cd Press L To Levitate & Let go to land D03E6D0B 0020 81400008 40CB cn Play As 801EF480 ???? 0000:"Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Warp Modifier cd Put this code on and press the start button and it will now take where you wanted to go, turn it back off after you have got there. D05EC55A 0000 803FF545 0001 813FF54A ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" crc 69AE0438-2C63F3F3-C:4A gn Zelda no Densetsu 2 - Mujura no Kamen (J) (V1.1) cn Have All\Quest Status Items 801EF7CD 0005 811EF7CE F7CF cn Infinite\Rupees 811EF74A 03E7 cn Infinite\Max & Double Magic Meter 801EF749 0060 811EF750 0101 cn Infinite\Arrows 801EF7B1 0063 cn Infinite\Bombs 801EF7B6 0063 cn Infinite\Bombchus 801EF7B7 0063 cn Infinite\Deku Sticks 801EF7B8 0063 cn Infinite\Deku Nuts 801EF7B9 0063 cn Infinite\Magic Beans 801EF7BA 0063 cn Infinite\Powder Kegs 801EF7BC 0063 cn Have\Ocarina of Time 801EF780 0000 cn Have\Hero's Bow 801EF781 0001 cn Have\Arrows\Fire Arrow 801EF782 0002 cn Have\Arrows\Ice Arrow 801EF783 0003 cn Have\Arrows\Light Arrow 801EF784 0004 cn Have\Bombs 801EF786 0006 cn Have\Bombchu 801EF787 0007 cn Have\Deku Sticks 801EF788 0008 cn Have\Deku Nuts 801EF789 0009 cn Have\Magic Beans 801EF78A 000A cn Have\Powder Kegs 801EF78C 000C cn Have\Pictograph 801EF78D 000D cn Have\Lens of Truth 801EF78E 000E cn Have\Hookshot 801EF78F 000F cn Have\Great Fairy's Sword 801EF790 0010 cn Have\Bottle Modifier\1 801EF792 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\2 801EF793 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\3 801EF794 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\4 801EF795 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\5 801EF796 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Bottle Modifier\6 801EF797 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn All Equipment Upgrades 801EF77D 0023 811EF7CA 201B cn Have All\Masks 801EF798 005A 801EF799 0055 801EF79A 0063 801EF79B 0061 801EF79C 005C 801EF79D 004E 801EF79E 0056 801EF79F 0062 801EF7A0 0054 801EF7A1 005E 801EF7A2 0064 801EF7A3 004F 801EF7A4 0058 801EF7A5 0059 801EF7A6 0053 801EF7A7 005B 801EF7A8 0052 801EF7A9 0050 801EF7AA 005F 801EF7AB 005D 801EF7AC 0057 801EF7AD 0060 801EF7AE 0065 801EF7AF 0051 cn Replace Sword With 801EF75C ???? 0002:"Fire Arrow w/ Bow",0003:"Ice Arrow w/ Bow",0004:"Light Arrow w/ Bow",0000:"Hero's Bow",0010:"Deity Link's Sword" cn Infinite\Health 811EF746 0140 cn Infinite\Hearts Options 811EF744 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D01FBC91 0000 801EF712 ???? 0000:"Mama's House non Beta",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0003:"Southern Swamp Mr Tingle Entry",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",002E:"Woodfall Temple non Beta",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",0038:"Path to Romani Ranch non Beta",004A:"outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",0074:"Cave Portal to Last Boss Field",007F:"Waterfall Sothern Swamp",008A:"Giant Turtle In the Temple non beta",008B:"Room of Miau & Tijo Zora Great Hall",0094:"Recieving Gorans Mask non Beta",0095:"?",0096:"Hungry Goran in the Snow",00A2:"Statue in Stone Tower",00A6:"Stone Tower non Beta",00B9:"Recieving Deku Mask non Beta",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water",00FF:"Vamps House In Ikana Canyon" cn Press L To Levitate cd Press L To Levitate & Let go to land D03E6FCB 0020 814002C8 40CB cn Play As 801EF730 ???? 0000:"Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Warp Modifier cd Put this code on and press the start button and it will now take where you wanted to go, turn it back off after you have got there. D03E6FCA 0000 803FF805 0001 813FF80A ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" crc 8473D0C1-23120666-C:4A gn Zelda no Densetsu 2 - Mujura no Kamen - Zelda Collection Version (J) (GC Version) [!] cn Infinite\Rupees 811ED85A 03E7 cn Infinite\Health 811ED856 03E7 cn Infinite\Max & Double Magic Meter 801ED859 0060 811ED860 0101 cn Infinite\Items cd This is Infinite use of Bombs,Bombchus,Deku Sticks,Deku Nuts,Magic Beans,& Powder Kegs. But you must also put it's Have on to work. 801ED8C1 0063 50000801 0000 801ED8C6 0063 cn Have\All Masks 811ED8A8 3E39 811ED8AA 4745 811ED8AC 4032 811ED8AE 3A46 811ED8B0 3842 811ED8B2 4833 811ED8B4 3C3D 811ED8B6 373F 811ED8B8 3634 811ED8BA 4341 811ED8BC 3B44 811ED8BE 4935 cn Use all C Buttons 811F1738 0000 811F173A 0000 cn Event Item\Modifier 1 801ED895 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 2 801ED89B ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 3 801ED8A1 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Have Item Modifier 801ED8A0 ???? 0005:"Japanese Flute?",000B:"Japanese Item?",0010:"Great Fairy's Sword",0011:"Japanese Hookshot?",0031:"Japanese Scroll?",004A:"Japanese Bow?" cn Have Bottle\Modifier 1 801ED8A2 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have Bottle\Modifier 2 801ED8A3 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have Bottle\Modifier 3 801ED8A4 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have Bottle\Modifier 4 801ED8A5 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have Bottle\Modifier 5 801ED8A6 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have Bottle\Modifier 6 801ED8A7 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Great Fairy's Sword 801ED8A0 0010 cn Have\QuestStatus Items 801ED8DD 0005 811ED8DE F7CF cn Have\Have Ocarina of Time 801ED890 0000 cn Have\Hero's Bow 801ED891 0001 cn Have\Fire Arrow 801ED892 0002 cn Have\Ice Arrow 801ED893 0003 cn Have\Light Arrow 801ED894 0004 cn Have\Bombs 801ED896 0006 cn Have\Bombchu 801ED897 0007 cn Have\Deku Sticks 801ED898 0008 cn Have\Deku Nuts 801ED899 0009 cn Have\Magic Beans 801ED89A 000A cn Have\Powder Kegs 801ED89C 000C cn Have\Pictograph 801ED89D 000D cn Have\Lens of Truth 801ED89E 000E cn Have\Hookshot 801ED89F 000F cn All Equipment Upgrades 801ED88D 0023 811ED8DA 201B 801ED86C 004F cn Replace Sword With cd Only put the Deity Link's Sword on, if using The Play As Fierce Deity Link Code, if not it will turn Fierce Deity Link into a crazed slashing Machine. You have been warned. 801ED86C ???? 004A:"Fire Arrow w/ Bow",004B:"Ice Arrow w/ Bow",004C:"Light Arrow w/ Bow",004D:"Kokiri Sword",004E:"Razor Sword",004F:"Guilded Sword",0050:"Deity Link's Sword" cn Play As 801ED840 ???? 0000:"Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Infinite\Hearts Options cd If you need to clear the Infinite Max Hearts from the screen just choose the 6 or 4 Heart Options, take off the cheat & then make a save. 811ED854 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D03E4CAB 0000 801ED822 ???? 0000:"Mama's House non Beta",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0003:"Southern Swamp Mr Tingle Entry",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",002E:"Woodfall Temple non Beta",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",0038:"Path to Romani Ranch non Beta",004A:"outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",0074:"Cave Portal to Last Boss Field",007F:"Waterfall Sothern Swamp",008A:"Giant Turtle In the Temple non beta",008B:"Room of Miau & Tijo Zora Great Hall",0094:"Recieving Gorans Mask non Beta",0095:"?",0096:"Hungry Goran in the Snow",00A2:"Statue in Stone Tower",00A6:"Stone Tower non Beta",00B9:"Recieving Deku Mask non Beta",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water",00FF:"Vamps House In Ikana Canyon" cn Warp Modifier cd Put this code on and it will now take where you wanted to go, turn it back off or it will infinite loop entering all the time. 803E4CAA 0000 803FD505 0001 813FD50A ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" cn All Items (Normal Ram Pak Version) FF1E0000 0000 50002402 0202 810EC350 0001 crc EC7011B7-7616D72B-C:4A gn Zelda no Densetsu - Toki no Ocarina (J) (v1.0) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 8111B99C 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C84B5 0010 8011A5D7 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 8111B7F2 0000 8111B7F4 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A66C 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A674 30FF 8111A676 FFFF cn Max\Heart Containers 8111A5FE 0140 cn Max\Gold Skulltulas Killed 8011A6A1 0064 cn Time of Day Modifier 8111A5DC ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 8111A600 0140 cn Infinite\Magic D011A609 0008 8011A60A 0001 8011A60C 0001 8011A603 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 8011A640 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011A65C 0009 cn Infinite\Deku Nuts 8011A65D 0009 cn Infinite\Bombs 8011A65E 0009 cn Infinite\Arrows 8011A65F 0009 cn Infinite\Deku Seeds 8011A662 0009 cn Infinite\Bombchu's 8011A664 0009 cn Infinite\Magic Beans 8011A66A 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 8011A678 0007 8011A679 0007 8011A67A 0007 8011A67B 0007 8011A67C 0007 8011A67D 0007 8011A67E 0007 8011A67F 0007 8011A680 0007 8011A681 0007 8011A682 0007 8011A68F 0009 8011A690 0009 8011A691 0009 8011A692 0009 8011A693 0009 8011A699 0009 8011A69C 0009 8011A697 0009 cn Have\Ocarina 8011A64B ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 8011A650 000E cn Have\Lens of Truth 8011A651 000F cn Have\Megaton Hammer 8011A653 0011 cn Have\Deku Stick 8011A644 0000 cn Have\Deku Nut 8011A645 0001 cn Have\Bombs 8011A646 0002 cn Have\Fairy Bow 8011A647 0003 cn Have\Fairy Slingshot 8011A64A 0006 cn Have\Bombchu 8011A64C 0009 cn Have\Arrows\Fire Arrow 8011A648 0004 cn Have\Arrows\Ice Arrow 8011A64E 000C cn Have\Arrows\Light Arrow 8011A654 0012 cn Have\Hookshot 8011A64D ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 8011A652 0010 cn Have\Magic\Fairie's Wind 8011A64F 000D cn Have\Magic\Nayru's Love 8011A655 0013 cn Have\Magic\Din's Fire 8011A649 0005 cn Bottles\Bottle 1 Modifier 8011A656 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 8011A657 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 8011A658 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 8011A659 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011A65A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011A65B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011A60E 0001 cn Have Quiver (Holds 30) 8011A671 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying.If you Use Black Gauntlets,They are as strong as the Golden Gauntlets. This code also gives you the Silver Scale and the Golden Scale and unlimited rupees. 8011A672 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 8011A673 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Use this cheat to levitate. You have to deactivate it to come back down. Useful for passing obstacles that usually can be passed only at a later point! D01C84B5 0020 811DAA90 40CB cn Press L For infinite Hover Boots, cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C84B5 0020 811DB2B2 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C84B5 0020 811DAA90 40CB D01C84B5 0000 811DB2B2 000D 8011A640 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Beta Mode,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C84B5 0000 8011B9E3 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 8011A69F 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 8111B998 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All other Timers cd This cheat works on all Race Timers.Under Water with iron Boots etc. 8011B9A1 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801D8BCA 0006 801F2208 0001 801EEC88 0001 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 8011B9A5 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest 01). 80025614 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C84B5 0010 8111B936 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 8011B4B9 00FF 8011B92F ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 8011A672 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" crc D43DA81F-021E1E19-C:4A gn Zelda no Densetsu - Toki no Ocarina (J) (v1.1) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 8111BB5C 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C8675 0010 8011A797 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 8111B9B2 0000 8111B9B4 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A82C 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A834 30FF 8111A836 FFFF cn Max\Heart Containers 8111A7BE 0140 cn Max\Gold Skulltulas Killed 8011A861 0064 cn Time of Day Modifier 8111A79C ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 8111A7C0 0140 cn Infinite\Magic D011A7C9 0008 8011A7CA 0001 8011A7CC 0001 8011A7C3 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 8011A800 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011A81C 0009 cn Infinite\Deku Nuts 8011A81D 0009 cn Infinite\Bombs 8011A81E 0009 cn Infinite\Arrows 8011A81F 0009 cn Infinite\Deku Seeds 8011A822 0009 cn Infinite\Bombchu's 8011A824 0009 cn Infinite\Magic Beans 8011A82A 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 8011A838 0007 8011A839 0007 8011A83A 0007 8011A83B 0007 8011A83C 0007 8011A83D 0007 8011A83E 0007 8011A83F 0007 8011A840 0007 8011A841 0007 8011A842 0007 8011A84F 0009 8011A850 0009 8011A851 0009 8011A852 0009 8011A853 0009 8011A859 0009 8011A85C 0009 8011A857 0009 cn Have\Ocarina 8011A80B ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 8011A810 000E cn Have\Lens of Truth 8011A811 000F cn Have\Megaton Hammer 8011A813 0011 cn Have\Deku Stick 8011A804 0000 cn Have\Deku Nut 8011A805 0001 cn Have\Bombs 8011A806 0002 cn Have\Fairy Bow 8011A807 0003 cn Have\Fairy Slingshot 8011A80A 0006 cn Have\Bombchu 8011A80C 0009 cn Have\Arrows\Fire Arrow 8011A808 0004 cn Have\Arrows\Ice Arrow 8011A80E 000C cn Have\Arrows\Light Arrow 8011A814 0012 cn Have\Hookshot 8011A80D ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 8011A812 0010 cn Have\Magic\Fairie's Wind 8011A80F 000D cn Have\Magic\Nayru's Love 8011A815 0013 cn Have\Magic\Din's Fire 8011A809 0005 cn Bottles\Bottle 1 Modifier 8011A816 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 8011A817 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 8011A818 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 8011A819 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011A81A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011A81B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011A7CE 0001 cn Have Quiver (Holds 30) 8011A831 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying.If you Use Black Gauntlets,They are as strong as the Golden Gauntlets. This code also gives you the Silver Scale and the Golden Scale and unlimited rupees. 8011A832 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 8011A833 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Use this cheat to levitate. You have to deactivate it to come back down. Useful for passing obstacles that usually can be passed only at a later point! D01C8675 0020 811DAC50 40CB cn Press L For infinite Hover Boots, cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C8675 0020 811DB472 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C8675 0020 811DAC50 40CB D01C8675 0000 811DB472 000D 8011A800 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Beta Mode,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C8675 0000 8011BBA3 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 8011A85F 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 8111BB58 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All other Timers cd This cheat works on all Race Timers.Under Water with iron Boots etc. 8011BB61 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801D8D8A 0006 801F23C8 0001 801EEE48 0001 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 8011BB65 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest 01). 800257D4 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C8675 0010 8111BAF6 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 8011B679 00FF 8011BAEF ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 8011A832 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" crc 693BA2AE-B7F14E9F-C:4A gn Zelda no Densetsu - Toki no Ocarina (J) (v1.2) //--------------- (JU) Region Cheat Codes --------------- cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 8111C04C 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C8D75 0010 8011AC87 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 8111BEA2 0000 8111BEA4 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111AD1C 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111AD24 30FF 8111AD26 FFFF cn Max\Heart Containers 8111ACAE 0140 cn Max\Gold Skulltulas Killed 8011AD51 0064 cn Time of Day Modifier 8111AC8C ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 8111ACB0 0140 cn Infinite\Magic D011ACB9 0008 8011ACBA 0001 8011ACBC 0001 8011ACB3 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 8011ACF0 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011AD0C 0009 cn Infinite\Deku Nuts 8011AD0D 0009 cn Infinite\Bombs 8011AD0E 0009 cn Infinite\Arrows 8011AD0F 0009 cn Infinite\Deku Seeds 8011AD12 0009 cn Infinite\Bombchu's 8011AD14 0009 cn Infinite\Magic Beans 8011AD1A 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 8011AD28 0007 8011AD29 0007 8011AD2A 0007 8011AD2B 0007 8011AD2C 0007 8011AD2D 0007 8011AD2E 0007 8011AD2F 0007 8011AD30 0007 8011AD31 0007 8011AD32 0007 8011AD3F 0009 8011AD40 0009 8011AD41 0009 8011AD42 0009 8011AD43 0009 8011AD49 0009 8011AD4C 0009 8011AD47 0009 cn Have\Ocarina 8011ACFB ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 8011AD00 000E cn Have\Lens of Truth 8011AD01 000F cn Have\Megaton Hammer 8011AD03 0011 cn Have\Deku Stick 8011ACF4 0000 cn Have\Deku Nut 8011ACF5 0001 cn Have\Bombs 8011ACF6 0002 cn Have\Fairy Bow 8011ACF7 0003 cn Have\Fairy Slingshot 8011ACFA 0006 cn Have\Bombchu 8011ACFC 0009 cn Have\Arrows\Fire Arrow 8011ACF8 0004 cn Have\Arrows\Ice Arrow 8011ACFE 000C cn Have\Arrows\Light Arrow 8011AD04 0012 cn Have\Hookshot 8011ACFD ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 8011AD02 0010 cn Have\Magic\Fairie's Wind 8011ACFF 000D cn Have\Magic\Nayru's Love 8011AD05 0013 cn Have\Magic\Din's Fire 8011ACF9 0005 cn Bottles\Bottle 1 Modifier 8011AD06 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 8011AD07 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 8011AD08 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 8011AD09 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011AD0A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011AD0B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011ACBE 0001 cn Have Quiver (Holds 30) 8011AD21 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying.If you Use Black Gauntlets,They are as strong as the Golden Gauntlets. This code also gives you the Silver Scale and the Golden Scale and unlimited rupees. 8011AD22 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 8011AD23 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Use this cheat to levitate. You have to deactivate it to come back down. Useful for passing obstacles that usually can be passed only at a later point! D01C8D75 0020 811DB350 40CB cn Press L For infinite Hover Boots, cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C8D75 0020 811DBB72 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C8D75 0020 811DB350 40CB D01C8D75 0000 811DBB72 000D 8011ACF0 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Beta Mode,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C8D75 0000 8011C093 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 8011AD4F 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 8111C048 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All other Timers cd This cheat works on all Race Timers.Under Water with iron Boots etc. 8011C051 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801D927A 0006 801F28B8 0001 801EF338 0001 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 8011C055 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest 01). 80025CC4 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C8B65 0010 8111BFE6 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 8011BB69 00FF 8011BFDF ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 8011AD22 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" crc 1FBAF161-2C1C54F1-C:41 gn 1080 SNOWBOARDING //--------------- (U) Region Cheat Codes --------------- cn Infinite Damage All Players & Levels 803F4C3D 0000 cn Infinite Lives & Continues 8026B1CB 0003 cn Enable All Levels & Boarders 80255089 00FF 8025508B 0005 81255096 FCFF 80255098 0007 cn Stop Timer\Time Attack\Air Make 8031AB5A 0000 cn Stop Timer\Time Attack\Half Pipe 802F649A 0000 cn Stop Timer\Time Attack\Crystal Lake 802A593A 0000 cn Stop Timer\Time Attack\Crystal Peak 802B2CDA 0000 cn Stop Timer\Time Attack\Golden Forrest 802B146A 0000 cn Stop Timer\Time Attack\Mountain Village 802CBA6A 0000 cn Stop Timer\Time Attack\Dragon Cave 802C148A 0000 cn Stop Timer\Time Attack\Deadly Fall 802CF67A 0000 cn Stop Timer\Trick Attack\Air Make 8031ABCA 00C5 cn Stop Timer\Trick Attack\Half Pipe 802F650A 00C5 cn Stop Timer\Trick Attack\Crystal Lake 8029F77A 00C5 cn Stop Timer\Trick Attack\Crystal Peak 802AC9FA 00C5 cn Stop Timer\Trick Attack\Golden Forrest 802AB06A 00C5 cn Stop Timer\Trick Attack\Mountain Village 802C51EA 00C5 cn Stop Timer\Trick Attack\Dragon Cave 802BAE4A 00C5 cn Stop Timer\Trick Attack\Deadly Fall 802C8F1A 00C5 cn Stop Timer\Contest\Crystal Lake 8029C1EA 00C5 cn Stop Timer\Contest\Crystal Peak 802A89AA 00C5 cn Stop Timer\Contest\Golden Forest 802A6E4A 00C5 cn Stop Timer\Contest\Air Make 80319CCA 00C5 cn Stop Timer\Contest\Half Pipe 802F530A 00C5 cn Have All\Match Levels Completed 8025508A 0005 cn Have All\Contest First Place Done 80244098 0007 cn Open Level Character Select cd With these codes, you have to press the buttons listed below when you are viewing a certain boarders stats. Highlight Akari Hayami's stats, and then hold down the C-Left button and then press the A button to be the Crystal Boarder. Highlight Kensuke Kimachi's stats, and then hold down the C-Up button and then press the A button to be the Metal Boarder. Hightlight Rob Haywood's stats, and then hold down the C-Right button and then press the A button to be the Panda Boarder 8125508A ???? 0001:"Easy Level",0002:"Easy & Normal Level",0003:"Easy Normal & Hard Levels",0004:"Easy Normal Hard Levels & Crystal Boarder",0005:"Easy Normal Hard Levels & Crystal & Metal Boarders" cn Play As 800200E7 ???? 0000:"Dion Blaster",0001:"Kensuke Kimachi",0002:"Akari Hayami",0003:"Ricky Winterborn",0004:"Rob Haywood",0005:"Silver Boarder",0006:"Gold Boarder",0007:"Panda Boarder" cn Have All\Trick Attacks Done 81255096 FCFF crc 82DC04FD-CF2D82F4-C:45 gn A Bug's Life (J) cn Infinite\Lives 801E1A38 0009 cn Infinite\Health 801E1A2D 0004 cn Always Have\Super Jump 811E1A28 0020 cn Always Have\50 pieces of corn 801E1A39 0032 cn Have F-L-I-K 801E1A3A 000F cn Levitate cd "Press R To Levitate & Let go to land (:" D008F2C1 0010 801E199E 0001 D008F2C1 0010 801E19AE 0001 cn Unlock All Levels 81099150 000F cn Have All Goldberry Tokens 801E1A26 0000 cn Start with Berry Weapon 811E1A2E ???? 0001:"Blueberry",0002:"Homing Berry",0003:"Goldberry",0004:"Super Berry ?" crc 1B598BF1-ECA29B45-C:45 gn Aerofighter's Assault (U) cn Ultra Fast Missile Recharge 8027E300 0001 cn Rocket Squad 8027E107 0001 cn Tomahawk Squad 8027E109 0001 cn Extra Points D027A20C 0000 8027A20C 00FF cn Extra Planes 8127CCEC FFFF cn 99 Bonus 80130B87 0063 cn 99 Accuracy 80130B80 0063 cn Gun Select 8027E023 ???? 0000:"Chaff",0001:"Jammings",0002:"Air Mines",0003:"Mahibishi",000A:"22mm BB Shot",000B:"22mm",000C:"Hunai Shot",000D:"Fireball",000E:"Sabre",0014:"Fire",0015:"Tomahawk",0016:"Ninja Glitch",0017:"Fire Wave",001E:"Rocket",001F:"Phoenix",0020:"Star",0021:"Fire Arrow",0028:"Ninjabeam" cn Infinite\Chaffs 8027E017 000A cn Infinite\Gun 8027E110 0001 cn Infinite\Special Weapons 8027E4D2 0002 cn Infinite\Armor 8127CFF4 44A0 8127CFF8 44A0 cn Infinite\Health 8027CFF5 00C8 8027CFF9 00C8 cn Always Have\F-15J Eagle 8027CCEC 0010 cn Always Have\X-29A A.T.D. 8027CCED 0020 cn Infinite\99 Lives 80348B98 0063 crc AEBE463E-CC71464B-C:45 gn AEROGAUGE cn No Damage\Player 1 50000402 0000 8113FFD8 0000 cn No Damage\Player 2 50000402 0000 81142078 0000 cn Unlock Hidden Tracks & Cars 8008F29C 0001 cn Freeze All Lap Timers 8013FCA1 0001 8013FCA5 0001 8013FCA9 0001 cn Freeze Overall Timer cd All of the Freeze All Lap Timers must be on. These codes will Stop the others from racing against you in Grand Prix mode. To win a race in Grand Prix you must finish at least one lap in the qualify round, then complete all laps in race for first. 8013FC95 0001 cn Laps Of Race 8013FC8E ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"Never Ending Laps" cn Play As\Player 1 8013FF95 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Play As\Player 2 8013FF96 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Level Select 8013FF9B ???? 0000:"Canyon Rush",0001:"Bikini Island",0002:"China Town",0003:"Neo Arena",0004:"China Town Jam",0005:"Neo Speed Way" cn Always 1st 8013FCE0 0001 cn Music Modifier 80109BDC ???? 00FF:"Music On",0000:"Music Off" crc E6A95A4F-BAD2EA23-C:45 gn Aidyn Chronicles - The First Mage (U) cn Infinite\Max Health 80278B98 001E cn Infinite\99 Health Potions cd Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game. 802785CB 0063 cn Have\Max Gold 50000401 0000 80277335 00FF cn Have\Max Total XP 50000401 0000 80278BAD 00FF cn Have\Max Total XP Remaning to Start cd This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats 50000401 0000 80278BB1 00FF crc C43E23A7-40B1681A-C:45 gn All-Star Baseball 99 (U) cn Infinite\Character Creation Points 800E2C31 00B0 cn Infinite\Strikes 800ABFB9 0000 cn Infinite\Balls 800ABFB7 0000 cn Infinite\Outs 800ABFBB 0000 cn Max\Character Creation Accuracy 810E2BF0 4170 cn Max\Character Creation Clutch 810E2BF4 4170 cn Max\Character Creation Contact 810E2BFC 4170 cn Max\Character Creation Power 810E2C00 4170 cn Max\Character Creation VS. LHP 810E2C04 4170 cn Max\Character Creation VS. RHP 810E2C08 4170 cn Max\Character Creation Bunting 810E2C0C 4170 cn Max\Character Creation VS LHB 810E2C10 4170 cn Max\Character Creation VS RHB 810E2C14 4170 cn Max\Character Creation Speed 810E2C18 4170 cn Max\Character Creation Defense 810E2C1C 4170 cn Max\Character Creation Arm Strength 810E2C20 4170 cn Max\Character Creation Streak 810E2C24 4170 cn Max\Character Creation Clutch 810E2C28 4170 crc 5E547A4D-90E60795-C:45 gn All-Star Baseball 2000 (U) cn Infinite\Strikes 8006E4E1 0000 cn Infinite\Balls 8006E4DF 0000 cn Infinite\Outs 8006E4E3 0000 cn Infinite\Character Creation Points 81103350 4170 cn Infinite\Pitch Type Creation Points 811039BC 4170 811039C0 4170 cn Character Creation\Max\Accuracy 81115A20 4170 cn Character Creation\Max\Stamina 81115A24 4170 cn Character Creation\Max\Contact 81115A28 4170 cn Character Creation\Max\Power 81115A2C 4170 cn Character Creation\Max\VS LHP 81115A30 4170 cn Character Creation\Max\VS RHP 81115A34 4170 cn Character Creation\Max\Bunting 81115A38 4170 cn Character Creation\Max\VS LHB 81115A3C 4170 cn Character Creation\Max\VS RHB 81115A40 4170 cn Character Creation\Max\Speed 81115A44 4170 cn Character Creation\Max\Defense 81115A48 4170 cn Character Creation\Max\Arm Str. 81115A4C 4170 cn Character Creation\Max\Streak 81115A50 4170 cn Character Creation\Max\Clutch 81115A54 4170 crc E185E291-4E50766D-C:45 gn All Star Tennis '99 (U) cn Game Win Select\Player 1 801BBFA1 ???? 0000:"0 Games Won",0001:"1 Game Won",0002:"2 Games Won",0003:"3 Games Won",0004:"4 Games Won",0005:"5 Games Won",0006:"For Game Set & Match" cn Game Win Select\Player 2 801BBFA2 ???? 0000:"0 Games Won",0001:"1 Game Won",0002:"2 Games Won",0003:"3 Games Won",0004:"4 Games Won",0005:"5 Games Won",0006:"For Game Set & Match" cn Points Select\Player 1 801C7260 ???? 0000:"0 Points",0015:"15 Points",0030:"30 Points",0040:"40 Points" cn Points Select\Player 2 801C7261 ???? 0000:"0 Points",0015:"15 Points",0030:"30 Points",0040:"40 Points" cn Play As\Player 1 800BFFA5 ???? 0000:"Zoe Taylor",0001:"Vanessa Child",0002:"Amanda Coetzer",0003:"Jana Novotna",0004:"Conchita Martinez",0005:"Leon Rodez",0006:"Michael Chang",0007:"Gustavo Kuerten",0008:"Jonas Bjorkman",0009:"Mark Philippoussis",000A:"Randy Powell",000B:"Richard Krajicek" cn Play As\Player 2 800BFFA6 ???? 0000:"Zoe Taylor",0001:"Vanessa Child",0002:"Amanda Coetzer",0003:"Jana Novotna",0004:"Conchita Martinez",0005:"Leon Rodez",0006:"Michael Chang",0007:"Gustavo Kuerten",0008:"Jonas Bjorkman",0009:"Mark Philippoussis",000A:"Randy Powell",000B:"Richard Krajicek" crc 4C52BBB2-CEAB0F6B-C:45 gn Army Men - Air Combat (U) cn Co-Pilot Modifier 800B245C ???? 0000:"Lt. James Marshall \"Woodstock\"",0001:"Lt. John Lawless \"Hardcore\"",0002:"Lt. Dave Parker \"Rawhide\"",0003:"Lt. Felicity Wannamaker \"Bombshell\"",0004:"Sergeant Hawk \"Sarge\" (Hidden Character)" cn Helicopter Modifier 800B2534 ???? 0001:"Huey",0002:"Chinook (Hidden)",0003:"Super Stallion (Hidden)",0004:"Apache (Hidden)" cn Always Play Level Modifier 800B254C ???? 0000:"Mission 1-Plastic Pandemonium",0001:"Mission 2-Going Car-razy",0002:"Mission 3-The Train That Could",0003:"Mission 4-Tan Terror-Tory",0004:"Mission 5-Bug Bath",0005:"Mission 6-Uninvited Guests",0006:"Mission 7-Ants In The Pants",0007:"Mission 8-Saucer Attack",0008:"Mission 9-The Heat is On",0009:"Mission 10-The Melting Pot",000A:"Mission 11-River Rapids Riot",000B:"Mission 12-Nighttime Teddy",000C:"Mission 13-Demolition Time",000D:"Mission 14-Pick Up The Pieces",000E:"Mission 15-Have An Ice Day",000F:"Mission 16-Plastro's Revenge",0010:"Mission 17-Bug Hunt: Chew Chew Bug-B-Q",0011:"Mission 18-Bug Hunt: Crispy Critters",0012:"Mission 19-Flag-Nab-It: Fort Frenzy",0013:"Mission 20-Flag-Nab-it: Freezer Burn",0014:"Mission 21-Food Fight: Picnic Panic",0015:"Mission 22-Food Fight: Cherry Surprise",0016:"Mission 23-Rescue: Don't Feed The Crabs",0017:"Mission 24-Rescue: Tide Pool Terror" cn Start On Play Level Modifier D00B254C 0000 800B254C ???? 0000:"Mission 1-Plastic Pandemonium",0001:"Mission 2-Going Car-razy",0002:"Mission 3-The Train That Could",0003:"Mission 4-Tan Terror-Tory",0004:"Mission 5-Bug Bath",0005:"Mission 6-Uninvited Guests",0006:"Mission 7-Ants In The Pants",0007:"Mission 8-Saucer Attack",0008:"Mission 9-The Heat is On",0009:"Mission 10-The Melting Pot",000A:"Mission 11-River Rapids Riot",000B:"Mission 12-Nighttime Teddy",000C:"Mission 13-Demolition Time",000D:"Mission 14-Pick Up The Pieces",000E:"Mission 15-Have An Ice Day",000F:"Mission 16-Plastro's Revenge",0010:"Mission 17-Bug Hunt: Chew Chew Bug-B-Q",0011:"Mission 18-Bug Hunt: Crispy Critters",0012:"Mission 19-Flag-Nab-It: Fort Frenzy",0013:"Mission 20-Flag-Nab-it: Freezer Burn",0014:"Mission 21-Food Fight: Picnic Panic",0015:"Mission 22-Food Fight: Cherry Surprise",0016:"Mission 23-Rescue: Don't Feed The Crabs",0017:"Mission 24-Rescue: Tide Pool Terror" cn Unlock All Planes 810B252A 0105 crc 862C0657-8DFD896D-C:45 gn Army Men - Sarge's Heroes (U) cn Incendiary Bullets 80054C94 0001 cn All Weapons 8115969E 0001 cn Start With Max Ammo 8115FCBE 0001 cn Invincible 8115FCEE 0001 cn Infinite Continues 81159692 0001 cn Invisible 81159682 0001 cn Tin Solider 811596A2 0001 cn Maximum Visibility 80070F52 0001 cn Flamethrowers Fire In All Directions 8006BD79 0020 cn No Flamethrowers Will Work 8006D69D 0001 cn Multiplayer Cheats\Incendiary Bullets 80054C81 0001 cn Enemies Don't Recongnize You Easily 8005742D 0001 cn Play As 811609A2 ???? 0007:"The Big Green One",0008:"Vikki",0009:"Plastro" cn Play Level 81163FFA 0001 8116403E ???? 88A0:"Spy Blue",88B4:"Bathroom",88C8:"Riff Mission",88E0:"Forest 81163FFA",88F0:"Hoover Mission",8908:"Thick Mission",8920:"Snow Mission",8938:"Shrap Mission",8950:"Fort Plastro",8968:"Scorch Mission",8980:"Showdown",8994:"Sandbox",89A4:"Kitchen",89B4:"Living Room",89C8:"The Way Home" cn You Move Faster 800ABD69 00FF 800ABDA9 00FF cn Press Start For Other Debug Info 8115FCE2 0001 cn Enemies Fight Themselves 800585D8 0020 cn No Enemies In Levels 80056D4C 0020 cn Less Enemies In Levels 80056688 0020 cn Enemies Can't Aim 8006D14C 0020 cn Enemies Have To Reload Their Guns 8006D16A 0020 cn Walls Off For Enemies When Hit 800566D8 0020 cn Bullets Only Damage At Extremely Short Range 8006D15A 0020 cn Improved Gun Handling 8009C014 003E cn Can't Fail Missions 810A04FA ED40 cn Everyone Has Dark Camoflauge On 50000804 0000 81098F22 FAE4 cn Flamethrower Has Air Buster Flame 810A536A 5008 810A5372 5008 cn Flamethrower Has Cloud Flame 810A536A 5224 810A5372 5224 cn Flamethrower Has Invisible Flame 810A536A 52A0 810A5372 52A0 cn Max Kills Multiplayer\Player 1 8033B9BC FFFF cn Max Kills Multiplayer\Player 2 8033BB78 FFFF crc B20F73B6-2975FC34-C:45 gn Army Men - Sarge's Heroes 2 (U) cn Invincible 8135C516 0600 cn All Weapons & Ammo 8115D06E 0001 8116368E 0001 cn Max Ammo 8116368E 0001 cn Continues 8115D062 0001 cn Invisible 8115D052 0001 cn Test Info 8115D3B6 0001 cn Living Large 811636AE 0001 cn Mini Mode 8115D06A 0001 cn Play as 81164372 ???? 0007:"Big Green One",0008:"Vikki",0009:"Plastro",000B:"Mystery Women",000C:"Hail Mendheimicus",000D:"Mini Soldier" cn Enemies Fight Themselves 8005EE9C 0020 cn Move Faster 800B9705 00FF 800B9749 00FF crc 1FB5D932-3BA9481B-C:45 gn Armorines - Project S.W.A.R.M. (U) cn Enable In-Game Cheat Menu & Level Select 81115936 014F cn Infinite Lewis Laser Rifle cd The infinite ammo will not work with these codes if you have the expansion pak inserted into your console. 802E1D6F 0170 cn Infinite Lewis Explosive Projectile Weapon cd The infinite ammo will not work with these codes if you have the expansion pak inserted into your console. 802E1D69 0030 cn Infinite Jungle Chemical Gun cd The infinite ammo will not work with these codes if you have the expansion pak inserted into your console. 802E1D7B 0160 cn Level Select 81115932 0008 cn Infinite Ammo (All Guns) 810496D0 2400 cn Don't Take Any Damage 8104A260 2400 cn Invincible 81048CA0 2400 cn Sound Modifier\Music Volume 80115944 ???? 0000:"Off",003C:"Low (5)",0078:"Medium (1.0)",00BC:"Defualt (1.5)",00F0:"Max (2.0)" cn Sound Modifier\SFX Volume 80115945 ???? 0000:"Off",003C:"Low (5)",0078:"Medium (1.0)",00BC:"Defualt (1.5)",00F0:"Max (2.0)" crc D1F7D8AB-293B0446-C:45 gn Asteroids Hyper 64 (U) cn Extra Lives 8007F90E 0063 cn Extra Points 8107F8FE FFFF cn Infinite Armageddon 8107F892 0001 cn Infinite Items On Pickup 8107F8A2 270F cn Unlock Classic Asteroids 8106DF5A 0001 cn Infinite Lives (Classic Asteroids) 8007F90F 002F crc 41B25DC4-1B726786-C:45 gn Automobili Lamborghini (U) cn Extra Vehicles 50000302 0000 800985C3 0001 50000302 0000 800985CB 0001 cn Max Points 800CE743 FFFF cn Infinite Time 810CE76E 02F4 cn Difficulty Modifier 810CE7A4 ???? 0000:"Novice",0001:"Expert" cn Speeds In Modifier 800CE803 ???? 0000:"KM/H",0001:"MPH" cn Always 1st Place 810A5F70 0001 crc A4BF9306-BF0CDFD1-C:45 gn Banjo-Kazooie cn Infinite\Eggs 80385F67 00FF cn Infinite\Lives 80385F8B 00FF cn Infinite\Jiggies 80385FCB 00FF cn Press L To Levitate cd Press L To Levitate & Let go to land D0281251 0020 8137C4BC 43E0 cn Infinite\Notes cd Just collect one Note to Have 255 Notes in all Worlds. 80385FF2 00FF 80385F62 0001 cn Infinite\Health 80385F83 0008 80385F87 0008 cn Infinite\Air 81385F8E 0E10 cn Infinite\Gold Feathers 80385F73 00FF cn Infinite\Red Feathers 80385F6F 00FF cn Infinite\Always Have All Jinjos 80385F7B 00FF cn Have Zero Time all Levels 50000B04 0000 81386004 3000 cn Character Select cd When Mumbo transforms you hold:C-Up for the Termite,C-Right for the Pumpkin,C-Down for the Walrus,C-Left for the Crocc,R for the Bumble Bee,L for the Washing Machine,Press nothing to turn into Banjo D0281251 0008 8037C2D3 0002 D0281251 0001 8037C2D3 0003 D0281251 0004 8037C2D3 0004 D0281251 0002 8037C2D3 0005 D0281251 0010 8037C2D3 0006 D0281251 0020 8037C2D3 0007 cn Infinite\Mumbo Tokens 80385FC6 00FF 80385FA2 00FF cn Take Off And Fly From Anywhere cd Press A Button. Do not use with Do Shock Spring Jump From Anywhere 8037C1D1 0002 cn Access All Moves 8037C3A0 0001 8037C3A1 007F 8037C3A2 00FF 8037C3A3 00FF cn Game 100% Complete 8137C3A0 001F 50000302 0000 8137C3A2 FFFF 50000602 0000 813832C0 FFFF 81383FCA 0064 81383FDC 0064 50000802 0000 813832F0 FFFF 81385FA0 0063 81385FC4 0063 81385FF0 0064 50000602 0000 81385FF2 6464 50001002 0000 813831A8 FFFF 813831B0 FF7F 813831B2 FFB0 813831B4 3DA6 813831B6 F264 813831C6 FF7F cn Secret Items 81283400 ???? FFFF:"Have All Collected",0000:"Have None" cn Do Shock Spring Jump From Anywhere cd Press A Button. Do not use with Take Off And Fly From Anywhere 8037C1D2 0002 crc C2E9AA9A-475D70AA-C:45 gn Banjo-Tooie (U) cn Infinite\Energy\Banjo and Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8111B644 0A0A cn Infinite\Air 8112B052 42C8 cn Have\AllMoves cd Press Top D-pad Up D1081084 0800 8112C770 8029 D1081084 0800 8112C772 0000 81290018 FFFF 8129001A FFFF 8129001C FFFF 8129001E FFFF cn Have Most of the Game Finished cd Start a new game,when you appear in Spiral Mountain press Top D-Pad. Go to the menu and you will notice all eggs, all moves are available. All the jiggies have been collected. Simply Save and Restart. 5000AC01 0000 80290000 00FF 8029002B 007F 80290063 00FB 80290073 005F D1081084 0800 8112C770 8029 D1081084 0800 8112C772 0000 cn Infinite\Energy\Snowball cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8011B647 0005 cn Infinite\Energy\Bee cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8011B653 000A 8011B654 000A cn Infinite\Energy\Washing Machine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8111B656 0A0A cn Infinite\Energy\Stony cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8011B659 000A 8011B65A 000A cn Infinite\Energy\Banjo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8011B65F 000A 8011B660 000A cn Infinite\Energy\Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8111B662 0A0A cn Infinite\Energy\Submarine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8011B665 000A 8011B666 000A cn Infinite\Energy\Mumbo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8111B668 0A0A cn Infinite\Energy\Detonator cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8111B66E 0A0A cn Infinite\Energy\T-Rex Baby cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011B069 0063 8011B67F 000A 8011B680 000A cn Have\All Moves & Dragon Kazooie cd Press Top D-pad,Do not use with either Have all Moves,Or Have Dragon Kazooie D1081084 0800 8112C770 8029 D1081084 0800 8112C772 0000 81290018 FFFF 8129001A FFFF 8129001C FFFF 8129001E FFFF 81290078 FFFF 8129007A FFFF cn Have\Dragon Kazooie cd Press Top D-pad,Do not use with Have All Modes Or Have All Moves & Dragon Kazooie D1081084 0800 8112C770 8029 D1081084 0800 8112C772 0000 81290078 FFFF 8129007A FFFF cn Play As cd To use this cheat, put the cheat on, then press L as you walk through a door to become that chosen character. Do not try to use the following character in Banjos house or anywhere as small or you will get stuck and wont be able to continue. Snowball Washing machine Submarine Golden Goliath Truck T-rex baby and T-rex daddy D0081085 0020 8012704C ???? 0001:"Banjo and Kazooie",0002:"Snowball",0006:"Bee",0007:"Washing machine",0008:"Stony",000A:"Banjo",000B:"Kazooie",000C:"Submarine",000D:"Mumbo",000E:"Golden Goliath",000F:"Detonator",0010:"Truck",0012:"T-rex baby",0013:"T-rex daddy" cn Instant Warp\Options\Spiral Mountain cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 00AD:"Grunty's Old Lair",00AE:"Behind The Waterfall",00AF:"Top Of Castle",0173:"Banjo's house" 80127643 0001 cn Instant Warp\Options\Jinjo Village cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 0142:"Jinjo Village",0144:"King Jingalings throne room",0143:"Bottles house",0145:"Green Jinjo's House",0146:"Black Jinjo's House",0147:"Yellow Jinjo's House",0148:"Blue Jinjo's House",014A:"Brown Jinjo's House",014B:"Orange Jinjo's House",014C:"Purple Jinjo's House",014D:"Red Jinjo's House",014E:"White Jinjo's House" 80127643 0001 cn Instant Warp\Options\Mayahem Temple cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 00B6:"Humba's Wigwam",00B7:"Mumbo's skull",00B8:"The Temple",00B9:"Prison Compound",00BC:"Code chamber",00C4:"Jade Snake Grove",00C5:"Treasure Chamber",00C6:"Kickball Arena",0177:"Targitzan's Slighty Sacred Temple",0178:"Inside Targitzans Temple",0179:"Targitzan Temple Lobby",017A:"Targitzan's Temple Boss",017F:"Mayan Kickball Arena",0166:"Multi",0167:"Still",00C8:"Kickball Arena",00C9:"Kickball Arena" 80127643 0001 cn Instant Warp\Options\Glitter Gulch Mine cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 00C7:"Mine",00CA:"Fuel depot",00CB:"Crushing shed",00CC:"Flooded caves",00CD:"Water storage",00CE:"Waterfall cavern",00CF:"Power hut basement",00D0:"Chuffy's cab",00D1:"Inside chuffy's boiler boss",00D2:"Gloomy caverns",00D3:"Generator caverns",00D4:"Power hut",00D5:"Wumba's wigwam",00D7:"Train station",00D8:"Prospectors hut",00D9:"Mumbo's hut",00DA:"Toxic gas cave",00DB:"Canary cave",00DC:"Ordnance storage",00E9:"Humba",0126:"Water supply pipe",0163:"Ordnance Storage entrance",0164:"Ordnance Storage game",0165:"Ordnance Storage game Multi",016F:"Testing",0170:"Testing",0171:"Mumbo's skull" 80127643 0001 cn Instant Warp\Options\Witchy World cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 00D6:"Witcy World",00DD:"Dodgem dome lobby",00DE:"Dodgem challenge \"1 vs 1\"",00DF:"Dodgem challenge \"2 vs 1\"",00E0:"Dodgem challenge \"3 vs 1\"",00E1:"Crazy castle stockade",00E2:"Crazy castle lobby",00E3:"Crazy castle pump room",00E4:"Balloon burst game",00E5:"Hoop hurry game",00E6:"Star spinner",00E7:"The inferno",00EA:"Cave of horrors",00EB:"Haunted cavern",00EC:"Train station",0124:"Saucer of Peril",013B:"Crazy castle stockade \"sop\"",013C:"Star spinner \"sop\"",0176:"Mumbo's skull" 80127643 0001 cn Instant Warp\Options\Jolly Roger's Lagoon cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 00ED:"Jolly's",00EE:"Pawno's emporium",00EF:"mumbo's skull",00F4:"Ancient Swimming Baths",00F6:"Electric Eels lair",00F7:"Seaweed Sanctum",00F8:"Inside the big fish",00FA:"temple of the fishes",01A8:"Atlantis",01A9:"Seabottom",0181:"sea bottom cavern",0182:"submarine multi",01A7:"Jolly Roger's Lagoon",00FF:"Blubber's wave race hire" 80127643 0001 cn Instant Warp\Options\Terrydacty Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 0112:"Terrydacty Land",0113:"Terry's nest",0114:"Train station",0115:"Oogle boogles cave",0116:"Inside the mountain",0117:"River passage",0118:"Styracosaurus family cave",0119:"Unga bunga's cave",011A:"Stomping plains",011B:"Bonfire caverns",011E:"Humba's Wigwam",0123:"Inside chompa's belly",0183:"Chompa's belly multi" 80127643 0001 cn Instant Warp\Options\Grunty Industries cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 0100:"Outside",0101:"Inside",0102:"Train station",0103:"Workers quarters",0104:"Trash compactor",0105:"Elevator shaft",0106:"Floor 2",0107:"Floor 2 \"electromagnet chamber\"",0108:"Floor 3",0109:"Floor 3 \"boiler plant\"",010A:"Floor 3 \"packing room\"",010B:"Floor 4",010C:"Floor 4 \"cable room\"",010D:"Floor 4 \"quality control\"",010E:"Floor 5",010F:"Basement",0110:"Basement \"repair depot",0111:"Basement \"waste disposal\"",0125:"Water supply pipe",0172:"Mumbo's skull",0162:"Floor 4 \"clinkers cavern\"",0187:"Sewer entrance" 80127643 0001 cn Instant Warp\Options\Hailfire Peaks cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 0127:"Lava side",0128:"Icy side",0129:"Lava train station",012A:"Ice train station",012B:"Chilli billi",012C:"Chilly willy",012D:"Colosseum kickball stadium lobby",0131:"Boggy's igloo",0132:"Icicle grotto",0133:"Inside the volcano",0168:"Icy side still" 80127643 0001 cn Instant Warp\Options\Cloud Cuckoo Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 0136:"Cloud Cuckoo Land 1",0137:"Inside the trashcan",0138:"Inside the cheesewedge",0139:"Zubba's nest",013A:"Central cavern",013D:"Inside the pot o gold",013E:"Mumbo's skull",013F:"Mingy jongo's skull",0140:"Humba wumba's wigwam",0161:"Cloud Cuckoo Land 2",0188:"Zubba's nest multi",0185:"Trash can mini" 80127643 0001 cn Instant Warp\Options\Isle O Hags cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 014F:"Wooded Hollow",0150:"Heggy's egg shed",0151:"Jiggywiggy's temple",0152:"Plateau",0153:"Plateau \"Honey B's Hive\"",0154:"Pine Grove",0155:"Cliff top",0156:"Cliff top Mumbo's skull",015A:"wasteland",015B:"inside another digger tunnel",015C:"Quagmire" 80127643 0001 cn Instant Warp\Options\Cauldron Keep cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 015D:"Cauldron Keep",015E:"The gatehouse",015F:"Tower of Tragedy Quiz",0160:"Gun chamber",016A:"Gun room still",017B:"Crazy Castle Stockade balloon burst multi",017C:"Crazy Castle Stockade Jump the hoops multi",017D:"Grunty Industries packing game",0180:"Colosseum kickball arena",0186:"Dodgems" 80127643 0001 cn Instant Warp\Options\Not sure cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D0081084 0000 81127640 ???? 00FC:"Lord woo fak fak",00F9:"Mr Patch",0121:"Inside Chuffy's wagon",0134:"Mumbo's Skull",0135:"Humba Wumba's wigwam 1",0157:"Humba Wumba's wigwam 2",019B:"Jingalings Zombified Palace",01A6:"Smuggler cavern",0141:"Inside the digger tunnel",0143:"Bottles house",0169:"Bottles house still",018A:"HAG Inside",019A:"HAG1 Final Boss" 80127643 0001 cn Monsters dont Hurt Banjo 50002430 0000 80132EF5 0000 50002430 0000 80132EF6 0000 50002430 0000 80132EF7 0000 50002430 0000 80132EF8 0000 50002430 0000 80132EF9 0000 cn Beta Bottles Revenge Mode cd Bottles Revenge is a Beta mode from Banjo Tooie that the RWP team recently uncovered after an extraordinary amount of effort. Bottles the Spirit transforms into Bottles the Devil and posses enemies nearby and allows a second player hooked up to Pad 2 to play as that Posses character to try to foil Banjos Plans. As player one goes about its business, player two uses every enemy nearby to try to nab Banjo and take away some life. This mode is incredible, and you can control almost every enemy in the game: slot machines, flying creatures, uggers, zubbas...and this is just the beginning. (Congrats Rare Witch Project) 8012B3F2 0001 800810C1 0002 crc 8C138BE0-95700E46-C:45 gn In-Fisherman Bass Hunter 64 (U) cn Catch Bigger Fish 80111F06 0001 cn Line Never Breaks 80111F05 0001 cn All Lakes Unlocked 80111F00 0001 cn Extra Cash 80111F0B 0001 cn Easier to Catch Fish 80111F0E 0001 cn No Penalties in Tounament 80111F08 0001 crc BCFACCAA-B814D8EF-C:45 gn Bassmasters 2000 (U) cn Player 1 Max Score (Casting Game) 8107A412 FFFF cn Player 2 Max Score (Casting Game) 8107A416 FFFF crc 204489C1-1286CF2B-C:45 gn Batman Beyond - Return of the Joker (U) cn Infinite\Infinite Health 802086F2 0064 cn Infinite\Infinite Lives 802086F1 0063 cn Infinite\Infinite Batarangs 802086FE 0063 cn Infinite\Max Charge & Magnetic Nun Chaku 802086B9 0064 crc 6AA4DDE7-E3E2F4E7-C:45 gn BattleTanx (U) cn Have Storm Ravens Gang 80135773 0001 cn Run Story 80135770 0001 cn Start With All Weapons 80135765 0001 cn Toads 80135776 0001 cn Trippy 80135771 0001 cn Unlimited Ammo 80135760 0001 cn Frogs 80135775 0001 cn Have All Levels 80135767 0001 cn Hurl Mode 8013576B 0001 cn Invincible 80135763 0001 cn Invisible 8013576A 0001 cn Unlimited Lives 80135772 0001 cn Regenerated Allied Tanks Are Indestrucible In Campaign 8009FB2A 0001 cn Multiplayer\Player 1\Infinite Ammo 802D8603 00FF cn Multiplayer\Player 2\Infinite Ammo 802D9F2B 00FF cn Multiplayer\Player 1\Tank Turret Always On (Use Right/Left C Button) 802DE7FB 0011 802DE7FF 0002 cn Multiplayer\Player 2\Tank Turret Always On 802DEB43 0011 802DEB47 0002 cn Multiplayer\Player 3\Tank Turret Always On 802DEE8B 0011 802DEE8F 0002 cn Multiplayer\Player 4\Tank Turret Always On 802DF1D3 0011 802DF1D7 0002 cn Multiplayer\Player 1\Always Have Radar 802D8195 0080 cn Multiplayer\Player 2\Always Have Radar 802D9ABD 0080 cn Multiplayer\Player 1\Always Has Cloaked On 802D818D 0001 cn Multiplayer\Player 2\Always Has Cloaked On 802D9AB5 0001 cn Multiplayer\Player 1\Your Goalith Tank On Tracks Always Has Radar 802D869D 0080 cn Multiplayer\Player 2\Your Goalith Tank On Tracks Always Has Radar 802D9FC5 0080 cn Multiplayer\Player 1\Your Goalith Tank On Tracks Always Has Cloaked On 802D8695 0001 cn Multiplayer\Player 2\Your Goalith Tank On Tracks Always Has Cloaked On 802D9FBD 0001 cn Multiplayer\Plater 1\One Hit And You Bite It 802D819F 0001 cn MultiPlayer\Player 2\One Hit And You Bite It 802D9AC7 0001 cn Area 51\Shock Wave Weapons 802D5A7D 00AF cn Area 51\Mines Are Invisible 802D5ACB 00CC cn Area 51\Mines Are Toxic Waste 802D5ACB 007C cn Area 51\Turn Ammo Pickup Picture To Flamer Picture 802D5AAF 00AC cn Area 51\Turn Nuke Into Toxic Waste Nuke 802D5A7B 007C cn Multiplayer\Balltlelord Mode\Player 1\All Special Weapons & Infinite Ammo 50000E02 0000 811AD7EE FFFF cn Multiplayer\Balltlelord Mode\Player 2\All Special Weapons & Infinite Ammo 50000E02 0000 811AE186 FFFF cn Multiplayer\Balltlelord Mode\Player 3\All Special Weapons & Infinite Ammo 50000E02 0000 811AEB1E FFFF cn Multiplayer\Balltlelord Mode\Player 4\All Special Weapons & Infinite Ammo 50000E02 0000 811AF4B6 FFFF cn Multiplayer\Deathmatch, Frenzy & Convoy Modes\Player 1\All Special Weapons & Infinite Ammo 50000E02 0000 811AD322 FFFF cn Multiplayer\Deathmatch, Frenzy & Convoy Modes\Player 2\All Special Weapons & Infinite Ammo 50000E02 0000 811ADCBA FFFF cn Multiplayer\Deathmatch, Frenzy & Convoy Modes\Player 3\All Special Weapons & Infinite Ammo 50000E02 0000 811AE652 FFFF cn Multiplayer\Deathmatch, Frenzy & Convoy Modes\Player 4\All Special Weapons & Infinite Ammo 50000E02 0000 811AEFEA FFFF cn Multiplayer\Hold 'Em Mode\Player 1\All Special Weapons & Infinite Ammo 50000E02 0000 811AD7EE FFFF cn Multiplayer\Hold 'Em Mode\Player 2\All Special Weapons & Infinite Ammo 50000E02 0000 811AE186 FFFF cn Multiplayer\Hold 'Em Mode\Player 3\All Special Weapons & Infinite Ammo 50000E02 0000 811AEB1E FFFF cn Multiplayer\Hold 'Em Mode\Player 4\All Special Weapons & Infinite Ammo 50000E02 0000 811AF4B6 FFFF cn All Batteries Have Hellfire 800A34A2 0001 cn All Batteries Have Bad Aim 800A1F7C 0001 cn Buildings Implode Instead Of Explode, And Remain Afire 8009298E 0001 cn Shoot Through Walls 8008E529 0001 cn All Battletanx Are Invincible 8009843D 0001 cn Can't Pick Up Queen Lords 8008A2F0 0001 cn Auto Win All Queen Lord Levels 800A6745 0001 cn Auto Lose All Queen Lord Levels 800A6746 0001 cn Slow Battle Tanks 8009A56A 0001 cn Buildings Fall Fast 80091BBC 0001 cn Nuke Blast Leaves Air Yellow 800F3333 0001 cn Nuke Blast Pink 8008055F 0001 cn Laser Fire Invisible 800846ED 0001 cn Full Control Of Tank In Bonus,Extra Side Player In Battlelord Multi! 800971EE 0001 cn Multiplayer\Balltlelord Mode\Player 1\Infinite Secondary Weapons In Battlelord 802D8609 00FF 802D860B 00FF 802D860D 00FF 802D860F 00FF 802D8611 00FF 802D8615 00FF 802D8617 00FF 802D8619 00FF 802D861B 00FF 802D861D 00FF 802D861F 00FF 802D8621 00FF cn Multiplayer\Balltlelord Mode\Player 2\Infinite Secondary Weapons In Battlelord 802D9F31 00FF 802D9F33 00FF 802D9F35 00FF 802D9F37 00FF 802D9F39 00FF 802D9F3D 00FF 802D9F3F 00FF 802D9F41 00FF 802D9F43 00FF 802D9F45 00FF 802D9F47 00FF 802D9F49 00FF cn In Campaign 3 Enemy Tanks May Join You 802D9AAC 0000 802DB3D4 0000 802DCCFC 0000 cn Multiplayer\Player 1\Main Weapon 802D85EB ???? 0000:"Nothing",0001:"Normal Tank Shells",0002:"Motor Tank Shells",0003:"Big Tank Shells",0004:"Rockets",0005:"Laser",0006:"Nuke",0007:"Gernades",0008:"?",0009:"?",000A:"Nuclear Lasers",000B:"Remote Rockets",000C:"Mines",000D:"Gun Buddies",000E:"Smoke Screen",000F:"Cloaking",0010:"Health" cn Multiplayer\Player 2\Main Weapon 802D9F13 ???? 0000:"Nothing",0001:"Normal Tank Shells",0002:"Motor Tank Shells",0003:"Big Tank Shells",0004:"Rockets",0005:"Laser",0006:"Nuke",0007:"Gernades",0008:"?",0009:"?",000A:"Nuclear Lasers",000B:"Remote Rockets",000C:"Mines",000D:"Gun Buddies",000E:"Smoke Screen",000F:"Cloaking",0010:"Health" cn Multiplayer\Player 1\Secondary Weapon 802D85F7 ???? 0000:"Nothing",0001:"Normal Tank Shells",0002:"Motor Tank Shells",0003:"Big Tank Shells",0004:"Rockets",0005:"Laser",0006:"Nuke",0007:"Gernades",0008:"?",0009:"?",000A:"Nuclear Lasers",000B:"Remote Rockets",000C:"Mines",000D:"Gun Buddies",000E:"Smoke Screen",000F:"Cloaking",0010:"Health" cn Multiplayer\Player 2\Secondary Weapon 802D9F1F ???? 0000:"Nothing",0001:"Normal Tank Shells",0002:"Motor Tank Shells",0003:"Big Tank Shells",0004:"Rockets",0005:"Laser",0006:"Nuke",0007:"Gernades",0008:"?",0009:"?",000A:"Nuclear Lasers",000B:"Remote Rockets",000C:"Mines",000D:"Gun Buddies",000E:"Smoke Screen",000F:"Cloaking",0010:"Health" cn Multiplayer\Player 1\Tank Body Modifier 802D819B ???? 0000:"Normal Tank",0001:"Motor Tank",0002:"Big Tank" cn Multiplayer\Player 2\Tank Body Modifier 802D9AC3 ???? 0000:"Normal Tank",0001:"Motor Tank",0002:"Big Tank" cn Multiplayer\Player 1\Goalith Tank On Tracks Body Modifier 802D86A3 ???? 0000:"Normal Tank",0001:"Motor Tank",0002:"Big Tank" cn Multiplayer\Player 2\Goalith Tank On Tracks Body Modifier 802D9FCB ???? 0000:"Normal Tank",0001:"Motor Tank",0002:"Big Tank" crc 75A4E247-6008963D-C:45 gn BattleTanx - Global Assault (U) cn Rapid Fire 8008E7F0 0001 cn Edge Hits Everything 80071AF0 0043 cn Mini-Tanks 1 80125AB8 0001 cn Mini-Tanks 2 80125AB9 0001 cn Mini-Tanks 3 80125AB9 0001 cn Mini-Tanks 4 80125ABB 0001 cn Mini-Tanks 5 80125ABC 0001 cn Infinite Tank Bucks 80236A9F 0064 cn Level Select 80117F49 0001 cn Invulnerability 80125AB0 0001 cn Start With All Weapons 80125AB1 0001 cn Secret Level 80125AB2 0001 cn Enable Models 80125AB3 0001 cn Cassandra Gang 80125AB5 0001 cn Brandon Gang 80125AB6 0001 crc 55D4C4CE-7753C78A-C:45 gn Battlezone - Rise of the Black Dogs (U) cn Infinite\Weapons 811DF6EA 04B0 cn Infinite\Ship Health 811DF6DE 0BA9 cn Infinite\Shots For Sniper Rifle 811DA682 0003 cn Have\All\Levels Unlocked & Completed For Americans 8006A1F0 0011 cn Have\All\Levels Unlocked & Completed For Soviets 8006A1F1 0008 cn Have\All\Levels Unlocked & Completed For Black Dogs 8006A1F3 000A cn Have\All\Missions Open And Complete For Americans 8006A1EC 0011 cn Have\All\Missions Open And Complete For Soviets 8006A1ED 0008 cn Have\All\Missions Open And Complete For Black Dogs 8006A1EF 000A cn Infinite\Scrap Collected 811FBCC6 FFFF cn Max\Scrap Limit 811FBCCA FFFF cn Infinite\Pilots 811FBCCE FFFF cn Max\Pilot Limits 811FBCD2 FFFF cn Infinite\Armor 8006A1C2 0001 cn Infinite\Ammo 8006A1C1 0001 cn Level Select 8006A1F5 0001 cn Add\Building 8006A1C0 0001 cn Add\Satellite 8006A1C3 0001 crc 4D79D316-E8501B33-C:45 gn Beast Wars Transmetal (U) cn Infinite\Health\Player 1 8112CD46 270F cn Infinite\Stun Meter\Player 1 8012CD49 00FF cn Infinite\Health\Player 2 8114D2C6 270F cn Infinite\Stun Meter\Player 2 8014D2C9 00FF cn Play As\Player 1 801BE2A4 ???? 0000:"Optimus Primal",0001:"Rattrap",0002:"Cheetor",0003:"Airazor",0004:"Megatron",0005:"Tarantulas",0006:"Waspinator",0007:"Terrorsaur" cn Play As\Player 2 801BE2A5 ???? 0000:"Optimus Primal",0001:"Rattrap",0002:"Cheetor",0003:"Airazor",0004:"Megatron",0005:"Tarantulas",0006:"Waspinator",0007:"Terrorsaur" cn Choose Stage\VS. Mode 800ED6CF ???? 0000:"Stage 1",0001:"Stage 2",0002:"Stage 3",0003:"Stage 4",0004:"Stage 5",0005:"Stage 6",0006:"Stage 7",0007:"Stage 8 (Hidden Stage)",0008:"Stage 9 (Hidden Stage)",0009:"Stage A (Hidden Stage)" cn Infinite\Time 80102A94 000A cn Bonus Menu Games\Infinite Time\Escape Race 100 & 200\Player 1 811BD3B6 000A cn Bonus Menu Games\Infinite Time\Escape Race 100 & 200\Player 2 811BD3BA 000A cn Bonus Menu Games\Max\Wins\Sunset & Sunrise Showdown\Player 1 801BC25F 00FF cn Bonus Menu Games\Max\Points\Disc Hunter\Player 1 801BD3E9 00FF cn Bonus Menu Games\Max\Points\Disc Hunter\Player 2 801BD3EB 00FF crc EDF419A8-BF1904CC-C:45 gn Beetle Adventure Racing! (U) cn Have\All Cars 8002CFF7 000B cn Have\All Tracks 8002CFF3 0006 cn Low Timer 81025DD4 3F40 cn Open All Difficulties 8002CFFB 0003 cn Infinite Continues 8002CC57 0005 cn Always Place 1st 81025DD4 1110 81025DDC 3F40 cn Multi-Player Unlock All Levels 50000901 0000 8002D000 0001 crc 08FFA4B7-01F453B6-C:45 gn Big Mountain 2000 (U) cn Always 1st/Low Time 81350C02 0000 80350C17 0063 cn Infinite Stamina 8034F798 0012 cn Free Ride Complete\Stage 1-Skier 800B3578 0001 cn Slalom Complete\Stage 1-Skier 800B357C 0001 cn Giant Slalom Complete\Stage 1-Skier 800B3580 0001 cn Free Ride Complete\Stage 2-Skier 800B3584 0001 cn Slalom Complete\Stage 2-Skier 800B3588 0001 cn Giant Slalom Complete\Stage 2-Skier 800B358C 0001 cn Free Ride Complete\Stage 3-Skier 800B3590 0001 cn Slalom Complete\Stage 3-Skier 800B3594 0001 cn Giant Slalom Complete\Stage 3-Skier 800B3598 0001 cn Free Ride Complete\Stage 4-Skier 800B359C 0001 cn Slalom Complete\Stage 4-Skier 800B35A0 0001 cn Giant Slalom Complete\Stage 4-Skier 800B35A4 0001 cn Free Ride Complete\Stage 1-Boarder 800B357A 0001 cn Slalom Complete\Stage 1-Boarder 800B357E 0001 cn Giant Slalom Complete\Stage 1-Boarder 800B3582 0001 cn Free Ride Complete\Stage 2-Boarder 800B3586 0001 cn Slalom Complete\Stage 2-Boarder 800B358A 0001 cn Giant Slalom Complete\Stage 2-Boarder 800B358E 0001 cn Free Ride Complete\Stage 3-Boarder 800B3592 0001 cn Slalom Complete\Stage 3-Boarder 800B3596 0001 cn Giant Slalom Complete\Stage 3-Boarder 800B359A 0001 cn Free Ride Complete\Stage 4-Boarder 800B359E 0001 cn Slalom Complete\Stage 4-Boarder 800B35A2 0001 cn Giant Slalom Complete\Stage 4-Boarder 800B35A6 0001 cn All Boards Complete 50001802 0000 810B3578 0001 crc 08123595-0510F1DE-C:45 gn Bio F.R.E.A.K.S. (U) cn Never Wins\Player 1 8015029B 0000 cn Needs 1 Match to Win\Player 1 D015029B 0000 8015029B 0001 cn Infinite Health\Player 1 811502AA 6400 cn 1-Hit Death\Player 1 D01502AA 0064 811502AA 0100 cn Infinite Shield\Player 1 811502AE 6400 cn Infinite Jetpack\Player 1 811502B2 3200 cn Play As\Player 1 801ABB2B ???? 000A:"She-Freak",000B:"PainMaster",000C:"Mutilator",000D:"ChainSaw" cn Never Wins\Player 2 80152917 0000 cn Needs 1 Match to Win\Player 2 D0152917 0000 80152917 0001 cn Infinite Health\Player 2 811502AA 6400 cn 1-Hit Death\Player 2 D0152926 0064 81152926 0100 cn Infinite Shield\Player 2 8115292A 6400 cn Infinite Jetpack\Player 2 8115292E 3200 crc 7C647C25-D9D901E6-C:45 gn Blast Corps (U) (V1.0) cn Infinite\Hydraulics Sidesweeper 803EDB51 0063 cn Infinite\Missiles Motor Bike 803F8AC3 0063 cn Infinite\Boosts Buggy Vehicle 803EE301 0064 cn Ballista Can Drive Through Anything 803F8A68 0001 cn Found All\RDUS 8036E9CC C350 cn Found All\Survivors 8036E9C9 00FF cn Found All\Scientists 80364AD0 003F cn Infinite Time D0315610 0000 81315610 0000 D0315612 0001 81315612 0000 crc 7C647E65-1948D305-C:45 gn Blast Corps (U) (V1.1) cn Infinite\Hydraulics Sidesweeper 803EDC00 0063 cn Infinite\Missiles Motor Bike 803F8B72 0063 cn Infinite\Boosts Buggy Vehicle 803EE3B0 0064 cn Ballista Can Drive Through Anything 803F8B17 0001 cn Found All\RDUS 8036EA7C C350 cn Found All\Survivors 8036EA70 00FF cn Found All\Scientists 80364B80 003F cn Infinite Time D03156C0 0000 813156C0 0000 D03156C2 0001 813156C2 0000 crc 7CD08B12-1153FF89-C:45 gn Blues Brothers 2000 (U) cn Have All\Keys cd This will give you the Grey & Red,Green & Gold Keys 800BD0B8 00FF 800BD0BE 00FF 800BD0BD 00FF cn Have All\Music Notes cd This will give you all 10 Music Notes 50000A01 0000 800BD1F0 0001 cn Infinite\Lives 800BD0E3 0009 cn Infinite\Health 800BD0F7 0002 cn Press L to Levitate cd Press L to levitate & let go to come back down D017DBC5 0020 810DAFD8 44CB cn Max Money 810BD0E6 03E7 cn Can Walk When The Game Is Paused 810AB9B6 0001 crc 5326696F-FE9A99C3-C:45 gn Body Harvest (U) cn Infinite\Greece 81052B18 0098 81052B1A 967F cn Infinite\Health 810DDCEC 0258 cn No Humans Killed 8104816A 0000 cn Have Alien Artifact 8004DC5F 0001 cn Item Modifier 8004DC4F ???? 0000:"Nothing",0002:"Howitzer Shells",0040:"Crank",0080:"Windmill Cog",0100:"Heirglyph Map Piece",0400:"Hangar Key",FFFF:"All Items" cn Weapon Select\1st Position 80048138 ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\2nd Position 80048139 ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\3rd Position 8004813A ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\4th Position 8004813B ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\5th Position 8004813C ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\6th Position 8004813D ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\7th Position 8004813E ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\8th Position 8004813F ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Infinite Ammo All Weapons 50001102 0000 81048146 8000 cn Level Select 80047F93 ???? 0001:"Greece",0002:"Java",0003:"America",0004:"Siberia",0005:"Comet" cn Press L To Wall Over Water, Climb Hills D00475D9 0020 8104DCD2 0808 crc F568D51E-7E49BA1E-C:45 gn Bomberman 64 (U) cn Invincible\Player 1 800AEE01 0001 cn Have\Pumped up Red Remote Bombs 802AC653 0004 cn Infinite\Lives 802AC627 0063 cn Infinite\Gems 802AC62F 0063 cn Infinite\Credits 802AC62B 0009 cn Infinite\Time 802AC643 0001 cn Carry 20 Bombs At A Time 800AEE0F 0014 cn Infinite\Energy\Player 1 800AEE07 0002 cn Infinite\Energy\Player 2 800AEECF 0002 cn Infinite\Energy\Player 3 800AEF97 0002 cn Infinite\Energy\Player 4 800AF05F 0002 crc 237E73B4-D63B6B37-C:45 gn Bomberman 64 - The Second Attack! (U) cn Infinite\Money 810ABD52 FFFF cn Infinite\Bombs 800AD758 0003 cn Have\Max Fire Level 800AD733 0003 cn Infinite\Health 800AD75F 0005 cn Infinite\Continue Time 810B5CD6 0090 cn Have\Fire Bombs 800AD73B 0003 cn Have\Kick Bombs Anytime 800AC743 0003 cn Flashing Invincible cd This cheat Makes you Flash But you cant be harmed,Once out of danger Turn the cheat off to stop the flashing.also do not put this on if you have already been hurt or you will stay on the floor. 800AD767 000A crc 4446FDD6-E3788208-C:45 gn Bomberman Hero (U) cn Full\Bomb Power 8016523F 0003 cn Full\Fire Power 80165240 0003 cn Infinite\Health 80165244 0004 cn Infinite\Lives 80165243 0009 cn Extra Gems D0165241 0000 80165241 004B cn Max\Bombs 8016523F 0008 cn Press L to Levitate cd Press L to levitate & let go to come back down D005A455 0020 81154178 41CB D005A455 0020 D0154154 0000 80154154 0040 cn Max\Score 80177608 FFFF cn Max\Explosion 80165240 0008 crc 85AE781A-C756F05D-C:45 gn Buck Bumble (U) cn Have All\Guns & Infinite Ammo cd Press C Left to receive all Guns 810FFF8A 0001 50000B04 0000 810E92E6 03E8 cn Infinite\Health cd If you fall into Water just turn off the Infinite Health & put back on after. 810E92D8 42D8 cn Infinite\99 Lives 810E9650 0005 cn Have All\Keys 810E92E0 0101 800E92E2 0001 cn Max Bonus 810E964A 270F cn Level Select 810FFF92 ???? 0001:"Mission 1 Shock Strike",0002:"Mission 2 Radar Run",0003:"Mission 3 Return Fire",0004:"Mission 4 The Sonar Tower",0005:"Mission 5 Big Blips",0006:"Mission 6 Short Fuse",0007:"Mission 7 Outpost",0008:"Mission 8 Sewer",0009:"Mission 9 Clean Up",000A:"Mission 10 Scramble Pylon",000B:"Mission 11 Herding Research",000C:"Mission 12 The Extractor",000D:"Mission 13 Nuke Tower",000E:"Mission 14 Mucus Storage",000F:"Mission 15 Depot Attack",0010:"Boss Mission Destroy Carrier Level",0011:"Mission 16 Sterilization",0012:"Mission 17 Scorpion Killer",0013:"Mission 18 Core Nuke",0014:"Mission 19 Gate Keeper",0015:"Queen Mission" crc 4222D89F-AFE0B637-C:45 gn Bust A Move '99 (U) cn Ceiling Never Drops\Player 1 810ECDEE 0000 cn Ceiling Never Drops\Player 2 810ECEDE 0000 cn Ceiling Never Drops\Player 3 81158846 0000 cn Ceiling Never Drops\Player 4 81158974 0000 cn Infinite Time To Set Pieces\Player 1 810ECE2C 0000 cn Infinite Time To Set Pieces\Player 2 810ECF1C 0000 cn Infinite Time To Set Pieces\Player 3 81158884 0000 cn Infinite Time To Set Pieces\Player 4 81158936 0000 cn Always Gets Bubbles\Player 1 800ECE59 0007 cn Never Gets Bubbles\Player 1 800ECE59 0000 cn Always Gets Bubbles\Player 2 800ECF49 0007 cn Never Gets Bubbles\Player 2 800ECF49 0000 cn Always Gets Bubbles\Player 3 801588B1 0007 cn Never Gets Bubbles\Player 3 801588B1 0000 cn Always Gets Bubbles\Player 4 801589A1 0007 cn Never Gets Bubbles\Player 4 801589A1 0000 crc 8A86F073-CD45E54B-C:45 gn Bust-A-Move 2 - Arcade Edition (U) cn Infinite Credits 80120171 0005 cn Player 1\Always Gets Bubbles 80171131 0006 cn Player 1\Never Gets Bubbles 80171131 0000 cn Computer\Always Gets Bubbles 80173601 0006 cn Computer\Never Gets Bubbles 80173601 0000 cn Player 1\Infinite Time To Set Pieces 8117AAFC 0000 cn Player 1\Screen Never Fills Over Time 80171125 000A crc AC16400E-CF5D071A-C:45 gn California Speed (U) cn Always Place 1st 80151C01 0000 cn Have All\Tracks 81168F8C FFFF cn Have All\Cars 50001504 0000 800AAE5B 0001 crc F35D5F95-8AFE3D69-C:45 gn Castlevania (U) (V1.0) cn Infinite\Health 81389C3E 0064 cn Infinite\Throwing Weapon 81389C48 0064 cn Throwing Weapon Modifier 81389C42 ???? 0000:"Nothing",0001:"Knives",0002:"Exploding Potions",0003:"Cross",0004:"Axes" cn Press L To Levitate D0387D7F 0020 81350810 3FCB cn Have\All Items 50000501 0000 80389C4A 0001 50000301 0000 80389C51 0001 80389C5A 0001 80389C5B 0001 80389C5D 0001 50000E01 0000 80389C60 0001 cn Have\Invincibility 80342BFE 000B cn Infinite\Red Jewels 80389C49 0063 cn Status 80389C88 ???? 0001:"Good",0008:"Vamp",0011:"Poison",0022:"Good but depressed",0066:"Sto",001F:"V+P" cn Open All Doors and Gates,No Bosses 50002A02 0000 81389BD0 FFFF cn Infinite\Energy 80389C3F 0064 cn Infinite\Funds 80389C45 0001 81389C46 869F cn Have\Exp Points 80389C49 0063 cn Max Power Up 80389CED 0002 cn Never Get Poisoned 81389C88 0000 cn Level Select cd You must use this code on a saved game, because the intro to the first level will mess up the game. Now select the saved game, and hold down the GS button until the level loads. Some of the boss stages will not let you fight the boss unless you re-enter the area. Also, with the part of stage modifier, the second code modifies the part of the level that you are in, and 0000 is the level's start. 89389C90 ???? 0000:"Forest of Silence",0002:"Castle Wall",0003:"Villa",0004:"Inside Villa",0006:"Garden Maze",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",0010:"Tower of Execution",0011:"- Tower of Sorcery",0012:"- Tower of Science",0013:"- Duel Tower",0014:"- Fight With Death/Actrise",0015:"- Castle Keep",0016:"- Intro (Glitch)",0017:"- Clock Tower",0018:"- Final Dracula",001A:"- Fight With Maze Boss",001B:"- Room of Clocks",001C:"- ??",001D:"- ??" 89389C92 0000 cn Switch From cd This Switch From Cheat lets you switch characters on a saved game For example, if you are Reindhart and you want to be Carrie in the middle of your game save it and then enable this Cheat and press F1. when you start your saved game back up you'll be Carrie instead of Reindhart. 80389C3D ???? 0000:"Carrie to Reindhart",0001:"Reindhart to Carrie" crc 4BCDFF47-AAA3AF8F-C:45 gn Castlevania (U) (V1.1) cn Infinite\Health 81389C3E 0064 cn Infinite\Throwing Weapon 81389C48 0064 cn Throwing Weapon Modifier 81389C42 ???? 0000:"Nothing",0001:"Knives",0002:"Exploding Potions",0003:"Cross",0004:"Axes" cn Press L To Levitate D0387D7F 0020 81350810 3FCB cn Have\All Items 50000501 0000 80389C4A 0001 50000301 0000 80389C51 0001 80389C5A 0001 80389C5B 0001 80389C5D 0001 50000E01 0000 80389C60 0001 cn Have\Invincibility 80342BFE 000B cn Infinite\Red Jewels 80389C49 0063 cn Status 80389C88 ???? 0001:"Good",0008:"Vamp",0011:"Poison",0022:"Good but depressed",0066:"Sto",001F:"V+P" cn Open All Doors and Gates,No Bosses 50002A02 0000 81389BD0 FFFF cn Infinite\Energy 80389C3F 0064 cn Infinite\Funds 80389C45 0001 81389C46 869F cn Have\Exp Points 80389C49 0063 cn Max Power Up 80389CED 0002 cn Never Get Poisoned 81389C88 0000 cn Level Select cd You must use this code on a saved game, because the intro to the first level will mess up the game. Now select the saved game, and hold down the GS button until the level loads. Some of the boss stages will not let you fight the boss unless you re-enter the area. Also, with the part of stage modifier, the second code modifies the part of the level that you are in, and 0000 is the level's start. 89389C90 ???? 0000:"Forest of Silence",0002:"Castle Wall",0003:"Villa",0004:"Inside Villa",0006:"Garden Maze",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",0010:"Tower of Execution",0011:"- Tower of Sorcery",0012:"- Tower of Science",0013:"- Duel Tower",0014:"- Fight With Death/Actrise",0015:"- Castle Keep",0016:"- Intro (Glitch)",0017:"- Clock Tower",0018:"- Final Dracula",001A:"- Fight With Maze Boss",001B:"- Room of Clocks",001C:"- ??",001D:"- ??" 89389C92 0000 cn Switch From cd This Switch From Cheat lets you switch characters on a saved game For example, if you are Reindhart and you want to be Carrie in the middle of your game save it and then enable this Cheat and press F1. when you start your saved game back up you'll be Carrie instead of Reindhart. 80389C3D ???? 0000:"Carrie to Reindhart",0001:"Reindhart to Carrie" crc 1CC06338-87388926-C:45 gn Castlevania - Legacy of Darkness (U) cn Infinite\Keys\Clocktower A 801CAB6F 000A cn Infinite\Keys\Clocktower B 801CAB70 000A cn Infinite\Keys\Storeroom 801CAB60 000A cn Infinite\Keys\Garden 801CAB61 000A cn Infinite\Keys\Copper 801CAB62 000A cn Infinite\Keys\Chamber 801CAB63 000A cn Infinite\Keys\Execution 801CAB64 000A cn Infinite\Keys\Deck 801CAB65 000A cn Infinite\Keys\Rose Garden 801CAB66 000A cn Infinite\Keys\Thorn 801CAB67 000A cn Infinite\Keys\Clocktower C 801CAB68 000A cn Infinite\Keys\Clocktower D 801CAB69 000A cn Infinite\Keys\Art Tower 1 801CAB6A 000A cn Infinite\Keys\Art Tower 2 801CAB6B 000A cn Infinite\Keys\Control Room 801CAB6C 000A cn Infinite\Keys\Wall 801CAB6D 000A cn Infinite\Keys\Clocktower E 801CAB6E 000A cn Infinite\Keys\Archives 801CAB5E 000A cn Infinite\Keys\Left Tower 801CAB5F 000A cn Infinite\Health 811CAB3A 2710 cn Infinite\Gold 811CAB42 2710 cn Infinite\Specials\Special 1 801CAB47 000A cn Infinite\Specials\Special 2 801CAB48 000A cn Infinite\Specials\Special 3 801CAB49 000A cn Infinite\Items\Roast Chicken 801CAB4A 000A cn Infinite\Items\Roast Beef 801CAB4B 000A cn Infinite\Items\Healing Kit 801CAB4C 000A cn Infinite\Items\Purifying 801CAB4D 000A cn Infinite\Items\Cure Ampoule 801CAB4E 000A cn Infinite\Items\Powerup 801CAB4F 000A cn Infinite\Items\The Contract 801CAB54 000A cn Infinite\Items\Magical Nitro 801CAB55 000A cn Infinite\Items\Mandragora 801CAB56 000A cn Infinite\Items\Sun Card 801CAB57 000A cn Infinite\Items\Moon Card 801CAB58 000A cn Infinite\Items\Winch Lever 801CAB59 000A cn Infinite\Items\Oldrey's Diary 801CAB5A 000A cn Infinite\Items\Crest Half A 801CAB5B 000A cn Infinite\Items\Crest Half B 801CAB5C 000A cn Infinite\Items\Rose Brooch 801CAB5D 000A cn Infinite\Items\Throwing Weapons 801CAB45 0064 cn Infinite\Items\Red Jewels 801CAB45 0068 cn Infinite\Bullets cd For Henry 801D3DA3 0006 cn Wolfman Can Use Weapons cd For Cornell 801CAB37 0002 cn Wolfman Can't Use Weapons cd For Cornell (Default) 801CAB37 0004 cn Rapid Fire Gun (Henry-Hold B) cd For Henry, Hold B D11C87F6 0040 801D3DA3 0006 cn Max Powerups 801CAE23 0002 cn Stop Timer Input 811CAB22 0001 cn Hard Mode Selected In A New Game cd With this code, you will not see the hard level status until you save and restart the game file. No special items are required to access this feature with this code turned on. 8032495F 0002 cn Weapon Modifier 811CAB3E ???? 0000:"Nothing",0001:"Knife",0002:"Potion",0003:"Cross",0004:"Axe" cn Level Modifier 801CAE79 ???? 0000:"Forest Of Silence",0001:"Left Tower",0002:"Castle Wall",0003:"Villa",0004:"Villa",0005:"Villa",0006:"Villa",001A:"Villa",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",000A:"Castle Center",000B:"Castle Center",000C:"Castle Center",000D:"Castle Center",000E:"Castle Center",000F:"Castle Center",0010:"Foggy Lake",0011:"Foggy Lake",0012:"Foggy Lake",0013:"Cave Of Spiderwomen",0014:"Castle Keep",0015:"Castle Keep",0016:"Falls Into Space(?)",0017:"Clock Tower",0018:"Final Battle Site",0019:"Castle Center",001B:"Room Of Clocks",001C:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",002B:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",001D:"Tower Of Sorcery",001E:"Tower Of Execution",001F:"Tower Of Execution",0020:"Tower Of Execution",0021:"Tower Of Science",0022:"Tower Of Science",0023:"Tower Of Ruins",0024:"Tower Of Ruins",0025:"Art Tower",0026:"Art Tower",0027:"Dual Tower",0028:"Clock Tower",0029:"Clock Tower",002A:"Outer Wall",002C:"Fall From Sky Ouside Of Castlevania Opening",002D:"Another Free Fall. Forest Where Girl Runs In Opening",002E:"Black Room(?)" cn Inter-Level Modifier 801CAE7B ???? 0000:"Forest Of Silence",0001:"Left Tower",0002:"Castle Wall",0003:"Villa",0004:"Villa",0005:"Villa",0006:"Villa",001A:"Villa",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",000A:"Castle Center",000B:"Castle Center",000C:"Castle Center",000D:"Castle Center",000E:"Castle Center",000F:"Castle Center",0010:"Foggy Lake",0011:"Foggy Lake",0012:"Foggy Lake",0013:"Cave Of Spiderwomen",0014:"Castle Keep",0015:"Castle Keep",0016:"Falls Into Space(?)",0017:"Clock Tower",0018:"Final Battle Site",0019:"Castle Center",001B:"Room Of Clocks",001C:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",002B:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",001D:"Tower Of Sorcery",001E:"Tower Of Execution",001F:"Tower Of Execution",0020:"Tower Of Execution",0021:"Tower Of Science",0022:"Tower Of Science",0023:"Tower Of Ruins",0024:"Tower Of Ruins",0025:"Art Tower",0026:"Art Tower",0027:"Dual Tower",0028:"Clock Tower",0029:"Clock Tower",002A:"Outer Wall",002C:"Fall From Sky Ouside Of Castlevania Opening",002D:"Another Free Fall. Forest Where Girl Runs In Opening",002E:"Black Room(?)" cn Cut Scene Modifier cd With this code, you must use the appropiate level mod before you attemp to run these cut scenes. Not doing so will ruin the cut scene as the graphics will be glitched. 801CAE93 0009 801CAE8B ???? 0003:"Castle Drawbridge Lowers",0004:"Character Enters Castle",0005:"(?)",000A:"(?)",000C:"(?)",0020:"(?)",0021:"(?)",0022:"(?)",0006:"Vampire In Main Entrance Hall Of Villa",0007:"One Of The Working Gears Cut Scenes",0008:"\"I Smell Poison\" From Underground Waterway",0009:"Castle Gate Closes In Villa Upon Entering Villa",000B:"Renon Appears For First Time",000D:"Village Vampire In Upstairs Villa",000E:"Malus Appears For The First Time",000F:"Malus Leaves Garden",0010:"Character In Boat On Foggy Lake",0011:"Seal Removed From Wall In Arena",0012:"Bleeding Statue",0013:"Cosmic Lights",0014:"Explosion At Wall In Arena",0015:"Explosion At Wall In Castle That Leads To Hidden Room",0016:"Malus Appears Again In Upstairs Room Of Castle",0017:"Bull Awakens",0018:"Vincent The Vampire",0019:"One Of The Working Gears Cut Scenes",001A:"Gate Opens In Forest Of Silence",001B:"Meet Renon For The Last Time In Castle Keep.",001C:"This Cut Scene Runs Cut Scene 27 And 2E",001E:"Castle Keep Destructs",001F:"Malus On Flying Horse Outside Castle Keep",0024:"Spider People In Tunnel",0025:"Rosa In Garden",0027:"Castel Destruction",0028:"Space Warp",0029:"Castle Destruction",002A:"Malus Is Saved By Reinhardt",002B:"Malus And Reinhardt On Horse",002E:"Rosa Returns",0030:"Ada, Henry And Cornell At Game End",0031:"Scrolling Text About Castle And Henry",0033:"Vampire In Basement",0034:"Vampire In Villa Basement Destroyed, Woman Vampire Rises",0035:"Finds Hidden Path In Villa Basement",0037:"Lever & Gear In Castle",0038:"Harpie",0039:"Harpie Destroyed",0044:"Death(Grim Reaper)",0045:"Death Is Destroyed",0046:"Castle Drawbridge Closes And Ortega Appears",0047:"Thirsty Man",0048:"Cornell Meets Henry In Garden",0049:"Cornell And Henry Part In Garden",0051:"Monster Dracula Appears",0052:"Actrise Appears In Castle Center",0054:"Actrise Appears Again With Cousin Fernandes Before Fight With Carrie",0055:"Cousin Fernandes Is Destroyed",0056:"Actrise Appears Again Before Fight With Carrie",0057:"Actrise Defeated By Carrie" cn Enable Characters All Charactors 8031B243 0004 cn Character Modifier 8031B22B ???? 0000:"Cornell",0001:"Reinhardt",0002:"Carrie",0003:"Henry" cn Status Modifier 801CAB84 ???? 0000:"Never Get Poisoned or Vamped",0001:"Normal",0004:"Vamp",0008:"Poison",000C:"Vamped & Poisoned",00FF:"Instant Death" cn Max Weapon Power-Up 801CAE27 0002 cn Day Modifier For Adult Henry 801CAB1F ???? 0000:"7 Days",0001:"6 Days",0002:"5 Days",0003:"4 Days",0004:"3 Days",0005:"2 Days",0006:"1 Day",0007:"0 Days" cn Infinite\Health Young Henry D11C87F6 0010 813A5360 2800 crc 6420535A-50028062-C:45 gn Chameleon Twist (U) cn Access All Levels 8020850E 00FF 80208510 00FF cn Extra Crowns 80251767 0015 cn Infinite Health 80174CF3 000A cn Extended Tongue 8133176E FFFF cn Level Select 8029087B ???? 0000:"Stage 1",0001:"Stage 2",0002:"Stage 3",0003:"Stage 4",0004:"Stage 5",0005:"Stage 6",0006:"Stage 7" crc CD538CE4-618AFCF9-C:45 gn Chameleon Twist 2 (U) cn Infinite Health 8018BA7D 000F cn Max Collectable Items 80164501 0014 cn Have 6 Carrots 80164519 007E cn Have All\Levels 80164508 003F cn Have All\Costumes 8016451A 00FE cn Have All\Collectibles\Stage 1 80164510 0014 cn Have All\Collectibles\Stage 2 80164511 0014 cn Have All\Collectibles\Stage 3 80164512 0014 cn Have All\Collectibles\Stage 4 80164513 0014 cn Have All\Collectibles\Stage 5 80164514 0014 cn Have All\Collectibles\Stage 6 80164515 0014 cn Press L To levitate cd Press L To Levitate & Let go to land D018BAB5 0020 8118B9E0 4200 crc 1E0E96E8-4E28826B-C:45 gn Charlie Blast's Territory (U) cn Stop Timer From Counting Down (All Levels) 8101D4FC 2400 crc 214CAD94-BE1A3B24-C:45 gn Chopper Attack (U) cn Max Score 81129426 FFFF cn Infinite Weapon\1st Position 8012943B 0063 cn Infinite Weapon\2nd Position 8012943F 0063 cn Infinite Weapon\3rd Position 80129443 0063 cn Infinite Weapon\4th Position 80129447 0063 cn Infinite Weapon\5th Position 8012944B 0063 cn Weapon Modifier\Gun Weapon 80129723 ???? 0000:"No Weapon",0001:"Normal Shot",0002:"2-Way Shot",0003:"3-Way Shot",0004:"4-Way Shot" cn Gun 4-Way Shot 80129723 0004 cn Infinite Fuel 81129726 FFFF cn Infinite Shield 811296C8 03E8 cn Opens All 5 Item Slots 8012945B 0005 cn Weapon Modifier\1st Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 80129439 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\2nd Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 8012943D ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\3rd Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 801294F1 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\4th Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 801294F5 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\5th Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 801294F9 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Score Attack Mode 81129472 0001 cn Stage Select On 81129476 0001 cn Option On 8112947A 0001 cn Clear Mission Selector 8112947C ???? 0001:"1",0002:"2",0003:"3",0004:"4",0005:"5",0006:"6",0007:"7",0008:"8" cn Texture Mode 81129484 0001 crc F03C24CA-C5237BCC-C:45 gn Clay Fighter 63 1-3 (U) cn Extra Characters/Secret Options 801A2B41 000F cn Stage Modifier 801A2B2B ???? 0000:"Candy Factory",0001:"Claynaveral Hangar",0002:"Camp Claynaveral",0003:"Outhouse",0004:"Mudville Mansion",0005:"Ghastly Graveyard",0006:"Spooky Spire",0007:"Happy Harry's Hut",0008:"Freezing Fortress",0009:"Refuse Room",000A:"Grotto Gulch",000B:"Rubbage Room",000C:"Rubbage Reef",000D:"Kiln's Laboratory",000E:"Kiln's Hideout",000F:"Fiery Furnace",0010:"Research Room",0011:"Clayribbean Cruise",0012:"Santa's Workship",0013:"Kooky Courtyard",0014:"Santa's Toy Factory",0015:"Boogerhenge",0016:"Backwash Bay",0017:"Tureen Toilet",0018:"Tribal Tower",0019:"Aquadome" cn Infinite Time To Choose Your Fighter 81200BEC 03A7 cn Player 1 Character Modifier 801A2B2F ???? 0001:"Blob",0002:"Bonker",0003:"Boogerman",0004:"Dr. Kiln",0005:"Earthworm Jim",0008:"Houngan",0009:"Icky Bod Clay",000A:"Kung Pow",000D:"Sumo Santa",000E:"Taffy",000F:"T-Hoppy" cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 1\Cant be Stunned 801F1B0B 0000 cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 1\Infinite Energy 801F1B13 00AA cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 1\No Energy 801F1B13 0000 cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 1\Full Super Bar 811F1B1A 0200 cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 2\Cant be Stunned 801F4FAB 0000 cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 2\Infinite Energy 801F4FB3 00AA cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 2\No Energy 801F4FB3 0000 cn Refuse Room, Grotto Gulch, Santa's Worshop\Player 2\Full Super Bar 811F4FBA 0200 cn Tribal Tower\Player 1\Cant be Stunned 801F1BAB 0000 cn Tribal Tower\Player 1\Infinite Energy 801F1BB3 00AA cn Tribal Tower\Player 1\No Energy 801F1BB3 0000 cn Tribal Tower\Player 1\Full Super Bar 811F1BBA 0200 cn Tribal Tower\Player 2\Cant be Stunned 801F504B 0000 cn Tribal Tower\Player 2\Infinite Energy 801F5053 00AA cn Tribal Tower\Player 2\No Energy 801F5053 0000 cn Tribal Tower\Player 2\Full Super Bar 811F505A 0200 cn Aquadome\Player 1\Cant be Stunned 801F1E3B 0000 cn Aquadome\Player 1\Infinite Energy 801F1E33 00AA cn Aquadome\Player 1\No Energy 801F1E33 0000 cn Aquadome\Player 1\Full Super Bar 811F1E3A 0200 cn Aquadome\Player 2\Cant be Stunned 801F52CB 0000 cn Aquadome\Player 2\Infinite Energy 801F52D3 00AA cn Aquadome\Player 2\No Energy 801F52D3 0000 cn Aquadome\Player 2\Full Super Bar 811F52DA 0200 cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 1\Cant be Stunned 801F233B 0000 cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 1\Infinite Energy 801F2343 00AA cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 1\No Energy 801F2343 0000 cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 1\Full Super Bar 811F234A 0200 cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 2\Cant be Stunned 801F57DB 0000 cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 2\Infinite Energy 801F57E3 00AA cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 2\No Energy 801F57E3 0000 cn Outhouse,Claynaveral Hangar,Camp Claynaveral\Player 2\Full Super Bar 811F57EA 0200 cn Freezing Fortress\Player 1\Cant be Stunned 801F239B 0000 cn Freezing Fortress\Player 1\Infinite Energy 801F23A3 00AA cn Freezing Fortress\Player 1\No Energy 801F23A3 0000 cn Freezing Fortress\Player 1\Full Super Bar 811F23AA 0200 cn Freezing Fortress\Player 2\Cant be Stunned 801F583B 0000 cn Freezing Fortress\Player 2\Infinite Energy 801F5843 00AA cn Freezing Fortress\Player 2\No Energy 801F5843 0000 cn Freezing Fortress\Player 2\Full Super Bar 811F584A 0200 cn Rubbage Reef\Player 1\Cant be Stunned 801F241B 0000 cn Rubbage Reef\Player 1\Infinite Energy 801F2423 00AA cn Rubbage Reef\Player 1\No Energy 801F2423 0000 cn Rubbage Reef\Player 1\Full Super Bar 811F242A 0200 cn Rubbage Reef\Player 2\Cant be Stunned 801F58BB 0000 cn Rubbage Reef\Player 2\Infinite Energy 801F58C3 00AA cn Rubbage Reef\Player 2\No Energy 801F58C3 0000 cn Rubbage Reef\Player 2\Full Super Bar 811F58CA 0200 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 1\Cant be Stunned 801F244B 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 1\Infinite Energy 801F2453 00AA cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 1\No Energy 801F2453 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 1\Full Super Bar 811F245A 0200 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 2\Cant be Stunned 801F58EB 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 2\Infinite Energy 801F58F3 00AA cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 2\No Energy 801F58F3 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion\Player 2\Full Super Bar 811F58FA 0200 cn Clayribbean Cruise\Player 1\Cant be Stunned 801F24FB 0000 cn Clayribbean Cruise\Player 1\Infinite Energy 801F2503 00AA cn Clayribbean Cruise\Player 1\No Energy 801F2503 0000 cn Clayribbean Cruise\Player 1\Full Super Bar 811F250A 0200 cn Clayribbean Cruise\Player 2\Cant be Stunned 801F599B 0000 cn Clayribbean Cruise\Player 2\Infinite Energy 801F59A3 00AA cn Clayribbean Cruise\Player 2\No Energy 801F59A3 0000 cn Clayribbean Cruise\Player 2\Full Super Bar 811F59AA 0200 cn Backwash Bay\Player 1\Cant be Stunned 801F258B 0000 cn Backwash Bay\Player 1\Infinite Energy 801F2593 00AA cn Backwash Bay\Player 1\No Energy 801F2593 0000 cn Backwash Bay\Player 1\Full Super Bar 811F259A 0200 cn Backwash Bay\Player 2\Cant be Stunned 801F5A2B 0000 cn Backwash Bay\Player 2\Infinite Energy 801F5A33 00AA cn Backwash Bay\Player 2\No Energy 801F5A33 0000 cn Backwash Bay\Player 2\Full Super Bar 811F5A3A 0200 cn Ghastly Graveyard\Player 1\Cant be Stunned 801F262B 0000 cn Ghastly Graveyard\Player 1\Infinite Energy 801F2633 00AA cn Ghastly Graveyard\Player 1\No Energy 801F2633 0000 cn Ghastly Graveyard\Player 1\Full Super Bar 811F263A 0200 cn Ghastly Graveyard\Player 2\Cant be Stunned 801F5ACB 0000 cn Ghastly Graveyard\Player 2\Infinite Energy 801F5AD3 00AA cn Ghastly Graveyard\Player 2\No Energy 801F5AD3 0000 cn Ghastly Graveyard\Player 2\Full Super Bar 811F5ADA 0200 cn Candy Factory\Player 1\Cant be Stunned 801F270B 0000 cn Candy Factory\Player 1\Infinite Energy 801F2713 00AA cn Candy Factory\Player 1\No Energy 801F2713 0000 cn Candy Factory\Player 1\Full Super Bar 811F271A 0200 cn Candy Factory\Player 2\Cant be Stunned 801F5BAB 0000 cn Candy Factory\Player 2\Infinite Energy 801F5BB3 00AA cn Candy Factory\Player 2\No Energy 801F5BB3 0000 cn Candy Factory\Player 2\Full Super Bar 811F5BBA 0200 cn Kooky Courtyard\Player 1\Cant be Stunned 801F280B 0000 cn Kooky Courtyard\Player 1\Infinite Energy 801F2813 00AA cn Kooky Courtyard\Player 1\No Energy 801F2813 0000 cn Kooky Courtyard\Player 1\Full Super Bar 811F281A 0200 cn Kooky Courtyard\Player 2\Cant be Stunned 801F5CAB 0000 cn Kooky Courtyard\Player 2\Infinite Energy 801F5CB3 00AA cn Kooky Courtyard\Player 2\No Energy 801F5CB3 0000 cn Kooky Courtyard\Player 2\Full Super Bar 811F5CBA 0200 cn Santa's Toy Factory\Player 1\Cant be Stunned 801F2C3B 0000 cn Santa's Toy Factory\Player 1\Infinite Energy 801F2C43 00AA cn Santa's Toy Factory\Player 1\No Energy 801F2C43 0000 cn Santa's Toy Factory\Player 1\Full Super Bar 811F2C4A 0200 cn Santa's Toy Factory\Player 2\Cant be Stunned 801F60DB 0000 cn Santa's Toy Factory\Player 2\Infinite Energy 801F60E3 00AA cn Santa's Toy Factory\Player 2\No Energy 801F60E3 0000 cn Santa's Toy Factory\Player 2\Full Super Bar 811F60EA 0200 cn Boogerhenge, Tureen Toilet\Player 1\Cant be Stunned 801F2FDB 0000 cn Boogerhenge, Tureen Toilet\Player 1\Infinite Energy 801F2FE3 00AA cn Boogerhenge, Tureen Toilet\Player 1\No Energy 801F2FE3 0000 cn Boogerhenge, Tureen Toilet\Player 1\Full Super Bar 811F2FEA 0200 cn Boogerhenge, Tureen Toilet\Player 2\Cant be Stunned 801F647B 0000 cn Boogerhenge, Tureen Toilet\Player 2\Infinite Energy 801F6483 00AA cn Boogerhenge, Tureen Toilet\Player 2\No Energy 801F6483 0000 cn Boogerhenge, Tureen Toilet\Player 2\Full Super Bar 811F648A 0200 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 1\Cant be Stunned 801F3BBB 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 1\Infinite Energy 801F3BC3 00AA cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 1\No Energy 801F3BC3 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 1\Full Super Bar 811F3BCA 0200 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 2\Cant be Stunned 801F705B 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 2\Infinite Energy 801F7063 00AA cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 2\No Energy 801F7063 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room\Player 2\Full Super Bar 811F706A 0200 cn Rubbage Room\Player 1\Cant be Stunned 801F464B 0000 cn Rubbage Room\Player 1\Infinite Energy 801F4653 00AA cn Rubbage Room\Player 1\No Energy 801F4653 0000 cn Rubbage Room\Player 1\Full Super Bar 811F465A 0200 cn Rubbage Room\Player 2\Cant be Stunned 801F7AEB 0000 cn Rubbage Room\Player 2\Infinite Energy 801F7AF3 00AA cn Rubbage Room\Player 2\No Energy 801F7AF3 0000 cn Rubbage Room\Player 2\Full Super Bar 811F7AFA 0200 crc FA5A3DFF-B4C9CDB9-C:45 gn Clay Fighter - Sculptor's Cut (U) cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 1\Cant be Stunned 801939FF 0000 cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 1\Infinite Health 80193A07 00AA cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 1\No Health 80193A07 0000 cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 1\Full Super Bar 81193A0E 0200 cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 2\Cant be Stunned 80196EEF 0000 cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 2\Infinite Health 80196EF7 00AA cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 2\No Health 80196EF7 0000 cn Santa's Workshop, Refuse Room, Grotto Gulch\Player 2\Full Super Bar 81196EFE 0200 cn Tribal Tower\Player 1\Cant be Stunned 80193A9F 0000 cn Tribal Tower\Player 1\Infinite Health 80193AA7 00AA cn Tribal Tower\Player 1\No Health 80193AA7 0000 cn Tribal Tower\Player 1\Full Super Bar 81193AAE 0200 cn Tribal Tower\Player 2\Cant be Stunned 80196F8F 0000 cn Tribal Tower\Player 2\Infinite Health 80196F97 00AA cn Tribal Tower\Player 2\No Health 80196F97 0000 cn Tribal Tower\Player 2\Full Super Bar 81196F9E 0200 cn Aquadome\Player 1\Cant be Stunned 80193D1F 0000 cn Aquadome\Player 1\Infinite Health 80193D27 00AA cn Aquadome\Player 1\No Health 80193D27 0000 cn Aquadome\Player 1\Full Super Bar 81193D2E 0200 cn Aquadome\Player 2\Cant be Stunned 8019720F 0000 cn Aquadome\Player 2\Infinite Health 80197217 00AA cn Aquadome\Player 2\No Health 80197217 0000 cn Aquadome\Player 2\Full Super Bar 8119721E 0200 cn Clayribbean Cruise\Player 1\Cant be Stunned 80193F3F 0000 cn Clayribbean Cruise\Player 1\Infinite Health 80193F47 00AA cn Clayribbean Cruise\Player 1\No Health 80193F47 0000 cn Clayribbean Cruise\Player 1\Full Super Bar 81193F4E 0200 cn Clayribbean Cruise\Player 2\Cant be Stunned 8019742F 0000 cn Clayribbean Cruise\Player 2\Infinite Health 80197437 00AA cn Clayribbean Cruise\Player 2\No Health 80197437 0000 cn Clayribbean Cruise\Player 2\Full Super Bar 8119743E 0200 cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 1\Cant be Stunned 8019422F 0000 cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 1\Infinite Health 80194237 00AA cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 1\No Health 80194237 0000 cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 1\Full Super Bar 8119423E 0200 cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 2\Cant be Stunned 8019771F 0000 cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 2\Infinite Health 80197727 00AA cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 2\No Health 80197727 0000 cn Camp Claynaveral, ClayNaveral Hangar, OutHouse\Player 2\Full Super Bar 8119772E 0200 cn Freezing Fortress\Player 1\Cant be Stunned 8019428F 0000 cn Freezing Fortress\Player 1\Infinite Health 80194297 00AA cn Freezing Fortress\Player 1\No Health 80194297 0000 cn Freezing Fortress\Player 1\Full Super Bar 8119429E 0200 cn Freezing Fortress\Player 2\Cant be Stunned 8019777F 0000 cn Freezing Fortress\Player 2\Infinite Health 80197787 00AA cn Freezing Fortress\Player 2\No Health 80197787 0000 cn Freezing Fortress\Player 2\Full Super Bar 8119778E 0200 cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 1\Cant be Stunned 8019433F 0000 cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 1\Infinite Health 80194347 00AA cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 1\No Health 80194347 0000 cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 1\Full Super Bar 8119434E 0200 cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 2\Cant be Stunned 8019782F 0000 cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 2\Infinite Health 80197837 00AA cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 2\No Health 80197837 0000 cn Spooky Spire, Happy Harry's Hut, Mudville Mansion\Player 2\Full Super Bar 8119783E 0200 cn Rubbage Reef Code\Player 1\Cant be Stunned 8019430F 0000 cn Rubbage Reef Code\Player 1\Infinite Health 80194317 00AA cn Rubbage Reef Code\Player 1\No Health 80194317 0000 cn Rubbage Reef Code\Player 1\Full Super Bar 8119431E 0200 cn Rubbage Reef Code\Player 2\Cant be Stunned 801977FF 0000 cn Rubbage Reef Code\Player 2\Infinite Health 80197807 00AA cn Rubbage Reef Code\Player 2\No Health 80197807 0000 cn Rubbage Reef Code\Player 2\Full Super Bar 8119780E 0200 cn Backwash Bay\Player 1\Cant be Stunned 8019447F 0000 cn Backwash Bay\Player 1\Infinite Health 80194487 00AA cn Backwash Bay\Player 1\No Health 80194487 0000 cn Backwash Bay\Player 1\Full Super Bar 8119448E 0200 cn Backwash Bay\Player 2\Cant be Stunned 8019796F 0000 cn Backwash Bay\Player 2\Infinite Health 80197977 00AA cn Backwash Bay\Player 2\No Health 80197977 0000 cn Backwash Bay\Player 2\Full Super Bar 8119797E 0200 cn Ghastly Graveyard\Player 1\Cant be Stunned 8019451F 0000 cn Ghastly Graveyard\Player 1\Infinite Health 80194527 00AA cn Ghastly Graveyard\Player 1\No Health 80194527 0000 cn Ghastly Graveyard\Player 1\Full Super Bar 8119452E 0200 cn Ghastly Graveyard\Player 2\Cant be Stunned 80197A0F 0000 cn Ghastly Graveyard\Player 2\Infinite Health 80197A17 00AA cn Ghastly Graveyard\Player 2\No Health 80197A17 0000 cn Ghastly Graveyard\Player 2\Full Super Bar 81197A1E 0200 cn Candy Factory\Player 1\Cant be Stunned 801945FF 0000 cn Candy Factory\Player 1\Infinite Health 80194607 00AA cn Candy Factory\Player 1\No Health 80194607 0000 cn Candy Factory\Player 1\Full Super Bar 8119460E 0200 cn Candy Factory\Player 2\Cant be Stunned 80197AEF 0000 cn Candy Factory\Player 2\Infinite Health 80197AF7 00AA cn Candy Factory\Player 2\No Health 80197AF7 0000 cn Candy Factory\Player 2\Full Super Bar 81197AFE 0200 cn Kooky Courtyard\Player 1\Cant be Stunned 801946FF 0000 cn Kooky Courtyard\Player 1\Infinite Health 80194707 00AA cn Kooky Courtyard\Player 1\No Health 80194707 0000 cn Kooky Courtyard\Player 1\Full Super Bar 8119470E 0200 cn Kooky Courtyard\Player 2\Cant be Stunned 80197BEF 0000 cn Kooky Courtyard\Player 2\Infinite Health 80197BF7 00AA cn Kooky Courtyard\Player 2\No Health 80197BF7 0000 cn Kooky Courtyard\Player 2\Full Super Bar 81197BFE 0200 cn Santa's Toy Factory\Player 1\Cant be Stunned 80194B2F 0000 cn Santa's Toy Factory\Player 1\Infinite Health 80194B37 00AA cn Santa's Toy Factory\Player 1\No Health 80194B37 0000 cn Santa's Toy Factory\Player 1\Full Super Bar 81194B3E 0200 cn Santa's Toy Factory\Player 2\Cant be Stunned 8019801F 0000 cn Santa's Toy Factory\Player 2\Infinite Health 80198027 00AA cn Santa's Toy Factory\Player 2\No Health 80198027 0000 cn Santa's Toy Factory\Player 2\Full Super Bar 8119802E 0200 cn Boogerhenge, Tureen Toilet\Player 1\Cant be Stunned 80194ECF 0000 cn Boogerhenge, Tureen Toilet\Player 1\Infinite Health 80194ED7 00AA cn Boogerhenge, Tureen Toilet\Player 1\No Health 80194ED7 0000 cn Boogerhenge, Tureen Toilet\Player 1\Full Super Bar 81194EDE 0200 cn Boogerhenge, Tureen Toilet\Player 2\Cant be Stunned 801983BF 0000 cn Boogerhenge, Tureen Toilet\Player 2\Infinite Health 801983C7 00AA cn Boogerhenge, Tureen Toilet\Player 2\No Health 801983C7 0000 cn Boogerhenge, Tureen Toilet\Player 2\Full Super Bar 811983CE 0200 cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 1\Cant be Stunned 80195AAF 0000 cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 1\Infinite Health 80195AB7 00AA cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 1\No Health 80195AB7 0000 cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 1\Full Super Bar 81195ABE 0200 cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 2\Cant be Stunned 80198F9F 0000 cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 2\Infinite Health 80198FA7 00AA cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 2\No Health 80198FA7 0000 cn Dr. Kiln's Laboratory, Research Room, Kilns Hideout, Fiery Furnace\Player 2\Full Super Bar 81198FAE 0200 cn Dog House\Player 1\Cant be Stunned 8019653F 0000 cn Dog House\Player 1\Infinite Health 80196547 00AA cn Dog House\Player 1\No Health 80196547 0000 cn Dog House\Player 1\Full Super Bar 8119654E 0200 cn Dog House\Player 2\Cant be Stunned 80199A2F 0000 cn Dog House\Player 2\Infinite Health 80199A37 00AA cn Dog House\Player 2\No Health 80199A37 0000 cn Dog House\Player 2\Full Super Bar 81199A3E 0200 cn VS. Mode\Player 1\Cant be Stunned 8019195F 0000 cn VS. Mode\Player 1\Infinite Health 80199167 00AA cn VS. Mode\Player 1\No Health 80199167 0000 cn VS. Mode\Player 1\Full Super Bar 8119916E 0200 cn VS. Mode\Player 2\Cant be Stunned 80194E4F 0000 cn VS. Mode\Player 2\Infinite Health 80194E57 00AA cn VS. Mode\Player 2\No Health 80194E57 0000 cn VS. Mode\Player 2\Full Super Bar 81194E5E 0200 cn Other Codes\Have High Five 810AA0BE 0001 cn Other Codes\Have Earth Worm Jim 810AA0E2 0001 cn Other Codes\Have Sumo Santa 810AA106 0001 cn Other Codes\Have Booger Man 810AA12A 0001 cn Other Codes\Debug Mode cd With this code, Press C-Up & C-Down to pick your stage. 810AA1A6 0001 cn Other Codes\Difficulty Modifier 810AE40A ???? 0000:"Cookie",0001:"Easy",0002:"Normal",0003:"Dude",0004:"Psycho" cn Other Codes\Time Limit Modifier 800AE423 ???? 0000:"On",0001:"Off" cn Other Codes\Throws & Holds Modifier 800AE42F ???? 0000:"On",0001:"Off" cn Other Codes\VS. Arena Select Modifier 800AE43B ???? 0000:"Random",0001:"Normal" cn Other Codes\Spillits Modifier 800AE447 ???? 0000:"Normal",0001:"Psycho" cn Other Codes\Health Meters Modifier 800AE5EF ???? 0000:"Off",0001:"On" cn Other Codes\Stun Meters Modifier 800AE5FB ???? 0000:"Off",0001:"On" cn Other Codes\Super Meters Modifier 800AE607 ???? 0000:"Off",0001:"On" cn Other Codes\Portraits Modifier 800AE613 ???? 0000:"Off",0001:"On" crc 2B6FA7C0-09A71225-C:45 gn Clay Fighter 63 1-3 (U) (beta) cn Extra Characters and Secret Options 8019ED41 000F cn Stage Select 8019ED2B ???? 0000:"Candy Factory",0001:"Claynaveral Hangar",0002:"Camp Claynaveral",0003:"Outhouse",0004:"Mudville Mansion",0005:"Ghastly Graveyard",0006:"Spooky Spire",0007:"Happy Harry's Hut",0008:"Freezing Fortress",0009:"Refuse Room",000A:"Grotto Gulch",000B:"Rubbage Room",000C:"Rubbage Reef",000D:"Kiln's Laboratory",000E:"Kiln's Hideout",000F:"Fiery Furnace",0010:"Research Room",0011:"Clayribbean Cruise",0012:"Santa's Workship",0013:"Kooky Courtyard",0014:"Santa's Toy Factory",0015:"Boogerhenge",0016:"Backwash Bay",0017:"Tureen Toilet",0018:"Tribal Tower",0019:"Aquadome" cn Play As\Player1 8019ED2F ???? 0000:"Bad Mr. Frosty",0001:"Blob",0002:"Bonker",0003:"Boogerman",0004:"Dr. Kiln",0005:"Earthworm Jim",0008:"Houngan",0009:"Icky Bod Clay",000A:"Kung Pow",000D:"Sumo Santa",000E:"Taffy",000F:"T-Hoppy" cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Can't be Stunned\Player 1 801EDCE3 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Infinite Energy\Player 1 801EDCEB 00AA cn Refuse Room, Grotto Gulch, Santa's Workship Stages\No Energy\Player 1 801EDCEB 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Full Super Bar\Player 1 811EDCF2 0200 cn Tribal Tower Stage\Can't be Stunned\Player 1 801EDD83 0000 cn Tribal Tower Stage\Infinite Energy\Player 1 801EDD8B 00AA cn Tribal Tower Stage\No Energy\Player 1 801EDD8B 0000 cn Tribal Tower Stage\Full Super Bar\Player 1 811EDD92 0200 cn Aquadome Stage\Can't be Stunned\Player 1 801EE013 0000 cn Aquadome Stage\Infinite Energy\Player 1 801EE00B 00AA cn Aquadome Stage\No Energy\Player 1 801EE00B 0000 cn Aquadome Stage\Full Super Bar\Player 1 811EE012 0200 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Can't be Stunned\Player 1 801EE513 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Infinite Energy\Player 1 801EE51B 00AA cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\No Energy\Player 1 801EE51B 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Full Super Bar\Player 1 811EE522 0200 cn Freezing Fortress Stage\Can't be Stunned\Player 1 801EE573 0000 cn Freezing Fortress Stage\Infinite Energy\Player 1 801EE57B 00AA cn Freezing Fortress Stage\No Energy\Player 1 801EE57B 0000 cn Freezing Fortress Stage\Full Super Bar\Player 1 811EE582 0200 cn Rubbage Reef Stage\Can't be Stunned\Player 1 801EE5F3 0000 cn Rubbage Reef Stage\Infinite Energy\Player 1 801EE5FB 00AA cn Rubbage Reef Stage\No Energy\Player 1 801EE5FB 0000 cn Rubbage Reef Stage\Full Super Bar\Player 1 811EE602 0200 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Can't be Stunned\Player 1 801EE623 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Infinite Energy\Player 1 801EE62B 00AA cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\No Energy\Player 1 801EE62B 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Full Super Bar\Player 1 811EE632 0200 cn Clayribbean Cruise Stage\Can't be Stunned\Player 1 801EE6D3 0000 cn Clayribbean Cruise Stage\Infinite Energy\Player 1 801EE6DB 00AA cn Clayribbean Cruise Stage\No Energy\Player 1 801EE6DB 0000 cn Clayribbean Cruise Stage\Full Super Bar\Player 1 811EE6E2 0200 cn Backwash Bay Stage\Can't be Stunned\Player 1 801EE763 0000 cn Backwash Bay Stage\Infinite Energy\Player 1 801EE76B 00AA cn Backwash Bay Stage\No Energy\Player 1 801EE76B 0000 cn Backwash Bay Stage\Full Super Bar\Player 1 811EE772 0200 cn Ghastly Graveyard Stage\Can't be Stunned\Player 1 801EE803 0000 cn Ghastly Graveyard Stage\Infinite Energy\Player 1 801EE80B 00AA cn Ghastly Graveyard Stage\No Energy\Player 1 801EE80B 0000 cn Ghastly Graveyard Stage\Full Super Bar\Player 1 811EE812 0200 cn Candy Factory Stage\Can't be Stunned\Player 1 801EE8E3 0000 cn Candy Factory Stage\Infinite Energy\Player 1 801EE8EB 00AA cn Candy Factory Stage\No Energy\Player 1 801EE8EB 0000 cn Candy Factory Stage\Full Super Bar\Player 1 811EE8F2 0200 cn Kooky Courtyard Stage\Can't be Stunned\Player 1 801EE9E3 0000 cn Kooky Courtyard Stage\Infinite Energy\Player 1 801EE9EB 00AA cn Kooky Courtyard Stage\No Energy\Player 1 801EE9EB 0000 cn Kooky Courtyard Stage\Full Super Bar\Player 1 811EE9F2 0200 cn Santa's Toy Factory Stage\Can't be Stunned\Player 1 801EEE13 0000 cn Santa's Toy Factory Stage\Infinite Energy\Player 1 801EEE1B 00AA cn Santa's Toy Factory Stage\No Energy\Player 1 801EEE1B 0000 cn Santa's Toy Factory Stage\Full Super Bar\Player 1 811EEE22 0200 cn Boogerhenge, Tureen Toilet Stage\Can't be Stunned\Player 1 801EF1B3 0000 cn Boogerhenge, Tureen Toilet Stage\Infinite Energy\Player 1 801EF1BB 00AA cn Boogerhenge, Tureen Toilet Stage\No Energy\Player 1 801EF1BB 0000 cn Boogerhenge, Tureen Toilet Stage\Full Super Bar\Player 1 811EF1C2 0200 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Can't be Stunned\Player 1 801EFD93 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Infinite Energy\Player 1 801EFD9B 00AA cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\No Energy\Player 1 801EFD9B 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Full Super Bar\Player 1 811EFDA2 0200 cn Rubbage Room Stage\Can't be Stunned\Player 1 801F0823 0000 cn Rubbage Room Stage\Infinite Energy\Player 1 801F082B 00AA cn Rubbage Room Stage\No Energy\Player 1 801F082B 0000 cn Rubbage Room Stage\Full Super Bar\Player 1 811F0832 0200 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Can't be Stunned\Player 2 801F1183 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Infinite Energy\Player 2 801F118B 00AA cn Refuse Room, Grotto Gulch, Santa's Workship Stages\No Energy\Player 2 801F118B 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Full Super Bar\Player 2 811F1192 0200 cn Tribal Tower Stage\Can't be Stunned\Player 2 801F1223 0000 cn Tribal Tower Stage\Infinite Energy\Player 2 801F122B 00AA cn Tribal Tower Stage\No Energy\Player 2 801F122B 0000 cn Tribal Tower Stage\Full Super Bar\Player 2 811F1232 0200 cn Aquadome Stage\Can't be Stunned\Player 2 801F14A3 0000 cn Aquadome Stage\Infinite Energy\Player 2 801F14AB 00AA cn Aquadome Stage\No Energy\Player 2 801F14AB 0000 cn Aquadome Stage\Full Super Bar\Player 2 811F14B2 0200 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Can't be Stunned\Player 2 801F19B3 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Infinite Energy\Player 2 801F19BB 00AA cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\No Energy\Player 2 801F19BB 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Full Super Bar\Player 2 811F19C2 0200 cn Freezing Fortress Stage\Can't be Stunned\Player 2 801F1A13 0000 cn Freezing Fortress Stage\Infinite Energy\Player 2 801F1A1B 00AA cn Freezing Fortress Stage\No Energy\Player 2 801F1A1B 0000 cn Freezing Fortress Stage\Full Super Bar\Player 2 811F1A22 0200 cn Rubbage Reef Stage\Can't be Stunned\Player 2 801F1A93 0000 cn Rubbage Reef Stage\Infinite Energy\Player 2 801F1A9B 00AA cn Rubbage Reef Stage\No Energy\Player 2 801F1A9B 0000 cn Rubbage Reef Stage\Full Super Bar\Player 2 811F1AA2 0200 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Can't be Stunned\Player 2 801F1AC3 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Infinite Energy\Player 2 801F1ACB 00AA cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\No Energy\Player 2 801F1ACB 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Full Super Bar\Player 2 811F1AD2 0200 cn Clayribbean Cruise Stage\Can't be Stunned\Player 2 801F1B73 0000 cn Clayribbean Cruise Stage\Infinite Energy\Player 2 801F1B7B 00AA cn Clayribbean Cruise Stage\No Energy\Player 2 801F1B7B 0000 cn Clayribbean Cruise Stage\Full Super Bar\Player 2 811F1B82 0200 cn Backwash Bay Stage\Can't be Stunned\Player 2 801F1C03 0000 cn Backwash Bay Stage\Infinite Energy\Player 2 801F1C0B 00AA cn Backwash Bay Stage\No Energy\Player 2 801F1C0B 0000 cn Backwash Bay Stage\Full Super Bar\Player 2 811F1C12 0200 cn Ghastly Graveyard Stage\Can't be Stunned\Player 2 801F1CA3 0000 cn Ghastly Graveyard Stage\Infinite Energy\Player 2 801F1CAB 00AA cn Ghastly Graveyard Stage\No Energy\Player 2 801F1CAB 0000 cn Ghastly Graveyard Stage\Full Super Bar\Player 2 811F1CB2 0200 cn Candy Factory Stage\Can't be Stunned\Player 2 801F1D83 0000 cn Candy Factory Stage\Infinite Energy\Player 2 801F1D8B 00AA cn Candy Factory Stage\No Energy\Player 2 801F1D8B 0000 cn Candy Factory Stage\Full Super Bar\Player 2 811F1D92 0200 cn Kooky Courtyard Stage\Can't be Stunned\Player 2 801F1E83 0000 cn Kooky Courtyard Stage\Infinite Energy\Player 2 801F1E8B 00AA cn Kooky Courtyard Stage\No Energy\Player 2 801F1E8B 0000 cn Kooky Courtyard Stage\Full Super Bar\Player 2 811F1E92 0200 cn Santa's Toy Factory Stage\Can't be Stunned\Player 2 801F22B3 0000 cn Santa's Toy Factory Stage\Infinite Energy\Player 2 801F22BB 00AA cn Santa's Toy Factory Stage\No Energy\Player 2 801F22BB 0000 cn Santa's Toy Factory Stage\Full Super Bar\Player 2 811F22C2 0200 cn Boogerhenge, Tureen Toilet Stage\Can't be Stunned\Player 2 801F2653 0000 cn Boogerhenge, Tureen Toilet Stage\Infinite Energy\Player 2 801F265B 00AA cn Boogerhenge, Tureen Toilet Stage\No Energy\Player 2 801F265B 0000 cn Boogerhenge, Tureen Toilet Stage\Full Super Bar\Player 2 811F2662 0200 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Can't be Stunned\Player 2 801F3233 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Infinite Energy\Player 2 801F323B 00AA cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\No Energy\Player 2 801F323B 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Full Super Bar\Player 2 811F3242 0200 cn Rubbage Room Stage\Can't be Stunned\Player 2 801F3CC3 0000 cn Rubbage Room Stage\Infinite Energy\Player 2 801F3CCB 00AA cn Rubbage Room Stage\No Energy\Player 2 801F3CCB 0000 cn Rubbage Room Stage\Full Super Bar\Player 2 811F3CD2 0200 crc 95286EB4-B76AD58F-C:45 gn Command & Conquer (U) cn NOD\Max Cash 810C50AE FFFF 810C50B0 0001 cn NOD\Max Power 810C50CE FFFF 810C50D0 0001 cn NOD\Instant\Build Buildings 810C50C6 FFFF cn NOD\Instant\Build Units 810C50BE FFFF cn NOD\Instant\Build Vehicles 810C50C2 FFFF cn NOD\Instant\Build Aircraft 810C50BA FFFF cn NOD\Instant\Air Strike 800962A4 0032 800C4FF8 00FF cn NOD\Instant\Ion Cannon 800962A5 0033 800C4FD8 00FF cn NOD\Instant\Nuclear Strike 800962A6 0034 800C5018 00FF cn GDI\Max Cash 810C4F06 FFFF 810C4F08 0001 cn GDI\Max Power 810C4F26 FFFF 810C4F28 0001 cn GDI\Instant\Build Buildings 810C4F1E FFFF cn GDI\Instant\Build Units 810C4F16 FFFF cn GDI\Instant\Build Vehicles 810C4F1A FFFF cn GDI\Instant\Build Aircraft 810C4F12 FFFF cn GDI\Instant\Air Strike 800962A4 0032 800C4E50 00FF cn GDI\Instant\Ion Cannon 800962A5 0033 800C4E30 00FF cn GDI\Instant\Nuclear Strike 800962A6 0034 800C4E70 00FF cn GDI\Mission 4\Infinite Health Hum-Vee 800ABE99 0096 cn GDI\Mission 4\Infinite Health APC #1 800ABFB1 00C8 cn GDI\Mission 4\Infinite Health APC #2 800AC03D 00C8 cn GDI\Mission 6\Infinite Health Commando 800B56CD 0050 cn GDI\Mission 6\Infinite Health Transportational Helicopter 800BFC95 005A cn GDI\Maximum Killed 80092E53 00C8 cn NOD\Maximum Killed 80092E4F 00C8 cn GDI\None Killed 80092E53 0000 cn NOD\None Killed 80092E4F 0000 cn GDI\Maximum Buildings Lost 80092E5F 00C8 cn NOD\Maximum Buildings Lost 80092E5B 00C8 cn GDI\No Buildings Lost 80092E5F 0000 cn NOD\No Buildings Lost 80092E5B 0000 cn 100% Efficiency 80092E4B 0064 cn 100% Leadership 80092E47 0064 cn Tons Of Ending Credits 81092E3C 0FFF 81092E3E FFFF cn Max Total Score 81092E42 FFFF cn Time Spent On Mission 80092E3B ???? 0000:"No Time",00FF:"Max Time" crc 30C7AC50-7704072D-C:45 gn Conker's Bad Fur Day (U) cn Infinite\Health\Player 1 800CC49A 0006 cn Infinite\Oxygen 800CC382 0001 cn Infinite\Pots of cash 810D214A FFFF cn Access All\Chapters, Scenes,& Multi-Player Characters 50000401 0000 800E9D01 00FF cn Play as Option 1 cd Here you can Choose Options who you want to play as,But only one Option at a time. 800D213F ???? 0001:"Wessle",0003:"Tedi",0004:"Combat Squirrel",0005:"Conker",000B:"Uga",000C:"Bald Caveman",000D:"Caveman",000E:"Mohican Caveman",0010:"Neo Conker",001B:"Villager",0021:"Zombie",0023:"Enemy Bat",0024:"Conkers Bat",0025:"Army Captain",0026:"Tedi Boss",0027:"Gregg",0028:"Gregg skeleton" cn Infinite\Lives Player 1 800D2144 0064 cn Infinite\Health\Player 2 800CC7C6 270F cn Infinite\Health\Player 3 800CCAF2 270F cn Infinite\Health\Player 4 800CCE1E 270F cn Infinite\Time In Multi 8108FD7A 7500 cn Infinite\Bags In Heist 800E0BE4 00FF cn Access All\Characters & Weapons In Multi Race 810E9D02 ???? 00FF:"All Characters & Baseball bat",00FB:"All Characters & Frying Pan",00F3:"All Characters & Bones" cn Infinite\Bombs 802055CA 0030 cn Infinite\Max Kills Player 1 800E0B47 03E7 cn Infinite\Accuracy Count Player 1 cd MULTI ONLY. Only put this code on once you are in the game 800E0B67 0001 cn Infinite\Head Shot Count Player 1 cd MULTI ONLY. Only put this code on once you are in the game,Once you pick up a Gun a shoot once, you will 100%. 800E0B6B 03E7 cn Press L To Levitate\Player 1 cd Press L Button to Levitate & Let go to come back down D0042A15 0020 810CC2F0 41CB cn Press L To Levitate\Player 2 cd Press L Button to Levitate & Let go to come back down D0042A1D 0020 810CC61C 41CB cn Press L To Levitate\Player 3 cd Press L Button to Levitate & Let go to come back down D0042A25 0020 810CC948 41CB cn Press L To Levitate\Player 4 cd Press L Button to Levitate & Let go to come back down D0042A2D 0020 810CCC74 41CB cn Matrix Mode (Anywhere) cd Press R to activate and then Right-C to exit. D1042A14 0010 800BEA0C 0001 D1042A14 0010 810BE574 D202 D1042A14 0001 800BEA0C 0000 D1042A14 0001 810BE574 0000 cn Conkers Speed Select 810CC318 ???? 3F00:"Slow Conker",3F80:"Normal Conker",3FF0:"Fast Conker",4030:"Super Fast Conker" cn Weapon Select In Multi (On Pick Up) cd Select what Weapon you would like in Multi Player and then on a Weapon Pickup you will have the weapon of your choice.to change for another just Enable the one of your choice to have that instead.(you must have a weapon already to change for the next. 80180873 ???? 0001:"Sword",0002:"Nothing",0003:"Yellow Chain-Ssaw",0004:"Throwing Knives",0005:"Riffle",0006:"Long Pistol with Sight",0007:"Rocket Launcher",0008:"Buck Shot",000A:"High Powred Riffle With Scope",000C:"Two Automatic Machine Guns",0013:"Gas Mask" crc 46A3F7AF-0F7591D0-C:45 gn Cruis'n Exotica (U) cn Unlock All Cars 8104F10E FFFF cn Always Place 1st\Player 1 81065174 0000 cn Infinite\Nitros\Player 1 800BE7FD 00FF cn Infinite\Continues 8107F850 00FF cn Infinite\Time 810802D4 4296 cn Play As 800802D0 ???? 0000:"",0001:"",0002:"",0003:"",0004:"",0005:"",0006:"",0007:"",0008:"",0009:"",000A:"",000B:"",000C:"",000D:"",000E:"",000F:"",0010:"",0011:"",0012:"",0013:"",0014:"",0015:"",0016:"",0017:"",0018:"",0019:"" crc FF2F2FB4-D161149A-C:45 gn Cruis'n USA (U) (v1.0) cn Always Place 1st 8015025B 0001 cn Unlimited Time 80150A68 0095 8015097D 0095 cn Car Upgrades\'63 Muscle Car 8015065F 0005 cn Car Upgrades\La Bomba 80150663 0005 cn Car Upgrades\Devastator 80150667 0005 cn Car Upgrades\Italia P69 8015066B 0005 cn Car Upgrades\All-Terrain Vehicle 8015066F 0004 cn Car Upgrades\School Bus 80150673 0004 cn Car Upgrades\Police Car 80150677 0004 cn Infinite Time 80150A6D 0045 cn Stop Elapsed Time And No Traffic 80150A69 0000 cn Play Level Modifier 80150A83 ???? 0000:"Golden Gate Park",0001:"San Francisco",0002:"US 101",0003:"Redwood Forest",0004:"Beverly Hills",0005:"LA Freeway",0006:"Death Valley",0007:"Arizona",0008:"Grand Canyon",0009:"Iowa",000A:"Chicago",000B:"Indiana",000C:"Appalachia",000D:"Washington DC",000E:"Cruise The USA" cn Player 1\Gearbox Type Modifier 80150333 ???? 0000:"Automatic",0001:"Manual" cn Player 1\Always First Place 8015034B 0001 cn Player 1\Always Have Fastest Car 8015033A 000C cn Player 2\Gearbox Type Modifier 801506CF ???? 0000:"Automatic",0001:"Manual" cn Player 2\Always First Place 801506E7 0001 cn Player 2\Always Have Fastest Car 801506D6 000C cn Player 1\Lights & Sirens For Police Car & School Bus 8115065A 0001 8114E4AA 0001 cn Player 2\Lights & Sirens For Police Car & School Bus 811509F6 0001 8114E4C2 0001 crc 5306CF45-CBC49250-C:45 gn Cruis'n USA (U) (v1.1) cn Car Upgrades\'63 Muscle Car 8015053F 0005 cn Car Upgrades\La Bomba 80150543 0005 cn Car Upgrades\Devastator 80150547 0005 cn Car Upgrades\Italia P69 8015054B 0005 cn Car Upgrades\All-Terrain Vehicle 8015054F 0004 cn Car Upgrades\School Bus 80150553 0004 cn Car Upgrades\Police Car 80150557 0004 cn Infinite Time 8015094D 0095 cn Stop Elapsed Time And No Traffic 80150949 0000 cn Play Level Modifier 80150963 ???? 0000:"Golden Gate Park",0001:"San Francisco",0002:"US 101",0003:"Redwood Forest",0004:"Beverly Hills",0005:"LA Freeway",0006:"Death Valley",0007:"Arizona",0008:"Grand Canyon",0009:"Iowa",000A:"Chicago",000B:"Indiana",000C:"Appalachia",000D:"Washington DC",000E:"Cruise The USA" cn Player 1\Gearbox Type Modifier 80150213 ???? 0000:"Automatic",0001:"Manual" cn Player 1\Always First Place 8015022B 0001 cn Player 1\Always Have Fastest Car 8015021A 0001 cn Player 2\Gearbox Type Modifier 801505AF ???? 0000:"Automatic",0001:"Manual" cn Player 2\Always First Place 801505C7 0001 cn Player 2\Always Have Fastest Car 801505B6 0001 cn Player 1\Lights & Sirens For Police Car & School Bus P1 8115053A 0001 8114E38A 0001 cn Player 2\Lights & Sirens For Police Car & School Bus P2 811508D6 0001 8114E3A2 0001 crc B3402554-7340C004-C:45 gn Cruis'n USA (U) (v1.2) cn Car Upgrades\'63 Muscle Car 8015056F 0005 cn Car Upgrades\La Bomba 80150573 0005 cn Car Upgrades\Devastator 80150577 0005 cn Car Upgrades\Italia P69 8015057B 0005 cn Car Upgrades\All-Terrain Vehicle 8015057F 0004 cn Car Upgrades\School Bus 80150583 0004 cn Car Upgrades\Police Car 80150587 0004 cn Infinite Time 8015097D 0095 cn Stop Elapsed Time And No Traffic 80150979 0000 cn Play Level Modifier 80150993 ???? 0000:"Golden Gate Park",0001:"San Francisco",0002:"US 101",0003:"Redwood Forest",0004:"Beverly Hills",0005:"LA Freeway",0006:"Death Valley",0007:"Arizona",0008:"Grand Canyon",0009:"Iowa",000A:"Chicago",000B:"Indiana",000C:"Appalachia",000D:"Washington DC",000E:"Cruise The USA" cn Player 1\Gearbox Type Modifier 80150243 ???? 0000:"Automatic",0001:"Manual" cn Player 1\Always First Place 8015025B 0001 cn Player 1\Always Have Fastest Car 8015024A 0001 cn Player 2\Gearbox Type Modifier 801505DF ???? 0000:"Automatic",0001:"Manual" cn Player 2\Always First Place 801505F7 0001 cn Player 2\Always Have Fastest Car 801505E6 0001 cn Player 1\Lights & Sirens For Police Car & School Bus 8115056A 0001 8114E3BA 0001 cn Player 2\Lights & Sirens For Police Car & School Bus 81150906 0001 8114E3D2 0001 crc DFE61153-D76118E6-C:45 gn Cruis'n World (U) cn Have All Car Upgrades 803BEE42 0005 cn Have All Cars 813BEE78 1FFF cn Time Counts Down Faster 813D0D3E 0000 cn Dancing Girl Always On 803BEE73 0001 803C21CF 0054 cn Player 1\Always Place 1st 803CE023 0001 cn Player 1\Car/Transmission Modifier 803BEE40 ???? 0000:"Serpent (Auto)",0001:"Serpent (Manual)",0002:"Kamikaze (Auto)",0003:"Kamikaze (Manual)",0004:"ATV (Auto",0005:"ATV (Manual)",0006:"Scarab (Auto)",0007:"Scarab (Manual)",0008:"Stallion P6 (Auto)",0009:"Stallion P6 (Manual)",000A:"Banzai GTV (Auto)",000B:"Banzai GTV (Manual)",000C:"Zombie (Auto)",000D:"Zombie (Manual)",000E:"Orca (Auto)",000F:"Orca (manual)",0010:"El Nino (Auto)",0011:"El Nino (Manual)",0012:"Rhino 4x4 (Auto)",0013:"Rhino 4x4 (Manual)",0014:"Sardine Extreme (Auto)",0015:"Sardine Extreme (Manual)",0016:"Road King (Auto)",0017:"Road King (Manual)",0018:"Grass Hopper (Auto)",0019:"Grass Hopper (Manual)",001A:"Bulldog (Auto)",001B:"Bulldog (Manual)",001C:"Enforcer (Auto)",001D:"Enforcer (Manual)",001E:"NY Taxi (Auto)",001F:"NY Taxi (Manual)",0020:"School Bus (Auto)",0021:"School Bus (Manual)",0022:"Exec (Auto)",0023:"Exec (Manual)",0024:"Conductor (Auto)",0025:"Conductor (Manual)",0026:"Speed Demon (Auto)",0027:"Speed Demon (Manual)",0028:"Tommy (Auto)",0029:"Tommy (Manual)",002A:"Rocket (Auto)",002B:"Rocket (Manual)",002C:"The Surgeon (Auto)",002D:"The Surgeon (Manual)",002E:"Monsta (Auto)",002F:"Monsta (Manual)",0030:"Howler (Auto)",0031:"Howler (Manual)" cn Player 1\Stop Elapsed Time 813C7678 3C80 cn Player 2\Always Place 1st 803CE4FB 0001 cn Player 2\Car/Transmission Modifier 803BEE48 ???? 0000:"Serpent (Auto)",0001:"Serpent (Manual)",0002:"Kamikaze (Auto)",0003:"Kamikaze (Manual)",0004:"ATV (Auto",0005:"ATV (Manual)",0006:"Scarab (Auto)",0007:"Scarab (Manual)",0008:"Stallion P6 (Auto)",0009:"Stallion P6 (Manual)",000A:"Banzai GTV (Auto)",000B:"Banzai GTV (Manual)",000C:"Zombie (Auto)",000D:"Zombie (Manual)",000E:"Orca (Auto)",000F:"Orca (manual)",0010:"El Nino (Auto)",0011:"El Nino (Manual)",0012:"Rhino 4x4 (Auto)",0013:"Rhino 4x4 (Manual)",0014:"Sardine Extreme (Auto)",0015:"Sardine Extreme (Manual)",0016:"Road King (Auto)",0017:"Road King (Manual)",0018:"Grass Hopper (Auto)",0019:"Grass Hopper (Manual)",001A:"Bulldog (Auto)",001B:"Bulldog (Manual)",001C:"Enforcer (Auto)",001D:"Enforcer (Manual)",001E:"NY Taxi (Auto)",001F:"NY Taxi (Manual)",0020:"School Bus (Auto)",0021:"School Bus (Manual)",0022:"Exec (Auto)",0023:"Exec (Manual)",0024:"Conductor (Auto)",0025:"Conductor (Manual)",0026:"Speed Demon (Auto)",0027:"Speed Demon (Manual)",0028:"Tommy (Auto)",0029:"Tommy (Manual)",002A:"Rocket (Auto)",002B:"Rocket (Manual)",002C:"The Surgeon (Auto)",002D:"The Surgeon (Manual)",002E:"Monsta (Auto)",002F:"Monsta (Manual)",0030:"Howler (Auto)",0031:"Howler (Manual)" cn Player 2\Stop Elapsed Time 813C78B4 3C80 cn Player 3\Always Place 1st 803CDB4B 0001 cn Player 3\Car/Transmission Modifier 803BEE50 ???? 0000:"Serpent (Auto)",0001:"Serpent (Manual)",0002:"Kamikaze (Auto)",0003:"Kamikaze (Manual)",0004:"ATV (Auto",0005:"ATV (Manual)",0006:"Scarab (Auto)",0007:"Scarab (Manual)",0008:"Stallion P6 (Auto)",0009:"Stallion P6 (Manual)",000A:"Banzai GTV (Auto)",000B:"Banzai GTV (Manual)",000C:"Zombie (Auto)",000D:"Zombie (Manual)",000E:"Orca (Auto)",000F:"Orca (manual)",0010:"El Nino (Auto)",0011:"El Nino (Manual)",0012:"Rhino 4x4 (Auto)",0013:"Rhino 4x4 (Manual)",0014:"Sardine Extreme (Auto)",0015:"Sardine Extreme (Manual)",0016:"Road King (Auto)",0017:"Road King (Manual)",0018:"Grass Hopper (Auto)",0019:"Grass Hopper (Manual)",001A:"Bulldog (Auto)",001B:"Bulldog (Manual)",001C:"Enforcer (Auto)",001D:"Enforcer (Manual)",001E:"NY Taxi (Auto)",001F:"NY Taxi (Manual)",0020:"School Bus (Auto)",0021:"School Bus (Manual)",0022:"Exec (Auto)",0023:"Exec (Manual)",0024:"Conductor (Auto)",0025:"Conductor (Manual)",0026:"Speed Demon (Auto)",0027:"Speed Demon (Manual)",0028:"Tommy (Auto)",0029:"Tommy (Manual)",002A:"Rocket (Auto)",002B:"Rocket (Manual)",002C:"The Surgeon (Auto)",002D:"The Surgeon (Manual)",002E:"Monsta (Auto)",002F:"Monsta (Manual)",0030:"Howler (Auto)",0031:"Howler (Manual)" cn Player 4\Always Place 1st 803CD673 0001 cn Player 4\Car/Transmission Modifier 803BEE58 ???? 0000:"Serpent (Auto)",0001:"Serpent (Manual)",0002:"Kamikaze (Auto)",0003:"Kamikaze (Manual)",0004:"ATV (Auto",0005:"ATV (Manual)",0006:"Scarab (Auto)",0007:"Scarab (Manual)",0008:"Stallion P6 (Auto)",0009:"Stallion P6 (Manual)",000A:"Banzai GTV (Auto)",000B:"Banzai GTV (Manual)",000C:"Zombie (Auto)",000D:"Zombie (Manual)",000E:"Orca (Auto)",000F:"Orca (manual)",0010:"El Nino (Auto)",0011:"El Nino (Manual)",0012:"Rhino 4x4 (Auto)",0013:"Rhino 4x4 (Manual)",0014:"Sardine Extreme (Auto)",0015:"Sardine Extreme (Manual)",0016:"Road King (Auto)",0017:"Road King (Manual)",0018:"Grass Hopper (Auto)",0019:"Grass Hopper (Manual)",001A:"Bulldog (Auto)",001B:"Bulldog (Manual)",001C:"Enforcer (Auto)",001D:"Enforcer (Manual)",001E:"NY Taxi (Auto)",001F:"NY Taxi (Manual)",0020:"School Bus (Auto)",0021:"School Bus (Manual)",0022:"Exec (Auto)",0023:"Exec (Manual)",0024:"Conductor (Auto)",0025:"Conductor (Manual)",0026:"Speed Demon (Auto)",0027:"Speed Demon (Manual)",0028:"Tommy (Auto)",0029:"Tommy (Manual)",002A:"Rocket (Auto)",002B:"Rocket (Manual)",002C:"The Surgeon (Auto)",002D:"The Surgeon (Manual)",002E:"Monsta (Auto)",002F:"Monsta (Manual)",0030:"Howler (Auto)",0031:"Howler (Manual)" cn Have All Car Upgrades 803BEE42 0005 cn Have All Cars 813BEE78 1FFF cn Championship Mode\Max Total Points 813BFBFA FFFF cn Championship Mode\Max Points Per Race 813BFBFE FFFF cn Championship Mode\Max Points To Next Level 813BFBFC FFFF cn Championship Mode\Unlimited Nitro\Player 1 803C75E7 0003 cn Championship Mode\Unlimited Nitro\Player 2 803C7823 0003 cn Championship Mode\Unlimited Nitro\Player 3 803C716F 0003 cn Championship Mode\Cannot Spin Out 803CDD93 0000 cn Championship Mode\Disable Left Lane Traffic 8033C95B 0001 cn Championship Mode\Disable Right Lane Traffic 8033C95F 0001 crc E8FC8EA1-9F738391-C:45 gn CyberTiger (U) cn Always Hole In One 8115E1D6 0000 cn Inventory\Max Distance & Wind Cutter 800B4412 00FF cn Inventory\Max No Bounce & Tee Up 800B4411 00FF cn Inventory\Max Accuracy & Skipper 800B4410 00FF cn Inventory\Max Spinner & Burrow 800B4413 00FF cn Inventory\Max Mystery 800B4420 00F0 cn Big Head 810AE840 401F cn Character Unlock\Kimmi 800B0BBA 0010 cn Character Unlock\Starr 800B0BCE 0010 cn Character Unlock\Marvin The Alien 800B0BD7 0001 cn Change Looks Of Liltiger 800B0BC4 0011 cn Character Unlock\Robert & Delvis 800B0BCA 0011 cn Character Unlock\Bengal The Tiger 800B0BC2 0010 cn Character Unlock\Cindy 800B0BBA 0001 cn Character Unlock\Festus 800B0BD3 0001 cn Character Unlock\Mark 800B0BC7 0012 cn Character Unlock\Twfan & Eagamer 800B0BBE 0011 cn Character Unlock\Traci (Leopard Costume) 800B0BCE 0011 cn Character Unlock\Bobby 800B0BC6 0001 crc A4A52B58-23759841-C:45 gn Dark Rift (U) cn Access Sonork Character 80049DF0 0001 cn Access Demitron Character 80049DF4 0001 cn Infinite Health\All Levels\Player 1 81028988 0800 8102898A 0018 81000060 3C1B 81000062 8008 81000064 8F7B 81000066 0228 8100006C 03E0 8100006E 0008 81000070 A761 81000072 0070 cn Press GS For 2 Rounds Won\Player 1 890B6330 0002 cn Press GS For 2 Rounds Won\Player 2 890B6342 0002 cn Music Modifier 800816B2 ???? 0000:"Music Off",002A:"Volume Low",0055:"Volume Medium",007F:"Volume Max" crc F5363349-DBF9D21B-C:45 gn Deadly Arts (U) cn Player 1\Character Modifier 80105001 ???? 0000:"Azami",0001:"Serina",0002:"Miki",0003:"Kai",0004:"Sakai",0005:"Kengon",0006:"Kyeya",0007:"Kaoru",0008:"Gouriki",0009:"Reiji",000A:"Yami",000B:"Hikari",000C:"Invisible Fighter" cn Player 1\Infinite Energy 81105026 03E8 cn Player 1\No Energy 81105026 0000 cn Player 1\Never Wins 8009E3F4 0000 cn Player 1\Needs 1 Round to Win D009E3F4 0000 8009E3F4 0001 cn Player 2\Character Modifier 8011B399 ???? 0000:"Azami",0001:"Serina",0002:"Miki",0003:"Kai",0004:"Sakai",0005:"Kengon",0006:"Kyeya",0007:"Kaoru",0008:"Gouriki",0009:"Reiji",000A:"Yami",000B:"Hikari",000C:"Invisible Fighter" cn Player 2\Infinite Energy 8111B3BE 03E8 cn Player 2\No Energy 8111B3BE 0000 cn Player 2\P2 Never Wins 8009E3F5 0000 cn Player 2\Needs 1 Round to Win D009E3F5 0000 8009E3F5 0001 cn Have Extra Characters (Gouriki & Reiji) 8009E3DF 00FF crc DEE584A2-0F161187-C:45 gn Destruction Derby 64 (U) cn Solo Mode\Infinite Damage Meter 80125FD9 0026 cn All Cars and Tracks 50000602 0000 81097A18 0101 cn All Difficulty Levels 81097A16 0003 cn Solo Mode\Vehicles\Baja Buggy 80097A18 0001 cn Solo Mode\Vehicles\Low Rider 80097A19 0001 cn Solo Mode\Vehicles\Woody Wagon 80097A1A 0001 cn Solo Mode\Vehicles\Pickup 80097A1B 0001 cn Solo Mode\Vehicles\Taxi Cab 80097A1C 0001 cn Solo Mode\Vehicles\Blue Demon 80097A1D 0001 cn Solo Mode\Vehicles\Rag Top 80097A1E 0001 cn Solo Mode\Vehicles\Hot Rod 80097A1F 0001 cn Solo Mode\Vehicles\Ambulance 80097A20 0001 cn Solo Mode\Vehicles\Watchback 80097A21 0001 cn Solo Mode\Vehicles\Street Rocket 80097A22 0001 cn Solo Mode\Vehicles\Police Car 80097A23 0001 cn Solo Mode\Tracks\Metro Challenge 80095CCC 0001 cn Solo Mode\Tracks\Seascape 80095CCD 0001 cn Solo Mode\Tracks\Boyou Run 80095CCE 0001 cn Solo Mode\Tracks\Terminal Impact 80095CCF 0001 cn Solo Mode\Tracks\Destruction Junction 80095CD0 0001 cn Solo Mode\Tracks\Sunset Canyon 80095CD1 0001 cn Solo Mode\Tracks\Apline Ridge 80095CD2 0001 cn Solo Mode\Tracks\Midnyte Rumble 80095CD3 0001 cn Multiplayer\Tracks\The Junkyard 80095CC8 0001 cn Multiplayer\Tracks\Have Aztec Ruins 80095CC9 0001 cn Multiplayer\Tracks\Urban Mayhem 80095CCA 0001 cn Multiplayer\Tracks\Ground Zero 80095CCB 0001 cn Multiplayer\Junkyard\Infinite Health\Player 1 80205B8B 00BE cn Multiplayer\Junkyard\Infinite Health\Player 2 8021505F 00BE cn Multiplayer\Aztec Ruins\Infinite Health\Player 1 801FC437 00BE cn Multiplayer\Aztec Ruins\Infinite Health\Player 2 80217C5F 00BE cn Multiplayer\Urban Mayhem\Infinite Health\Player 1 8021779F 00BE cn Multiplayer\Urban Mayhem\Infinite Health\Player 2 80235E5F 00BE cn Multiplayer\Ground Zero\Infinite Health\Player 1 801F64D7 00BE cn Multiplayer\Ground Zero\Infinite Health\Player 2 80211D1F 00BE cn Solo Mode\Seascape Sprint\Infinite Health D02D4C24 0080 802D4C33 00E1 cn Solo Mode\Metro Challenge\Infinite Health D02EDB18 0080 802EDB27 00E1 cn Solo Mode\Terminal Impact\Infinite Health D02B5AA3 0080 802B5AB2 00E1 cn Solo Mode\Destruction Junction\Infinite Health D029A9B0 0080 8029A9BF 00E1 cn Solo Mode\Midnyte Rumble\Infinite Health D030C70B 0080 8030C71A 00E1 cn Solo Mode\Bayou Run\Infinite Health D0285E7C 0080 80285E8B 00E1 cn Solo Mode\Alpine Ridge\Infinite Health D02B9D24 0080 802B9D33 00E1 cn Solo Mode\Sunset Canyon\Infinite Health D0303A68 0080 80303A77 00E1 crc 53D440E7-7519B011-C:45 gn Diddy Kong Racing (U) (V1.0) cn Enable All Cheats cd Go into Options & then Magic Codes. Then Code list to turn off & on what you want. 50000401 0000 810DFD9C FFFF cn Have All\Trophies cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 811FC9DE FFFF cn Have All\Keys cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 811FC9D8 FFFF cn Have All\Amulets cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 811FC9E6 FFFF cn Boss Cannot Move\Dino 811DFCF4 44A0 cn Boss Cannot Move\Octo 811E045C 44A0 cn Have All\99 Balloons 810DFD9A FFFF 801FCBED 0063 cn Have All\Levels Completely Finished 50000904 0000 801FCAF7 00FF 801FCB1F 00FF 801FCB27 00FF 50000404 0000 801FCB2F 00FF 801FCB4F 00FF 50000804 0000 801FCB53 00FF cn Have All\Silver Coins\Ancient Lake cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E34AA 0008 cn Have All\Silver Coins\Fossil Canyon cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E694A 0008 cn Have All\Silver Coins\Jungle Falls cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E513A 0008 cn Have All\Silver Coins\Hot Top Volcano cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E480A 0008 cn Have All\Silver Coins\Everfrost Peak cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E513A 0008 cn Have All\Silver Coins\Walrus Cove cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E4C5A 0008 cn Have All\Silver Coins\Snowball Valley cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E4BDA 0008 cn Have All\Silver Coins\Frosty Village cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E612A 0008 cn Have All\Silver Coins\Whale Bay cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E3CDA 0008 cn Have All\Silver Coins\Pirate Lagoon cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E2B3A 0008 cn Have All\Silver Coins\Crescent Island cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E3C0A 0008 cn Have All\Silver Coins\Treasure Caves cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E38FA 0008 cn Have All\Silver Coins\Boulder Canyon cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E63CA 0008 cn Have All\Silver Coins\Greenwood Village cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E4C8A 0008 cn Have All\Silver Coins\Windmill Plains cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E9D9A 0008 cn Have All\Silver Coins\Haunted Woods cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E4BFA 0008 cn Have All\50 Bananas\Ancient Lake cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E32CD 0032 cn Have All\50 Bananas\Fossil Canyon cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E676D 0032 cn Have All\50 Bananas\Jungle Falls cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E44CD 0032 cn Have All\50 Bananas\Hot Top Volcano cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E462D 0032 cn Have All\50 Bananas\Whale Bay cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E3AFD 0032 cn Have All\50 Bananas\Pirate Lagoon cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E295D 0032 cn Have All\50 Bananas\Crescent Island cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E3A2D 0032 cn Have All\50 Bananas\Treasure Caves cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E371D 0032 cn Have All\50 Bananas\Everfrost Peak cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E4F5D 0032 cn Have All\50 Bananas\Walrus Cove cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E4A7D 0032 cn Have All\50 Bananas\Snowball Valley cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E49FD 0032 cn Have All\50 Bananas\Frosty Village cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E5F4D 0032 cn Have All\50 Bananas\Boulder Canyon cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E61ED 0032 cn Have All\50 Bananas\Greenwood Village cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E4AAD 0032 cn Have All\50 Bananas\Windwill Plains cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E9BBD 0032 cn Have All\50 Bananas\Haunted Woods cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E4A1D 0032 cn Have All\50 Bananas\Spacedust Alley cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E654D 0032 cn Have All\50 Bananas\Darkmoon Caverns cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E5D0D 0032 cn Have All\50 Bananas\Star City cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E578D 0032 cn Have All\50 Bananas\Spaceport Alpha cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E3C6D 0032 cn Have All\The pieces of the TT thing 801FC9E6 0004 cn Infinite\Power Ups\Ancient Lake cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E6A2B 0010 cn Infinite\Power Ups\Boulder Canyon cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E8D4B 0010 cn Infinite\Power Ups\Crescent Island cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E718B 0010 cn Infinite\Power Ups\Darkmoon Caverns cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E96AB 0010 cn Infinite\Power Ups\Everfrost Peak cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E871B 0010 cn Infinite\Power Ups\Fossil Canyon cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E9ECB 0010 cn Infinite\Power Ups\Frosty Village cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E96A6 0010 cn Infinite\Power Ups\Greenwood Village cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E820B 0010 cn Infinite\Power Ups\Hot Top Volcano cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E477B 0010 cn Infinite\Power Ups\Haunted Woods cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E817B 0010 cn Infinite\Power Ups\Jungle Falls cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E45BB 0010 cn Infinite\Power Ups\Pirate Lagoon cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E54B6 0010 cn Infinite\Power Ups\Snowball Valley cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E815B 0010 cn Infinite\Power Ups\Spaceport Alpha cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E676B 0010 cn Infinite\Power Ups\Space Dust Alley cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E904B 0010 cn Infinite\Power Ups\Starcity cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E8EEB 0010 cn Infinite\Power Ups\Treasure Cove cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E6E7B 0010 cn Infinite\Power Ups\Walrus Cove cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E81DB 0010 cn Infinite\Power Ups\Whale Bay cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E665B 0010 cn Infinite\Power Ups\Windmill Plains cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801EC6BB 0010 crc E402430D-D2FCFC9D-C:45 gn Diddy Kong Racing (U) (V1.1) cn Enable All Cheats cd Go into Options & then Magic Codes. Then Code list to turn off & on what you want. 810E031C FFFF 810E031E FFFF cn Have All\Trophies cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 811FC9DE FFFF cn Have All\Keys cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 811FD1C8 FFFF cn Have All\Amulets cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 811FD1D6 FFFF cn Boss Cannot Move\Dino 811E0444 44A0 cn Boss Cannot Move\Octo 811E0BAC 44A0 cn Have All\99 Balloons 810E058A FFFF 801FD3DD 0063 cn Have All\Levels Completely Finished 50000904 0000 801FD2E7 00FF 801FD30F 00FF 801FD317 00FF 50000404 0000 801FD31F 00FF 801FD33F 00FF 50000804 0000 801FD343 00FF cn Have All\Silver Coins\Ancient Lake cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E3BFA 0008 cn Have All\Silver Coins\Fossil Canyon cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E709A 0008 cn Have All\Silver Coins\Jungle Falls cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E588A 0008 cn Have All\Silver Coins\Hot Top Volcano cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E4F5A 0008 cn Have All\Silver Coins\Everfrost Peak cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E588A 0008 cn Have All\Silver Coins\Walrus Cove cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E53AA 0008 cn Have All\Silver Coins\Snowball Valley cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E532A 0008 cn Have All\Silver Coins\Frosty Village cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E687A 0008 cn Have All\Silver Coins\Whale Bay cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E442A 0008 cn Have All\Silver Coins\Pirate Lagoon cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E328A 0008 cn Have All\Silver Coins\Crescent Island cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E435A 0008 cn Have All\Silver Coins\Treasure Caves cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E404A 0008 cn Have All\Silver Coins\Boulder Canyon cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E6B1A 0008 cn Have All\Silver Coins\Greenwood Village cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E53DA 0008 cn Have All\Silver Coins\Windmill Plains cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801EA4EA 0008 cn Have All\Silver Coins\Haunted Woods cd Do not use more than 1 Silver Coins up at a time or it will cause a crash 801E534A 0008 cn Have All\50 Bananas\Ancient Lake cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E3A1D 0032 cn Have All\50 Bananas\Fossil Canyon cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E6EBD 0032 cn Have All\50 Bananas\Jungle Falls cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E4C1D 0032 cn Have All\50 Bananas\Hot Top Volcano cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E4D7D 0032 cn Have All\50 Bananas\Whale Bay cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E424D 0032 cn Have All\50 Bananas\Pirate Lagoon cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E30AD 0032 cn Have All\50 Bananas\Crescent Island cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E417D 0032 cn Have All\50 Bananas\Treasure Caves cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E3E6D 0032 cn Have All\50 Bananas\Everfrost Peak cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E56AD 0032 cn Have All\50 Bananas\Walrus Cove cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E51CD 0032 cn Have All\50 Bananas\Snowball Valley cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E514D 0032 cn Have All\50 Bananas\Frosty Village cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E669D 0032 cn Have All\50 Bananas\Boulder Canyon cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E693D 0032 cn Have All\50 Bananas\Greenwood Village cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E51FD 0032 cn Have All\50 Bananas\Windwill Plains cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801EA30D 0032 cn Have All\50 Bananas\Haunted Woods cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E516D 0032 cn Have All\50 Bananas\Spacedust Alley cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E6C9D 0032 cn Have All\50 Bananas\Darkmoon Caverns cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E645D 0032 cn Have All\50 Bananas\Star City cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E5EDD 0032 cn Have All\50 Bananas\Spaceport Alpha cd Do not use more than 1 50 Bananas up at a time or it will cause a crash 801E43BD 0032 cn Have All\The pieces of the TT thing 801FD1D6 0004 cn Infinite\Power Ups\Ancient Lake cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E717B 0010 cn Infinite\Power Ups\Boulder Canyon cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E949B 0010 cn Infinite\Power Ups\Crescent Island cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E78DB 0010 cn Infinite\Power Ups\Darkmoon Caverns cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E9DFB 0010 cn Infinite\Power Ups\Everfrost Peak cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E8E6B 0010 cn Infinite\Power Ups\Fossil Canyon cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801EA61B 0010 cn Infinite\Power Ups\Frosty Village cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E9DF6 0010 cn Infinite\Power Ups\Greenwood Village cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E895B 0010 cn Infinite\Power Ups\Hot Top Volcano cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E4ECB 0010 cn Infinite\Power Ups\Haunted Woods cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E88CB 0010 cn Infinite\Power Ups\Jungle Falls cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E4D0B 0010 cn Infinite\Power Ups\Pirate Lagoon cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E5C06 0010 cn Infinite\Power Ups\Snowball Valley cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E88AB 0010 cn Infinite\Power Ups\Spaceport Alpha cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E6EBB 0010 cn Infinite\Power Ups\Space Dust Alley cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E979B 0010 cn Infinite\Power Ups\Starcity cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E963B 0010 cn Infinite\Power Ups\Treasure Cove cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E75CB 0010 cn Infinite\Power Ups\Walrus Cove cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E892B 0010 cn Infinite\Power Ups\Whale Bay cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801E6DAB 0010 cn Infinite\Power Ups\Windmill Plains cd For Track Race Only.Do not use more than 1 Infinite Power up at a time or it will cause a crash 801ECE0B 0010 crc C16C421B-A21580F7-C:45 gn Disney's Donald Duck - Goin' Quackers (U) cn Infinite\99 Lives 801D72AE 0063 cn Infinite\99 Stars 801D72AF 0063 cn Instant\Rage Attack (Press C-Left) D00CB2A1 0002 801CE5BD 0001 cn Instant\Hyperactive State [Invincible] (Press C-Right) D00CB2A1 0001 801CE616 0001 cn Instant\Carrier Box [Moon Walk] (Press L) cd Press and hold the L Button and you will run floating of any ledge slowing drifting down. If you keep pressing the A Button while Holding L it will act as a Moon Jump. D00CB2A1 0020 801C939F 0001 cn Infinite\Time\Gladstones Time Attack 801D72A7 00FF cn Infinite\Time\Nephews Toy Hunting 801D72A3 0063 cn Have All\Levels and Bonus Stages Unlocked cd Press start in Gyro's Lab and then resume game to see all open 801D72CC 00FF 801D72CD 00FF 801D72CE 00FF 801D72CF 00FF 801D72D3 00FF cn Have All\Time Attack & Toy Hunting Comnpleated (All Levels) cd Press start in Gyro's Lab and then resume game to see all open 801D72D8 00FF 801D72D9 00FF 801D72DA 00FF 801D72DB 00FF 801D72DC 00FF 801D72DD 00FF 801D72DE 00FF 801D72DF 00FF crc CBFE69C7-F2C0AB2A-C:45 gn Disney's Tarzan (U) cn Infinite\Health 811921C0 0120 cn Have\Coins Collected 100% 800DD257 0064 cn Have\Level & Tokens Completed 100% 800DD22F 0000 800DD230 0001 800DD231 0000 cn Access Level Select cd On the main menu Scroll down to make CHEATS visible to go into Level Select.For in-Game Cheats,Pause gameplay. 810DD21C 8001 cn Infinite\Lives 800DD252 ???? 0003:"3 Lives",0063:"99 Lives" cn Have\All TARZAN Letters 800DD225 00FF cn Have\Full Portrait 800DD224 00FF cn Infinite\Red Weapon 81192098 0063 cn Infinite\Green Weapon 81192096 0063 cn Infinite\Purple Weapon 8119209A 0063 cn Press GS For\Sabor Attacks\Sabor 1 Hit Kill 8924A23E 0001 cn Infinite\Bonus Timer cd This is For All Timers on Bonus Levels 801735FE 0025 crc EC58EABF-AD7C7169-C:45 gn Donkey Kong 64 (U) cn Donkey Kong\Infinite Ammo 807FCC45 0096 cn Infinite\Health 817FCC4C 041F cn Donkey Kong\Infinite Musical Instrument 817FC954 0103 817FC958 00FF cn Diddy\Infinite Musical Instrument 817FC9B6 000A cn Tiny\Infinite Musical Instrument 817FCA72 000A cn Lanky\Infinite Musical Instrument 817FCA14 000A cn Chunky\Infinite Musical Instrument 817FCAD0 000A cn Infinite\Camera Film 807FCC49 0005 cn Infinite\Orange Bombs 807FCC41 0096 cn Donkey Kong\Infinite Bananas\Jungle Japes 817FC95A 03E7 cn Donkey Kong\Infinite Bananas\Angry Aztec 817FC95C 03E7 cn Donkey Kong\Infinite Bananas\FactoryLevel 817FC95E 03E7 cn Donkey Kong\Infinite Bananas\Galleon Level 817FC9BE 03E7 cn Donkey Kong\Infinite Bananas\Fungi Forest 817FC962 03E7 cn Donkey Kong\Infinite Bananas\Creepy Castle 817FC966 03E7 cn Donkey Kong\Infinite Bananas\Crystal Caves 817FC964 03E7 cn Donkey Kong\All Golden Bananas\Jungle Japes 817FC992 03E7 cn Donkey Kong\All Golden Bananas\Angry Aztecs 817FC994 03E7 cn Donkey Kong\All Golden Bananas\Frantic Factory 817FC996 03E7 cn Donkey Kong\All Golden Bananas\Gloomy Galleon 817FC998 03E7 cn Donkey Kong\All Golden Bananas\Crystal Caves 817FC99C 03E7 cn Donkey Kong\All Golden Bananas\Creepy Castle 817FC99E 03E7 cn Donkey Kong\All Golden Bananas\DK Isle 817FC9A0 03E7 cn Diddy\All Golden Bananas\Jungle Japes 817FC9F0 0064 cn Diddy\All Golden Bananas\Angry Aztecs 817FC9F2 0064 cn Diddy\All Golden Bananas\Frantic Factory 817FC9F4 0064 cn Diddy\All Golden Bananas\Gloomy Galleon 817FC9F6 0064 cn Diddy\All Golden Bananas\Fungi Forest 817FC9F8 0064 cn Diddy\All Golden Bananas\Crystal Caves 817FC9FA 0064 cn Diddy\All Golden Bananas\Creepy Castle 817FC9FC 0064 cn Diddy\All Golden Bananas\DK Isle 817FC9FE 0064 cn Tiny\All Golden Bananas\Jungle Japes 817FCAAC 0064 cn Tiny\All Golden Bananas\Angry Aztecs 817FCAAE 0064 cn Tiny\All Golden Bananas\Frantic Factory 817FCAB0 0064 cn Tiny\All Golden Bananas\Gloomy Galleon 817FCAB2 0064 cn Tiny\All Golden Bananas\Fungi Forest 817FCAB4 0064 cn Tiny\All Golden Bananas\Crystal Caves 817FCAB6 0064 cn Tiny\All Golden Bananas\Creepy Castle 817FCAA8 0064 cn Tiny\All Golden Bananas\DK Isle 817FCABA 0064 cn Lanky\All Golden Bananas\Jungle Japes 817FCA4E 0064 cn Lanky\All Golden Bananas\Angry Aztecs 817FCA50 0064 cn Lanky\All Golden Bananas\Frantic Factory 817FCA52 0064 cn Lanky\All Golden Bananas\Gloomy Galleon 817FCA54 0064 cn Lanky\All Golden Bananas\Fungi Forest 817FCA56 0064 cn Lanky\All Golden Bananas\Crystal Caves 817FCA58 0064 cn Lanky\All Golden Bananas\Creepy Castle 817FCA5A 0064 cn Lanky\All Golden Bananas\DK Isle 817FCA5C 0064 cn Chunky\All Golden Bananas\Jungle Japes 817FCB0A 0064 cn Chunky\All Golden Bananas\Angry Aztecs 817FCB0C 0064 cn Chunky\All Golden Bananas\Frantic Factory 817FCB0E 0064 cn Chunky\All Golden Bananas\Gloomy Galleon 817FCB10 0064 cn Chunky\All Golden Bananas\Fungi Forest 817FCB12 0064 cn Chunky\All Golden Bananas\Crystal Caves 817FCB14 0064 cn Chunky\All Golden Bananas\Creepy Castle 817FCB16 0064 cn Chunky\All Golden Bananas\DK Isle 817FCB18 0064 cn Donkey Kong\Infinite Coins 817FC956 03E7 cn Diddy\Infinite Coins 817FC9B4 03E7 cn Tiny\Infinite Coins 817FCA70 03E7 cn Lanky\Infinite Coins 817FCA12 03E7 cn Chunky\Infinite Coins 817FCACE 03E7 cn Infinite\Crystal Coconuts 807FCB87 0096 cn Donkey Kong\Has Moves 817FC950 0103 cn Donkey Kong\Have Weapon 817FC952 0103 cn Free Pass (Access All Areas) cd This is exactly what it says, You can walk through Any Locked Door,Gate, Or Area. Have Fun. 8066D226 0001 8066D321 0001 crc A83E101A-E937B69D-C:45 gn Doom64 (U) v1.0 cn Always Have\Gun 800632C3 0001 cn Always Have\Shotgun 800632C7 0001 cn Always Have\Double Shotgun 800632CB 0001 cn Always Have\Chain Gun 800632CF 0001 cn Always Have\Missile Launcher 800632D3 0001 cn Always Have\Chainsaw 800632BB 0001 cn Always Have\Plasma Rifle 800632D7 0001 cn Always Have\BFG 9000 800632DB 0001 cn Always Have\Have Rocket Launcher 800632D1 0001 cn Always Have\Laser Weapon 800632DD 0001 cn Always Have\Bio Suite 80063283 ???? 00FF:"On",0000:"Off" cn Infinite\Armor 8006326F 00FF cn Rapid Fire 8106333A 0B94 cn Invincible 8006330B 0002 cn Turn Map Markers On 8006330B 0004 cn Invincible And Map Markers 8006330B 0006 cn Berserk Mode 8006327B 00FF cn [Max Brightness] cd Enable this cheat on rom load to have Max Brightness (internal) and then put Jabo d3d8 on 160% Max for a extra brightness Boost. 8005A7C8 0064 cn Have All\Weapons 50000A04 0000 810632BA 0001 cn Infinite\Ammo All Weapons 50000404 0000 810632E2 013C cn Have All\Keys 50000504 0000 8106328E FFFF cn Enable Cheat Menu 8005A7D3 0001 crc 423E96F4-CE88F05B-C:45 gn Doom64 (U) v1.1 cn Always Have\Gun 80063373 0001 cn Always Have\Shotgun 80063377 0001 cn Always Have\Double Shotgun 8006337B 0001 cn Always Have\Chain Gun 8006337F 0001 cn Always Have\Missile Launcher 80063383 0001 cn Always Have\Chainsaw 8006336B 0001 cn Always Have\Plasma Rifle 80063387 0001 cn Always Have\BFG 9000 8006338B 0001 cn Always Have\Have Rocket Launcher 80063381 0001 cn Always Have\Laser Weapon 8006338F FFFF cn Always Have\Bio Suite 80063333 ???? 00FF:"On",0000:"Off" cn Infinite\Armor 8006331F 00FF cn Rapid Fire 810633EA 0B94 cn Invincible 800633BB 0002 cn Turn Map Markers On 800633BB 0004 cn Invincible And Map Markers 800633BB 0006 cn Berserk Mode 8006332B 00FF cn [Max Brightness] cd Enable this cheat on rom load to have Max Brightness (internal) and then put Jabo d3d8 on 160% Max for a extra brightness Boost. 8005A878 0064 cn Infinite\Ammo All Weapons 80063393 00FF 80063397 00FF 8006339B 00FF 8006339F 00FF cn Have All Keys 8006333F 0001 80063343 0001 80063344 0001 80063353 0001 8006334F 0001 80063348 0001 cn Enable Cheat Menu 8005A883 0001 crc A62230C3-F0834488-C:45 gn Dual Heroes (U) cn Player 1\Infinite Energy D022671C 0000 8122671C 00FA cn Player 2\Infinite Energy D022671E 0000 8122671E 00FA cn Infinite Time D0226724 0000 81226724 003C cn Player 1\Never Wins D0226715 0001 80226715 0000 cn Player 2\1 Win To Win D0226717 0000 80226717 0001 cn Player 2\Never Wins D0226717 0001 80226717 0000 cn Player 1\1 Win To Win D0226715 0000 80226715 0001 cn Player 1\No Energy D022671C 0000 8122671C 0000 cn Player 2\No Energy D022671E 0000 8122671E 0000 cn Player 1\Infinite Time To Continue 802267CB 0009 803CF2A1 0009 cn Only Play One Round D0226791 0000 81226718 0001 cn Player 2\Lifebar Flashes Red D022672E 0000 8122672E 00CF crc FBB9F1FA-6BF88689-C:45 gn Duck Dodgers Starring Daffy Duck (U) cn Infinite\Lives 80026A67 0063 cn Infinite\Quarks 81159282 FFFF cn Infinite\Atoms 81159286 FFFF crc A273AB56-DA33DB9A-C:45 gn Duke Nukem 64 (U) cn In-Game Cheats\Open Cheat Menu 801012D8 0001 cn In-Game Cheats\Open Invincibility Cheat 801012DC 0001 cn In-Game Cheats\Open Monsters Cheat 801012E0 0001 cn In-Game Cheats\Open All Items Cheat 801012E4 0001 cn In-Game Cheats\Open Goto Level ?? Cheat 801012E8 0001 cn Infinite Night Vision 812A5A5C 0640 cn Infinite Holoduke 812A5A2C 0640 cn Infinite Portable Medikit 812A5A4A 0064 cn Infinite Protective Boots 812A5AA2 00C8 cn In-Game Cheats\Invincibility Cheat On 802AAA68 0001 cn In-Game Cheats\Invincibility Cheat Off 802AAA68 0000 cn In-Game Cheats\Monsters Cheat On 802AABDB 0000 cn In-Game Cheats\Monsters Cheat Off 802AABDB 0001 cn Infinite\Armor 812A5A92 0064 cn Infinite\Vitamin K 812A5A90 0190 cn Infinite\Jet Pack 812A5A8E 0640 cn Infinite\Scuba Gear 812A5A8C 1900 cn Have All Keys 802A5A47 000F cn Player 1\Infinite Health\Hollywood Holocaust 80247463 00FF cn Player 1\Infinite Health\Gun Crazy 80247D53 00FF cn Player 1\Infinite Health\Death Row 80246E5F 00FF cn Player 1\Infinite Health\Toxic Dump 80246D83 00FF cn Player 1\Infinite Health\Launch Facility 80248223 00FF cn Player 1\Infinite Health\The Abyss 80246E07 00FF cn Player 1\Infinite Health\Battleload 80246F67 00FF cn Player 1\Infinite Health\Duke Burger 8024761B 00FF cn Player 1\Infinite Health\Spaceport 8024735B 00FF cn Player 1\Infinite Health\Incubator 80246D2B 00FF cn Player 1\Infinite Health\Warp Factor 8024709B 00FF cn Player 1\Infinite Health\Fusion Station 80247723 00FF cn Player 1\Infinite Health\Occupied Territory 80246DDB 00FF cn Player 1\Infinite Health\Tiberius Station 80246CA7 00FF cn Player 1\Infinite Health\Lunar Reactor 80246C4F 00FF cn Player 1\Infinite Health\Dark Side 802473B3 00FF cn Player 1\Infinite Health\Dread Nought 80246D2B 00FF cn Player 1\Infinite Health\Overlord 80247513 00FF cn Player 1\Infinite Health\Lunatic Fringe 80246D2B 00FF cn Player 1\Infinite Health\Raw Meat 80246DDB 00FF cn Player 1\Infinite Health\Bank Roll 802471A3 00FF cn Player 1\Infinite Health\Flood Zone 80246D2B 00FF cn Player 1\Infinite Health\L.A. Rumble 80246EE3 00FF cn Player 1\Infinite Health\Movie Set 80246DAF 00FF cn Player 1\Infinite Health\Rabit Transit 8024869B 00FF cn Player 1\Infinite Health\Fahrenheith 8024735B 00FF cn Player 1\Infinite Health\Hotel Hell 80246D83 00FF cn Player 1\Infinite Health\Stadium 8024979F 00FF cn Player 1\Infinite Health\Area 51 8024774F 00FF cn Player 1\Infinite Health\Free Way 80247E5B 00FF cn Player 1\Infinite Health\Castle Dukenstein 802490BF 00FF cn Player 1\Infinite Health\Piracy 80247673 00FF cn Player 1\Infinite Health\Shaft 80247AEB 00FF cn Player 1\Infinite Health\Noctis Labyrinthus 80247C1F 00FF cn Player 2\Infinite Health\Hollywood Holocaust 8124D526 00FF cn Player 2\Infinite Health\Gun Crazy 8124E57A 00FF cn Player 2\Infinite Health\Death Row 8124AFAE 00FF cn Player 2\Infinite Health\Toxic Dump 81251BCA 00FF cn Player 2\Infinite Health\Launch Facility 8124AEA6 00FF cn Player 2\Infinite Health\The Abyss 8124FD5E 00FF cn Player 2\Infinite Health\BattleLord 81246CFE 00FF cn Player 2\Infinite Health\Spaceport 8124B13A 00FF cn Player 2\Infinite Health\Incubator 8124CEF6 00FF cn Player 2\Infinite Health\Warp Factor 8124ED8E 00FF cn Player 2\Infinite Health\Fusion Station 81250336 00FF cn Player 2\Infinite Health\Occupied Territory 8124AC96 00FF cn Player 2\Infinite Health\Tiberius Station 8124C8F2 00FF cn Player 2\Infinite Health\Lunar Reactor 81247C1E 00FF cn Player 2\Infinite Health\Dark Side 8124E1DE 00FF cn Player 2\Infinite Health\Dreadnought 81249562 00FF cn Player 2\Infinite Health\Overlord 81247646 00FF cn Player 2\Infinite Health\Raw Meat 8124E052 00FF cn Player 2\Infinite Health\Bank Roll 8124DE6E 00FF cn Player 2\Infinite Health\Flood Zone 8124D736 00FF cn Player 2\Infinite Health\L.A. Rumble 8124BF52 00FF cn Player 2\Infinite Health\Movie Set 81248382 00FF cn Player 2\Infinite Health\Rabid Transit 8124D86A 00FF cn Player 2\Infinite Health\Fahrenheit 8124A1C2 00FF cn Player 2\Infinite Health\Hotel Hell 8124D526 00FF cn Player 2\Infinite Health\Stadium 8124924A 00FF cn Player 2\Infinite Health\Castle Dukenstein 81249092 00FF cn Player 2\Infinite Health\Piracy 81248ABA 00FF cn Player 2\Infinite Health\Shaft 812477A6 00FF cn Player 3\Infinite Health\Hollywood Holocaust 8124BC0E 00FF cn Player 3\Infinite Health\Gun Crazy 8124C086 00FF cn Player 3\Infinite Health\Death Row 8124AF2A 00FF cn Player 3\Infinite Health\Toxic Dump 8125051A 00FF cn Player 3\Infinite Health\Launch Facility 8124AD9E 00FF cn Player 3\Infinite Health\The Abyss 8124FD32 00FF cn Player 3\Infinite Health\BattleLord 81246CD2 00FF cn Player 3\Infinite Health\Spaceport 8124B10E 00FF cn Player 3\Infinite Health\Incubator 8124B1EA 00FF cn Player 3\Infinite Health\Warp Factor 812482FE 00FF cn Player 3\Infinite Health\Fusion Station 8125030A 00FF cn Player 3\Infinite Health\Occupied Territory 8124AC6A 00FF cn Player 3\Infinite Health\Tiberius Station 8124C8C6 00FF cn Player 3\Infinite Health\Lunar Reactor 81247BF2 00FF cn Player 3\Infinite Health\Dark Side 8124E1B2 00FF cn Player 3\Infinite Health\Dreadnought 81249536 00FF cn Player 3\Infinite Health\Overlord 81246EB6 00FF cn Player 3\Infinite Health\Raw Meat 8124E026 00FF cn Player 3\Infinite Health\Bank Roll 8124992A 00FF cn Player 3\Infinite Health\Flood Zone 8124D70A 00FF cn Player 3\Infinite Health\L.A. Rumble 8124BF26 00FF cn Player 3\Infinite Health\Movie Set 81248356 00FF cn Player 3\Infinite Health\Rabid Transit 8124D83E 00FF cn Player 3\Infinite Health\Fahrenheit 8124A196 00FF cn Player 3\Infinite Health\Hotel Hell 8124D4FA 00FF cn Player 3\Infinite Health\Stadium 8124921E 00FF cn Player 3\Infinite Health\Castle Dukenstein 81248432 00FF cn Player 3\Infinite Health\Piracy 81248A8E 00FF cn Player 3\Infinite Health\Shaft 8124777A 00FF cn Player 4\Infinite Health\Hollywood Holocaust 8124B76A 00FF cn Player 4\Infinite Health\Gun Crazy 8124B922 00FF cn Player 4\Infinite Health\Death Row 8124AEFE 00FF cn Player 4\Infinite Health\Toxic Dump 8124DDBE 00FF cn Player 4\Infinite Health\Launch Facility 8124AD1A 00FF cn Player 4\Infinite Health\The Abyss 8124E3C2 00FF cn Player 4\Infinite Health\BattleLord 81246CA6 00FF cn Player 4\Infinite Health\Spaceport 8124979E 00FF cn Player 4\Infinite Health\Incubator 81247F0A 00FF cn Player 4\Infinite Health\Warp Factor 812482D2 00FF cn Player 4\Infinite Health\Fusion Station 81248172 00FF cn Player 4\Infinite Health\Occupied Territory 8124AC3E 00FF cn Player 4\Infinite Health\Tiberius Station 8124C89A 00FF cn Player 4\Infinite Health\Lunar Reactor 81247BC6 00FF cn Player 4\Infinite Health\Dark Side 81247932 00FF cn Player 4\Infinite Health\Dreadnought 8124950A 00FF cn Player 4\Infinite Health\Overlord 81246E8A 00FF cn Player 4\Infinite Health\Raw Meat 8124DFFA 00FF cn Player 4\Infinite Health\Bank Roll 812498FE 00FF cn Player 4\Infinite Health\Flood Zone 81247F36 00FF cn Player 4\Infinite Health\L.A. Rumble 8124A3A6 00FF cn Player 4\Infinite Health\Movie Set 8124832A 00FF cn Player 4\Infinite Health\Rabid Transit 8124B1BE 00FF cn Player 4\Infinite Health\Fahrenheit 8124A16A 00FF cn Player 4\Infinite Health\Hotel Hell 8124C68A 00FF cn Player 4\Infinite Health\Stadium 812491C6 00FF cn Player 4\Infinite Health\Castle Dukenstein 81248406 00FF cn Player 4\Infinite Health\Piracy 81248A62 00FF cn Player 4\Infinite Health\Shaft 8124774E 00FF cn Player 1\Have\Boots 802A5AB9 0001 cn Player 1\Have\Pistol 802A5ABA 0001 cn Player 1\Have\Shotgun 802A5ABB 0001 cn Player 1\Have\SMG 802A5ABC 0001 cn Player 1\Have\Grenade Launcher 802A5ABD 0001 cn Player 1\Have\Pipe Bombs 802A5ABE 0001 cn Player 1\Have\Shrinker 802A5ABF 0001 cn Player 1\Have\Expander 802A5AC0 0001 cn Player 1\Have\Missile Launcher 802A5AC1 0001 cn Player 1\Have\Plasma Cannon 802A5AC2 0001 cn Player 1\Have\Laser Trip Bomb 802A5AC3 0001 cn Player 1\Infinite Ammo\Pistol 802A5A01 00FF cn Player 1\Infinite Ammo\Shotgun 802A5A03 00FF cn Player 1\Infinite Ammo\SMG's 802A5A05 00FF cn Player 1\Infinite Ammo\Grenade Launcher 802A5A07 00FF cn Player 1\Infinite Ammo\Pipe Bombs 802A5A09 00FF cn Player 1\Infinite Ammo\Shrinker 802A5A0B 00FF cn Player 1\Infinite Ammo\Expander 802A5A0D 00FF cn Player 1\Infinite Ammo\Missile Launcher 802A5A0F 00FF cn Player 1\Infinite Ammo\Plasma Cannon 802A5A11 00FF cn Player 1\Infinite Ammo\Laser Trip Bomb 802A5A13 00FF cn Player 2\Have\Boots 802A5E45 0001 cn Player 2\Have\Pistol 802A5E46 0001 cn Player 2\Have\Shotgun 802A5E47 0001 cn Player 2\Have\SMG 802A5E48 0001 cn Player 2\Have\Grenade Launcher 802A5E49 0001 cn Player 2\Have\Pipe Bomb 802A5E4A 0001 cn Player 2\Have\Shrinker 802A5E4B 0001 cn Player 2\Have\Expander 802A5E4C 0001 cn Player 2\Have\Missle Launcher 802A5E4D 0001 cn Player 2\Have\Plasma Cannon 802A5E4E 0001 cn Player 2\Have\Laser Trip Bomb 802A5E4F 0001 cn Player 2\Infinite Ammo\Pistol 802A5D8C 00FF cn Player 2\Infinite Ammo\Shotgun 802A5D8F 00FF cn Player 2\Infinite Ammo\SMG's 802A5D91 00FF cn Player 2\Infinite Ammo\Grenade Launcher 802A5D93 00FF cn Player 2\Infinite Ammo\Pipe Bombs 802A5D95 00FF cn Player 2\Infinite Ammo\Shrinker 802A5D97 00FF cn Player 2\Infinite Ammo\Expander 802A5D99 00FF cn Player 2\Infinite Ammo\Missile Launcher 802A5D9B 00FF cn Player 2\Infinite Ammo\Laser Trip Bomb 802A5D9D 00FF cn Player 2\Infinite Ammo\Plasma Cannon 802A5D9F 00FF cn Player 3\Have\Boots 802A61D1 0001 cn Player 3\Have\Pistol 802A61D2 0001 cn Player 3\Have\Shotgun 802A61D3 0001 cn Player 3\Have\SMG 802A61D4 0001 cn Player 3\Have\Grenade Launcher 802A61D5 0001 cn Player 3\Have\Pipe Bomb 802A61D6 0001 cn Player 3\Have\Shrinker 802A61D7 0001 cn Player 3\Have\Expander 802A61D8 0001 cn Player 3\Have\Missle Launcher 802A61D9 0001 cn Player 3\Have\Plasma Cannon 802A61DA 0001 cn Player 3\Have\Laser Trip Bomb 802A61DB 0001 cn Player 3\Infinite Ammo\Pistol 802A6119 00FF cn Player 3\Infinite Ammo\Shotgun 802A611B 00FF cn Player 3\Infinite Ammo\SMG's 802A611D 00FF cn Player 3\Infinite Ammo\Grenade Launcher 802A611F 00FF cn Player 3\Infinite Ammo\Pipe Bombs 802A6121 00FF cn Player 3\Infinite Ammo\Shrinker 802A6123 00FF cn Player 3\Infinite Ammo\Expander 802A6125 00FF cn Player 3\Infinite Ammo\Missile Launcher 802A6127 00FF cn Player 3\Infinite Ammo\Laser Trip Bomb 802A6129 00FF cn Player 3\Infinite Ammo\Plasma Cannon 802A612B 00FF cn Player 4\Have\Boots 802A655D 0001 cn Player 4\Have\Pistol 802A655E 0001 cn Player 4\Have\SMG 802A655F 0001 cn Player 4\Have\Submachine Guns 802A6560 0001 cn Player 4\Have\Grenade Launcher 802A6561 0001 cn Player 4\Have\Pipe Bomb 802A6562 0001 cn Player 4\Have\Shrinker 802A6563 0001 cn Player 4\Have\Expander 802A6564 0001 cn Player 4\Have\Missle Launcher 802A6565 0001 cn Player 4\Have\Plasma Cannon 802A6566 0001 cn Player 4\Have\Laser Trip Bomb 802A6567 0001 cn Player 4\Infinite Ammo\Pistol 802A64A5 00FF cn Player 4\Infinite Ammo\Shotgun 802A64A7 00FF cn Player 4\Infinite Ammo\SMG's 802A64A9 00FF cn Player 4\Infinite Ammo\Grenade Launcher 802A64AB 00FF cn Player 4\Infinite Ammo\Pipe Bombs 802A64AD 00FF cn Player 4\Infinite Ammo\Shrinker 802A64AF 00FF cn Player 4\Infinite Ammo\Expander 802A64B1 00FF cn Player 4\Infinite Ammo\Missile Launcher 802A64B3 00FF cn Player 4\Infinite Ammo\Laser Trip Bomb 802A64B5 00FF cn Player 4\Infinite Ammo\Plasma Cannon 802A64B7 00FF crc DF574191-9EB5123D-C:45 gn Earthworm Jim 3D (U) cn Infinite Egg Chucker Ammo 800C69BF 00FA cn Infinite Cleaver Ammo 800C6A1F 00FA cn Infinite Blaster Ammo 810C6916 03E7 cn Infinite Rocket Launcher Ammo 810C6946 03E7 cn Infinite Banana Peel Ammo 810C6976 03E7 cn Infinite Green Slimer Ammo 810C69A6 03E7 cn Infinite Shotgun Ammo 810C69EE 03E7 cn Infinite Music Gun Ammo 810C6A06 03E7 cn Infinite Boomerang Knives Ammo 810C6A1E 03E7 cn Infinite Mushroom Ammo 810C6E36 03E7 cn Have 231 Marbles D00E9FF3 0000 800E9FF3 03E7 cn Infinite Health 800C690F 0064 cn Infinite Lives 800C6913 0063 cn Infinite Laser Ammo 800C6917 00FA cn Have All Gold Udders 50002802 0000 810C625A 0101 crc BDF9766D-BD068D70-C:45 gn ECW Hardcore Revolut (U) cn VS & Tournment Mode\Player 1\Infinite Health D02931FD 0029 81293380 0000 D02931FD 0029 81293382 0000 cn VS & Tournment Mode\Player 1\Infinite Health D02931FD 0029 81293380 00FF D02931FD 0029 81293382 00FF cn VS & Tournment Mode\Player 1\Super Strength D02931FD 0029 812933DA FFFF cn VS & Tournment Mode\Player 1\Invincible D02931FD 0029 812933DE FFFF cn VS & Tournment Mode\Player 1\Super Speed D02931FD 0029 812933E2 FFFF cn VS & Tournment Mode\Player 1\Super Stamina D02931FD 0029 812933E6 FFFF cn VS & Tournment Mode\Player 1\Instant Recovery D02931FD 0029 812933EA FFFF cn VS & Tournment Mode\Player 1\Can't Be Pinned D02931FD 0029 8129330A FFFF cn VS & Tournment Mode\Player 1\Can't Be Counted Out D02931FD 0029 8129327E 0384 cn VS & Tournment Mode\Player 2\Infinite Health D02931FD 0029 81294620 0000 D02931FD 0029 81294622 0000 cn VS & Tournment Mode\Player 2\Infinite Health D02931FD 0029 81294620 00FF D02931FD 0029 81294622 00FF cn VS & Tournment Mode\Player 2\Super Strength D02931FD 0029 8129467A FFFF cn VS & Tournment Mode\Player 2\Invincible D02931FD 0029 8129467E FFFF cn VS & Tournment Mode\Player 2\Super Speed D02931FD 0029 81294682 FFFF cn VS & Tournment Mode\Player 2\Super Stamina D02931FD 0029 81294686 FFFF cn VS & Tournment Mode\Player 2\Instant Recovery D02931FD 0029 8129468A FFFF cn VS & Tournment Mode\Player 2\Can't Be Pinned D02931FD 0029 812945AA FFFF cn VS & Tournment Mode\Player 2\Can't Be Counted Out D02931FD 0029 8129451E 0384 cn All Tag Team Modes\Player 1\Infinite Health D029A98D 0029 8129AB10 0000 D029A98D 0029 8129AB12 0000 cn All Tag Team Modes\Player 1\Infinite Health D029A98D 0029 8129AB10 00FF D029A98D 0029 8129AB12 00FF cn All Tag Team Modes\Player 1\Super Strength D029A98D 0029 8129AB6A FFFF cn All Tag Team Modes\Player 1\Invincible D029A98D 0029 8129AB6E FFFF cn All Tag Team Modes\Player 1\Super Speed D029A98D 0029 8129AB72 FFFF cn All Tag Team Modes\Player 1\Super Stamina D029A98D 0029 8129AB76 FFFF cn All Tag Team Modes\Player 1\Instant Recovery D029A98D 0029 8129AB7A FFFF cn All Tag Team Modes\Player 1\Can't Be Pinned D029A98D 0029 8129AA9A FFFF cn All Tag Team Modes\Player 1\Can't Be Counted Out D029A98D 0029 8129AA0E 0384 cn All Tag Team Modes\Player 2\Infinite Health D029A98D 0029 8129BDB0 0000 D029A98D 0029 8129BDB2 0000 cn All Tag Team Modes\Player 2\Infinite Health D029A98D 0029 8129BDB0 00FF D029A98D 0029 8129BDB2 00FF cn All Tag Team Modes\Player 2\Super Strength D029A98D 0029 8129BE0A FFFF cn All Tag Team Modes\Player 2\Invincible D029A98D 0029 8129BE0E FFFF cn All Tag Team Modes\Player 2\Super Speed D029A98D 0029 8129BE12 FFFF cn All Tag Team Modes\Player 2\Super Stamina D029A98D 0029 8129BE16 FFFF cn All Tag Team Modes\Player 2\Instant Recovery D029A98D 0029 8129BE1A FFFF cn All Tag Team Modes\Player 2\Can't Be Pinned D029A98D 0029 8129BD3A FFFF cn All Tag Team Modes\Player 2\Can't Be Counted Out D029A98D 0029 8129BCAE 0384 cn All Tag Team Modes\Player 3\Infinite Health D029A98D 0029 8129D050 0000 D029A98D 0029 8129D052 0000 cn All Tag Team Modes\Player 3\Infinite Health D029A98D 0029 8129D050 00FF D029A98D 0029 8129D052 00FF cn All Tag Team Modes\Player 3\Super Strength D029A98D 0029 8129D0AA FFFF cn All Tag Team Modes\Player 3\Invincible D029A98D 0029 8129D0AE FFFF cn All Tag Team Modes\Player 3\Super Speed D029A98D 0029 8129D0B2 FFFF cn All Tag Team Modes\Player 3\Super Stamina D029A98D 0029 8129D0B6 FFFF cn All Tag Team Modes\Player 3\Instant Recovery D029A98D 0029 8129D0BA FFFF cn All Tag Team Modes\Player 3\Can't Be Pinned D029A98D 0029 8129CFDA FFFF cn All Tag Team Modes\Player 3\Can't Be Counted Out D029A98D 0029 8129CF4E 0384 cn All Tag Team Modes\Player 4\Infinite Health D029A98D 0029 8129E2F0 0000 D029A98D 0029 8129E2F2 0000 cn All Tag Team Modes\Player 4\Infinite Health D029A98D 0029 8129E2F0 00FF D029A98D 0029 8129E2F2 00FF cn All Tag Team Modes\Player 4\Super Strength D029A98D 0029 8129E34A FFFF cn All Tag Team Modes\Player 4\Invincible D029A98D 0029 8129E34E FFFF cn All Tag Team Modes\Player 4\Super Speed D029A98D 0029 8129E352 FFFF cn All Tag Team Modes\Player 4\Super Stamina D029A98D 0029 8129E356 FFFF cn All Tag Team Modes\Player 4\Instant Recovery D029A98D 0029 8129E35A FFFF cn All Tag Team Modes\Player 4\Can't Be Pinned D029A98D 0029 8129E27A FFFF cn All Tag Team Modes\Player 4\Can't Be Counted Out D029A98D 0029 8129E1EE 0384 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Infinite Health D029A87D 0029 8129AA00 0000 D029A87D 0029 8129AA02 0000 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Infinite Health D029A87D 0029 8129AA00 00FF D029A87D 0029 8129AA02 00FF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Super Strength D029A87D 0029 8129AA5A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Invincible D029A87D 0029 8129AA5E FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Super Speed D029A87D 0029 8129AA62 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Super Stamina D029A87D 0029 8129AA66 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Instant Recovery D029A87D 0029 8129AA6A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Can't Be Pinned D029A87D 0029 8129A98A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 1\Can't Be Counted Out D029A87D 0029 8129A8FE 0384 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Infinite Health D029A87D 0029 8129BCA0 0000 D029A87D 0029 8129BCA2 0000 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Infinite Health D029A87D 0029 8129BCA0 00FF D029A87D 0029 8129BCA2 00FF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Super Strength D029A87D 0029 8129BCFA FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Invincible D029A87D 0029 8129BCFE FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Super Speed D029A87D 0029 8129BD02 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Super Stamina D029A87D 0029 8129BD06 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Instant Recovery D029A87D 0029 8129BD0A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Can't Be Pinned D029A87D 0029 8129BC2A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 2\Can't Be Counted Out D029A87D 0029 8129BB9E 0384 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Infinite Health D029A87D 0029 8129CF40 0000 D029A87D 0029 8129CF42 0000 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Infinite Health D029A87D 0029 8129CF40 00FF D029A87D 0029 8129CF42 00FF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Super Strength D029A87D 0029 8129CF9A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Invincible D029A87D 0029 8129CF9E FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Super Speed D029A87D 0029 8129CFA2 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Super Stamina D029A87D 0029 8129CFA6 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Instant Recovery D029A87D 0029 8129CFAA FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Can't Be Pinned D029A87D 0029 8129CECA FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 3\Can't Be Counted Out D029A87D 0029 8129CE3E 0384 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Infinite Health D029A87D 0029 8129E1E0 0000 D029A87D 0029 8129E1E2 0000 cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Infinite Health D029A87D 0029 8129E1E0 00FF D029A87D 0029 8129E1E2 00FF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Super Strength D029A87D 0029 8129E23A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Invincible D029A87D 0029 8129E23E FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Super Speed D029A87D 0029 8129E242 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Super Stamina D029A87D 0029 8129E246 FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Instant Recovery D029A87D 0029 8129E24A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Can't Be Pinned D029A87D 0029 8129E16A FFFF cn Tornado, Lumberjack, 1-On-3, 3-On-1 Modes\Player 4\Can't Be Counted Out D029A87D 0029 8129E0DE 0384 cn Battle Royal Mode\Player 1\Infinite Health D029A66D 0029 8129A7F0 0000 D029A66D 0029 8129A7F2 0000 cn Battle Royal Mode\Player 1\Infinite Health D029A66D 0029 8129A7F0 00FF D029A66D 0029 8129A7F2 00FF cn Battle Royal Mode\Player 1\Super Strength D029A66D 0029 8129A84A FFFF cn Battle Royal Mode\Player 1\Invincible D029A66D 0029 8129A84E FFFF cn Battle Royal Mode\Player 1\Super Speed D029A66D 0029 8129A852 FFFF cn Battle Royal Mode\Player 1\Super Stamina D029A66D 0029 8129A856 FFFF cn Battle Royal Mode\Player 1\Instant Recovery D029A66D 0029 8129A85A FFFF cn Battle Royal Mode\Player 1\Can't Be Pinned D029A66D 0029 8129A77A FFFF cn Battle Royal Mode\Player 1\Can't Be Counted Out D029A66D 0029 8129A6EE 0384 cn Battle Royal Mode\Player 2\Infinite Health D029A66D 0029 8129BA90 0000 D029A66D 0029 8129BA92 0000 cn Battle Royal Mode\Player 2\Infinite Health D029A66D 0029 8129BA90 00FF D029A66D 0029 8129BA92 00FF cn Battle Royal Mode\Player 2\Super Strength D029A66D 0029 8129BAEA FFFF cn Battle Royal Mode\Player 2\Invincible D029A66D 0029 8129BAEE FFFF cn Battle Royal Mode\Player 2\Super Speed D029A66D 0029 8129BAF2 FFFF cn Battle Royal Mode\Player 2\Super Stamina D029A66D 0029 8129BAF6 FFFF cn Battle Royal Mode\Player 2\Instant Recovery D029A66D 0029 8129BAFA FFFF cn Battle Royal Mode\Player 2\Can't Be Pinned D029A66D 0029 8129BA1A FFFF cn Battle Royal Mode\Player 2\Can't Be Counted Out D029A66D 0029 8129B98E 0384 cn Battle Royal Mode\Player 3\Infinite Health D029A66D 0029 8129CD30 0000 D029A66D 0029 8129CD32 0000 cn Battle Royal Mode\Player 3\Infinite Health D029A66D 0029 8129CD30 00FF D029A66D 0029 8129CD32 00FF cn Battle Royal Mode\Player 3\Super Strength D029A66D 0029 8129CD8A FFFF cn Battle Royal Mode\Player 3\Invincible D029A66D 0029 8129CD8E FFFF cn Battle Royal Mode\Player 3\Super Speed D029A66D 0029 8129CD92 FFFF cn Battle Royal Mode\Player 3\Super Stamina D029A66D 0029 8129CD96 FFFF cn Battle Royal Mode\Player 3\Instant Recovery D029A66D 0029 8129CD9A FFFF cn Battle Royal Mode\Player 3\Can't Be Pinned D029A66D 0029 8129CCBA FFFF cn Battle Royal Mode\Player 3\Can't Be Counted Out D029A66D 0029 8129CC2E 0384 cn Battle Royal Mode\Player 4\Infinite Health D029A66D 0029 8129DFD0 0000 D029A66D 0029 8129DFD2 0000 cn Battle Royal Mode\Player 4\Infinite Health D029A66D 0029 8129DFD0 00FF D029A66D 0029 8129DFD2 00FF cn Battle Royal Mode\Player 4\Super Strength D029A66D 0029 8129E02A FFFF cn Battle Royal Mode\Player 4\Invincible D029A66D 0029 8129E02E FFFF cn Battle Royal Mode\Player 4\Super Speed D029A66D 0029 8129E032 FFFF cn Battle Royal Mode\Player 4\Super Stamina D029A66D 0029 8129E036 FFFF cn Battle Royal Mode\Player 4\Instant Recovery D029A66D 0029 8129E03A FFFF cn Battle Royal Mode\Player 4\Can't Be Pinned D029A66D 0029 8129DF5A FFFF cn Battle Royal Mode\Player 4\Can't Be Counted Out D029A66D 0029 8129DECE 0384 cn 1 On 2 & 2 On 1 Modes\Player 1\Infinite Health D0296E4D 0029 81296FD0 0000 D0296E4D 0029 81296FD2 0000 cn 1 On 2 & 2 On 1 Modes\Player 1\Infinite Health D0296E4D 0029 81296FD0 00FF D0296E4D 0029 81296FD2 00FF cn 1 On 2 & 2 On 1 Modes\Player 1\Super Strength D0296E4D 0029 8129702A FFFF cn 1 On 2 & 2 On 1 Modes\Player 1\Invincible D0296E4D 0029 8129702E FFFF cn 1 On 2 & 2 On 1 Modes\Player 1\Super Speed D0296E4D 0029 81297032 FFFF cn 1 On 2 & 2 On 1 Modes\Player 1\Super Stamina D0296E4D 0029 81297036 FFFF cn 1 On 2 & 2 On 1 Modes\Player 1\Instant Recovery D0296E4D 0029 8129703A FFFF cn 1 On 2 & 2 On 1 Modes\Player 1\Can't Be Pinned D0296E4D 0029 81296F5A FFFF cn 1 On 2 & 2 On 1 Modes\Player 1\Can't Be Counted Out D0296E4D 0029 81296ECE 0384 cn 1 On 2 & 2 On 1 Modes\Player 2\Infinite Health D0296E4D 0029 81298270 0000 D0296E4D 0029 81298272 0000 cn 1 On 2 & 2 On 1 Modes\Player 2\Infinite Health D0296E4D 0029 81298270 00FF D0296E4D 0029 81298272 00FF cn 1 On 2 & 2 On 1 Modes\Player 2\Super Strength D0296E4D 0029 812982CA FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Invincible D0296E4D 0029 812982CE FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Super Speed D0296E4D 0029 812982D2 FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Super Stamina D0296E4D 0029 812982D6 FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Instant Recovery D0296E4D 0029 812982DA FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Can't Be Pinned D0296E4D 0029 812981FA FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Can't Be Counted Out D0296E4D 0029 8129816E 0384 cn 1 On 2 & 2 On 1 Modes\Player 2\Infinite Health D0296E4D 0029 81299510 0000 D0296E4D 0029 81299512 0000 cn 1 On 2 & 2 On 1 Modes\Player 2\Infinite Health D0296E4D 0029 81299510 00FF D0296E4D 0029 81299512 00FF cn 1 On 2 & 2 On 1 Modes\Player 2\Super Strength D0296E4D 0029 8129956A FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Invincible D0296E4D 0029 8129956E FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Super Speed D0296E4D 0029 81299572 FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Super Stamina D0296E4D 0029 81299576 FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Instant Recovery D0296E4D 0029 8129957A FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Can't Be Pinned D0296E4D 0029 8129949A FFFF cn 1 On 2 & 2 On 1 Modes\Player 2\Can't Be Counted Out D0296E4D 0029 8129940E 0384 cn 3 Way Dance Mode\Player 1\Infinite Health D0296C3D 0029 81296DC0 0000 D0296C3D 0029 81296DC2 0000 cn 3 Way Dance Mode\Player 1\Infinite Health D0296C3D 0029 81296DC0 00FF D0296C3D 0029 81296DC2 00FF cn 3 Way Dance Mode\Player 1\Super Strength D0296C3D 0029 81296E1A FFFF cn 3 Way Dance Mode\Player 1\Invincible D0296C3D 0029 81296E1E FFFF cn 3 Way Dance Mode\Player 1\Super Speed D0296C3D 0029 81296E22 FFFF cn 3 Way Dance Mode\Player 1\Super Stamina D0296C3D 0029 81296E26 FFFF cn 3 Way Dance Mode\Player 1\Instant Recovery D0296C3D 0029 81296E2A FFFF cn 3 Way Dance Mode\Player 1\Can't Be Pinned D0296C3D 0029 81296D4A FFFF cn 3 Way Dance Mode\Player 1\Can't Be Counted Out D0296C3D 0029 81296CBE 0384 cn 3 Way Dance Mode\Player 2\Infinite Health D0296C3D 0029 81298060 0000 D0296C3D 0029 81298062 0000 cn 3 Way Dance Mode\Player 2\Infinite Health D0296C3D 0029 81298060 00FF D0296C3D 0029 81298062 00FF cn 3 Way Dance Mode\Player 2\Super Strength D0296C3D 0029 812980BA FFFF cn 3 Way Dance Mode\Player 2\Invincible D0296C3D 0029 812980BE FFFF cn 3 Way Dance Mode\Player 2\Super Speed D0296C3D 0029 812980C2 FFFF cn 3 Way Dance Mode\Player 2\Super Stamina D0296C3D 0029 812980C6 FFFF cn 3 Way Dance Mode\Player 2\Instant Recovery D0296C3D 0029 812980CA FFFF cn 3 Way Dance Mode\Player 2\Can't Be Pinned D0296C3D 0029 81297FEA FFFF cn 3 Way Dance Mode\Player 2\Can't Be Counted Out D0296C3D 0029 81297F5E 0384 cn 3 Way Dance Mode\Player 3\Infinite Health D0296C3D 0029 81299300 0000 D0296C3D 0029 81299302 0000 cn 3 Way Dance Mode\Player 3\Infinite Health D0296C3D 0029 81299300 00FF D0296C3D 0029 81299302 00FF cn 3 Way Dance Mode\Player 3\Super Strength D0296C3D 0029 8129935A FFFF cn 3 Way Dance Mode\Player 3\Invincible D0296C3D 0029 8129935E FFFF cn 3 Way Dance Mode\Player 3\Super Speed D0296C3D 0029 81299362 FFFF cn 3 Way Dance Mode\Player 3\Super Stamina D0296C3D 0029 81299366 FFFF cn 3 Way Dance Mode\Player 3\Instant Recovery D0296C3D 0029 8129936A FFFF cn 3 Way Dance Mode\Player 3\Can't Be Pinned D0296C3D 0029 8129928A FFFF cn 3 Way Dance Mode\Player 3\Can't Be Counted Out D0296C3D 0029 812991FE 0384 cn Character Modifier\Player 1 80122773 ???? 000D:"Cyrus the Virus",000F:"Mack Daddy",0015:"Gertner",0019:"Jeff Jones",001C:"Beulah",001D:"Mad Goat",001F:"Nurse",0022:"Tommy Rich",0025:"Santoro",0027:"Sound Guy",0028:"The Sheik",0029:"Skull",002A:"H Slash",002E:"Louie",0030:"J Styles",0032:"Taz",0033:"Trainer",0036:"Excel" cn Character Modifier\Player 2 80122783 ???? 000D:"Cyrus the Virus",000F:"Mack Daddy",0015:"Gertner",0019:"Jeff Jones",001C:"Beulah",001D:"Mad Goat",001F:"Nurse",0022:"Tommy Rich",0025:"Santoro",0027:"Sound Guy",0028:"The Sheik",0029:"Skull",002A:"H Slash",002E:"Louie",0030:"J Styles",0032:"Taz",0033:"Trainer",0036:"Excel" cn Create A Wrestler\Infinite Move % 80131600 0024 cn Create A Wrestler\Infinite Attribute Points 8115DD52 0000 crc F2A653CB-60633B3B-C:45 gn Elmo's Letter Adventure (U) cn Found All Letters 810ACBA2 000C cn Infinite Strikes 810A760A 0000 cn Have No Letters cd Keep you kid busy for hours!!! 810ACBA2 0000 crc 02B1538F-C94B88D0-C:45 gn Elmo's Number Journey (U) cn Found All Numbers 810ACFB2 000C cn Infinite Strikes 810A7A76 0000 cn Have No Numbers cd Keep you kid busy for hours!!! 810ACFB2 0000 crc 07861842-A12EBC9F-C:45 gn Excitebike 64 (U) cn Auto-Pilot Always On Turbo (Original Excitebike Mode) 810E3142 19AA cn Unlock\Difficulties & All Special Tracks 810F2D50 FFFF cn Unlock\Silver & Gold Cup 810F2D4E 0003 cn Max Stunt Points 810E4D18 0098 810E4D1A 967F cn Always Low Temp 810E4F98 0000 810E4F9A 0000 cn Steering Control 800C9E50 0040 cn Super Speed For All 800CA9A0 0040 800CA9A1 0070 cn Power Turbo 800CA99C 0040 800CA99D 00E0 cn No\Overheating 800CA984 00C3 cn No\Collision Drivers 800D9D34 0040 cn Fast\Movement (Player) 800D9D65 00AF cn Slow\Movement (Player) 800D9D65 0060 cn Fast\Movement (Drones) 800D9D55 00A0 cn Slow\Movement (Drones) 800D9D55 0060 cn Earthquake Mode 810D7010 3AD0 crc FDA245D2-A74A3D47-C:45 gn Extreme-G (U) cn Infinite Shields\Player 1 801635F5 00C8 cn Infinite Primary Weapon\Player 1 801635FD 00C8 cn Infinite Turbos\Player 1 801635CB 0003 801635CF 0003 cn Bike Modifier\Player 1 80167C3F ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Infinite Shields\Player 2 80163D65 00C8 cn Infinite Primary Weapon\Player 2 80163D6D 00C8 cn Infinite Turbos\Player 2 80163D3B 0003 80163D3F 0003 cn Bike Modifier\Player 2 80167C8B ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Infinite Shields\Player 3 801644D5 00C8 cn Infinite Primary Weapon\Player 3 801644DD 00C8 cn Infinite Turbos\Player 3 801644AB 0003 801644AF 0003 cn Bike Modifier\Player 3 80167CD7 ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Infinite Shields\Player 4 80164C45 00C8 cn Infinite Primary Weapon\Player 4 80164C4D 00C8 cn Infinite Turbos\Player 4 80164C1B 0003 80164C1F 0003 cn Bike Modifier\Player 4 80167D23 ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Extra Bikes Unlocked 80167C13 0001 80167C17 0003 cn Extra Levels Unlocked 80167C0B 0001 80167C0F 0001 cn All Tracks Unlocked 8019436E 0008 50000264 0000 80167747 0001 50000264 0000 80167873 0001 50000564 0000 8016799F 0001 cn Mode Select 80095F6F ???? 0001:"Boulder",0002:"Fish Eye Lens",0003:"Boulder & Fish Eye Lens",0004:"Magnify",0008:"Anti-Gravity",000A:"Anti-Gravity & Fish Eye Lens",0010:"Wireframe",0011:"Boulder & Wireframe",0020:"Stealth Mode",0040:"Ghost Mode",0080:"Ugly Mode" crc 5CD4150B-470CC2F1-C:45 gn Extreme-G XG2 (U) cn Infinite\Nitros\Player 1 80170B63 0004 80170B67 0004 cn Infinite\Shield\Player 1 80170B8D 00C8 cn Infinite Lasers\Player 1 80170B99 00C8 cn Infinite Nitros\Player 2 801711CB 0004 801711CF 0004 cn Infinite Shield\Player 2 801711F5 00C8 cn Infinite Lasers\Player 2 80171241 00C8 cn Infinite Nitros\Player 3 80171833 0004 80171837 0004 cn Infinite Shield\Player 3 8017185D 00C8 cn Infinite Lasers\Player 3 80171869 00C8 cn Infinite Nitros\Player 4 80171E9B 0004 80171E9F 0004 cn Infinite Shield\Player 4 80171EC5 00C8 cn Infinite Lasers\Player 4 80171ED1 00C8 cn Access\All Tracks 50000BD8 0000 80182F87 0001 cn Access\All Superbikes 50000304 0000 801839CF 0001 cn Access\All Secret Characters cd This code is Fantastic, You have 12 characters to choose from to you race without any bike, just on foot 50000C04 0000 801839CF 0001 cn [Screen Hud Clear] cd If you are using a Plugin other then Jabos and can not see through the Thick Hud then Let the game load 1st before Putting this code on,Or it will give an error and Freeze 80092B8B 0004 crc AE82687A-9A3F388D-C:45 gn F-1 Pole Position 64 (U) cn Always First Place 810BA6DA 0000 crc 52F78805-8B8FCAB7-C:45 gn Fighter's Destiny (U) cn Start with Stars Modifier\Player 1 D0209757 0000 80209757 ???? 0000:"No Stars",0006:"Max Stars" cn Start with Stars Modifier\Player 2 D020B61F 0000 8020B61F ???? 0000:"No Stars",0006:"Max Stars" cn Have 1 Star\Ryuji 8030734E 0001 cn Have 1 Star\Bob 8030734F 0001 cn Have 1 Star\Pierre 80307350 0001 cn Have 1 Star\Meiling 80307351 0001 cn Have 1 Star\Leon 80307352 0001 cn Have 1 Star\Abdul 80307353 0001 cn Have 1 Star\Ninja 80307354 0001 cn Have 1 Star\Tomahawk 80307355 0001 cn Have 1 Star\Valerie 80307356 0001 cn Infinite Health\Player 1 802098A1 0000 802047C3 0000 cn Infinite Health\Player 2 802047C7 0000 8020B769 0000 cn Start on stage 100 on Survival to get Joker 802EF67B 0063 cn Stop timer for Fastest to get Robot 810ADBDC 3F80 cn Always Win Judge's Decision\Player 1 8020B777 FFFF 802098AF 0000 cn Always Win Judge's Decision\Player 2 802098AF FFFF 8020B777 0000 cn Enable Boro 80307349 0001 cn Level Select 8022A84C ???? 0000:"Fire Mountain",0001:"Desert",0002:"Highlands",0003:"Hong Kong",0004:"Coliseum",0005:"Jungle",0006:"Ninja Room",0007:"Suspension Bridge",0008:"Palace",0009:"Observation",000A:"Pasture",000B:"Joker's Room",000C:"Blue Hell Mountain",000D:"Palace" cn Play As\Player 1 802EF622 ???? 0000:"Ryuji",0001:"Bob",0002:"Pierre",0003:"Meiling",0004:"Leon",0005:"Abdul",0006:"Ninja",0007:"Tomahawk",0008:"Boro",0009:"Valerie",000A:"Ushi",000B:"Joker",000C:"The Master",000D:"No Clue" crc AEEF2F45-F97E30F1-C:45 gn Fighter Destiny 2 (U) cn P1 Always Win Judging 801F727A 00FF cn P2 Always Win Judging 801F53AE 00FF cn P1 Always Lose Judging 801F727A 0000 cn P2 Always Lose Judging 801F53AE 0000 cn Max Attack Power-Fighters Arena 801FBF6E 00C7 cn Max Health Power-Fighters Arena 801FBF6F 00C7 cn Max Recovery-Fighters Arena 801FBF70 00C7 cn Low Time 800BA390 0001 crc 32EFC7CB-C3EA3F20-C:45 gn Fighting Force 64 (U) cn Infinite Lives P1 800CE0F3 0003 cn Infinite Lives P2 800CE0F7 0003 cn Infinite Pistol Ammo 8106006C 2400 cn Infinite Rocket Launcher Ammo 81060130 2400 cn Infinite Shotgun Ammo 810601D8 2400 crc A92D52E5-1D26B655-C:45 gn Flying Dragon (U) cn Infinite\Health\Player 1 8020B7B1 00C8 cn Infinite\Special\Player 1 8120AEB4 0190 cn 1 Win to Win\Player 1 D020C27F 0000 8020C27F 0001 cn Infinite\Health\Player 2 8020BC0D 00C8 cn Infinite\Special\Player 2 8120B1B0 0190 cn 1 Win to Win\Player 2 D020C27F 0000 8020C27F 0010 cn Infinite\Money 8121106C 2704 crc 9E330C01-8C0314BA-C:45 gn Forsaken 64 (U) cn Infinite Shields D014E5E2 0011 8114E5E0 1000 cn Enable Battle Mode And Levels 8008ED6E 0012 cn Gore Mode 8008ED67 0012 cn Infinite Lives 8004013C 0005 cn GS Button For 255 Spare0 Missiles 8814E648 00FF crc 3261D479-ED0DBC25-C:45 gn Fox Sports College Hoops '99 (U) cn Trail Follows The Ball 810B4600 4100 cn Programmers Team 81097088 0100 cn Z-Axis Stadium 80098E98 0088 cn Final Four Stadium 80098E98 0089 cn No Fans In Crowd 810CA520 0454 cn Away Team Scores 0 8012A4EA 0000 cn Away Team Scores 150 8012A4EA 0096 cn Home Team Scores 0 8012A4D2 0000 cn Home Team Scores 150 8012A4D2 0096 cn Infinite Shot Clock 8112A4BC 4210 cn Infinite Time Outs Away 8012A4EC 0006 cn Infinite Time Outs Home 8012A4D4 0006 cn No Time Outs Away 8012A4EC 0000 cn No Time Outs Home 8012A4D4 0000 cn Big Head Mode 81098E88 0100 cn Partially Invisible Players 81098E84 0100 cn Shot Clock Disabled 8109707C 0000 cn GS Button For 1-Second Shot Clock 8912A4BC 3FC0 crc E8E5B179-44AA30E8-C:45 gn Frogger2 (Unreleased Alpha) cn Freeze Timer 80163ABF 000A cn Infinite 99 Lives 80163AC7 0063 cn Infinite Lives (Retro Frogger) 8025AC2F 0005 crc B30ED978-3003C9F9-C:45 gn F-Zero X (U) cn Time Always 00.00.00/1st Place 802C4BC0 0000 802C4BC2 0001 cn Infinite Lives 800E5ED9 0005 cn Unlock Everything 800CD3C8 0001 cn Player 1\Infinite Shield 812C4B48 4326 cn Player 2\Infinite Shield 812C4EF0 4326 cn Player 3\Infinite Shield 812C5298 4326 cn Player 4\Infinite Shield 812C5640 4326 cn Max Shield 812C4B4C 4326 cn Have Boost From Start D02C4DAC 003F 802C4925 0050 cn One Lap To Race D02C4BC9 0000 812C4BC8 0002 D02C4BCB 0001 812C4BCA 0002 cn Expert Mode 800E5ED9 0000 812C4B48 0000 812C4B4C 0000 cn Super Ultimate Mega Fast Mode 812C4984 2222 cn Cool Camera 800E523E 0000 cn Hunk O' Junk 802C4B3F 0040 cn Show 30 Cars Out Of 1 Position 800E5FC7 001D cn Player 1\Invisible Car cd Vs. Mode Only 802C4CCB 0000 cn Player 1\Character Modifier 800E5EE1 ???? 0000:"Captain Falcon",0001:"Dr. Stewart",0002:"Pico",0003:"Samurai Goroh",0004:"Jody Summer",0005:"Mighty Gazelle",0006:"Mr. EAD",0007:"Baba",0008:"Octoman",0009:"Gomar + Shioh",000A:"Kate Alen",000B:"Roger Buster",000C:"James McCloud",000D:"Leon",000E:"Antonio Guster",000F:"Black Shadow",0010:"Michael Chain",0011:"Jack Levin",0012:"Super Arrow",0013:"Mrs. Arrow",0014:"John Tanaka",0015:"Beastman",0016:"Zoda",0017:"Dr. Clash",0018:"Silver Neelsen",0019:"Bio Rex",001A:"Draq",001B:"Billy",001C:"The Skull",001D:"Blood Falcon",001E:"Perfect Captain Falcon" cn Player 2\Character Modifier 802C4F90 ???? 0000:"Captain Falcon",0001:"Dr. Stewart",0002:"Pico",0003:"Samurai Goroh",0004:"Jody Summer",0005:"Mighty Gazelle",0006:"Mr. EAD",0007:"Baba",0008:"Octoman",0009:"Gomar + Shioh",000A:"Kate Alen",000B:"Roger Buster",000C:"James McCloud",000D:"Leon",000E:"Antonio Guster",000F:"Black Shadow",0010:"Michael Chain",0011:"Jack Levin",0012:"Super Arrow",0013:"Mrs. Arrow",0014:"John Tanaka",0015:"Beastman",0016:"Zoda",0017:"Dr. Clash",0018:"Silver Neelsen",0019:"Bio Rex",001A:"Draq",001B:"Billy",001C:"The Skull",001D:"Blood Falcon",001E:"Perfect Captain Falcon" cn Player 3\Character Modifier 802C5338 ???? 0000:"Captain Falcon",0001:"Dr. Stewart",0002:"Pico",0003:"Samurai Goroh",0004:"Jody Summer",0005:"Mighty Gazelle",0006:"Mr. EAD",0007:"Baba",0008:"Octoman",0009:"Gomar + Shioh",000A:"Kate Alen",000B:"Roger Buster",000C:"James McCloud",000D:"Leon",000E:"Antonio Guster",000F:"Black Shadow",0010:"Michael Chain",0011:"Jack Levin",0012:"Super Arrow",0013:"Mrs. Arrow",0014:"John Tanaka",0015:"Beastman",0016:"Zoda",0017:"Dr. Clash",0018:"Silver Neelsen",0019:"Bio Rex",001A:"Draq",001B:"Billy",001C:"The Skull",001D:"Blood Falcon",001E:"Perfect Captain Falcon" cn Player 4\Character Modifier 802C56E0 ???? 0000:"Captain Falcon",0001:"Dr. Stewart",0002:"Pico",0003:"Samurai Goroh",0004:"Jody Summer",0005:"Mighty Gazelle",0006:"Mr. EAD",0007:"Baba",0008:"Octoman",0009:"Gomar + Shioh",000A:"Kate Alen",000B:"Roger Buster",000C:"James McCloud",000D:"Leon",000E:"Antonio Guster",000F:"Black Shadow",0010:"Michael Chain",0011:"Jack Levin",0012:"Super Arrow",0013:"Mrs. Arrow",0014:"John Tanaka",0015:"Beastman",0016:"Zoda",0017:"Dr. Clash",0018:"Silver Neelsen",0019:"Bio Rex",001A:"Draq",001B:"Billy",001C:"The Skull",001D:"Blood Falcon",001E:"Perfect Captain Falcon" cn Player 1\Car Color Modifier 802C4BED ???? 0000:"1st Color",0001:"2nd Color",0002:"3rd Color",0003:"4th Color",0005:"Hidden Color" cn Player 2\Car Color Modifier 802C4F95 ???? 0000:"1st Color",0001:"2nd Color",0002:"3rd Color",0003:"4th Color",0005:"Hidden Color" cn Player 3\Car Color Modifier 802C533D ???? 0000:"1st Color",0001:"2nd Color",0002:"3rd Color",0003:"4th Color",0005:"Hidden Color" cn Player 4\Car Color Modifier 802C56E5 ???? 0000:"1st Color",0001:"2nd Color",0002:"3rd Color",0003:"4th Color",0005:"Hidden Color" cn Track Modifier 800F8517 ???? 0000:"Mute City",0001:"Silence",0002:"Sand Ocean",0003:"Devils Forest",0004:"Big Blue",0005:"Port Town",0006:"Sector Alpha",0007:"Red Canyon",0008:"Devils Forest 2",0009:"Mute City 2",000A:"Big Blue 2",000B:"White Land",000C:"Fire Field",000D:"Silence 2",000E:"Sector Beta",000F:"Red Canyon",0010:"White Land 2",0011:"Mute City 2",0012:"Rainbow Road",0013:"Devils Forest 3",0014:"Space Plant",0015:"Sand Ocean 2",0016:"Port Town 2",0017:"Big Hand" cn Max Grand Prix Points 812C492A FFFF crc 729B5E32-B728D980-C:45 gn GAUNTLET LEGENDS cn Infinite\Max Health 810C5C54 0000 810C5C56 270F 810C5C64 0000 810C5C66 270F cn Infinite\Money 810C5CF6 FFFF cn Max Strength 810C5C04 0000 810C5C06 FFFF cn Max Speed 810C5C14 0000 810C5C16 FFFF cn Max Magic 810C5C24 0000 810C5C26 FFFF cn Max Armour 810C5C34 0000 810C5C36 FFFF cn Infinite\Turbo 800FD30F 0064 cn Level 99 810C5C44 0000 810C5C46 0063 cn Infinite\Special Weapons 800C5FF7 0009 800C5D37 0009 800C5D67 0009 800C5DE7 0009 800C5EB7 0009 cn Always Shoot 5-Way 800FD198 0200 cn Always Shoot 3-Way 800FD19A 0002 cn Always Shoot Rapid Fire 800FD19A 1000 cn Have Window Schards 8104EFCA 000F cn Have Rune Stones 8104EFC6 1FFF cn Infinite\Item On Pickup 50010100 0000 810C5BF6 FFFF cn Infinite\Keys On Pickup 800C5C97 0006 crc 3EDC7E12-E26C1CC9-C:45 gn Gex 3: Deep Cover Gecko (U) cn Start With 50 Remotes D00A54EB 0000 800A54EB 0032 cn Infinite Health 800A54D9 0004 cn Extra Flies D00A54DF 0000 800A54DF 0032 crc 89FED774-CAAFE21B-C:45 gn Gex 64: Enter The Gecko (U) cn Infinite Health 800C56BB 0005 cn Infinite Lives 800C56B7 0005 cn Have All Artifacts 800C56BF 0063 800C56C3 0063 800C56C7 0063 crc 8E6E01FF-CCB4F948-C:45 gn Glover (U) cn Infinite\Double Jumps 8028FC07 0000 cn Press L To Levitate D02AE905 0020 81290334 43E0 cn Infinite\Health 8029018F 0028 cn Infinite\Lives 80290193 000A cn GS Button For 40 Gems 8829018F 0028 cn Infinite\Activate Cheat\Modifier 1 81297BEC ???? 0080:"Level Select",0100:"Open Portals",0200:"Open Levels",0380:"All Of The Above" cn Infinite\Activate Cheat\Modifier 2 81297BEE ???? 0002:"Call Ball (Press L)",0008:"Infinite Lives",0040:"Infinite Energy",0200:"Big Ball",024A:"All Of The Above" cn Infinite\Action Modifier 802901E3 ???? 0000:"Freeze Enemy Spell",0001:"Death Spell",0002:"Frog Spell",0003:"Walk On Walls Spell",0004:"Big Glover Spell",0005:"Tree Spell",0006:"Helicopter Spell",0007:"Enemy Ball Spell",0008:"Purple Bouncy Ball Spell",0009:"Tiny Black/Grey Ball Spell",000A:"Beach Ball Spell",000B:"Hovering Ball Spell",000C:"Green Ball Spell",000D:"Super Call Ball Spell",000E:"Call Ball Spell" crc 4252A5AD-AE6FBF4E-C:45 gn Goemon's Great Adventure (U) cn Infinite Gold P1 81088286 03E7 cn Infinite Health P1 80088284 0003 cn Infinite Lives P1 80088283 0003 cn Infinite Gold P2 8119ADEE 03E7 cn Infinite Health P2 81088290 03E7 cn Infinite Lives P2 8008828D 0003 cn Infinite Coins P1 8119ADEE 03E7 cn Open All Levels 50002D02 0000 810882AA 0303 crc DCBC50D1-09FD1AA3-C:45 gn Goldeneye 007 (U) cn Enable All Levels & In-Built Cheat Menu 8006992E FFFF 80069930 FFFF 80069967 FFFF 8006996C FFFF 80069971 FFFF 80069976 FFFF 8006997B FFFF 8006992F FFFF 80069965 FFFF 8006996A FFFF 8006996F FFFF 80069974 FFFF 80069979 FFFF cn Always Have 00:00 Time (All Levels) 8004837E 0000 8004838E 0000 80048396 0000 80079A22 0000 80079F26 0000 cn Infinite Ammo (All Levels) 80079E3B 0001 cn Bulletproof Bond 8002CE44 0030 cn Weak Enemies 8002CE48 0048 cn Walk through doors, objects 800364CB 0000 cn Enable All Levels 80036FB7 0001 cn All Objectives Complete 80036FD3 0001 cn Gain Access\To Aztec Level Without Beating Secret Agent Or 00 Agent 8002A8FB 001A cn Gain Access\To Egyptian Level Without Beating Secret Agent Or 00 Agent 8002A8FB 001C cn Infinite Health Player 1 (all levels) 8100C0F4 0801 8100C0F6 8090 8100C0F8 AFA4 8100C0FA 0000 81060240 0004 81060242 7600 81060244 3C02 81060246 8008 81060248 8C42 8106024A 9EE0 8106024C 3401 8106024E 3F80 81060250 A441 81060252 00DC 81060254 0800 81060256 303F cn Cradle in multiplayer cd Puts the cradle graphic in the levels screen where the facility normally is in the multiplayer levels screen.Warning it doesn't allow you to enter the multiplayer levels screen,it should automatically have selected cradle, which cannot be changed from the multiplayer menus 8002B11D 0092 8002B11F 0093 8002B127 0029 8002B123 0008 802ADC8D 0052 802ADC8E 0041 802ADC8F 0044 802ADC90 004C 802ADC91 0045 cn Custom Weapon Grouping cd golden gun fun should replace slappers only! appears in the multi weapons. 80048673 0013 81048678 3FC0 80048677 00D0 8004867F 000D 80048683 000A 8004868B 0013 81048690 3FC0 8004868F 00D0 80048697 000D 8004869B 000A 800486A3 0019 810486A8 3FC0 800486A7 00D3 800486AF 0006 800486B3 0003 800486BB 0019 810486C0 3FC0 800486BF 00D3 800486C7 0006 800486CB 0003 800486D3 0013 810486D8 3FC0 800486D7 00D0 800486DF 000D 800486E3 000A 800486EB 0013 810486F0 3FC0 800486EF 00D0 800486F7 000D 800486FB 000A 80048703 0019 81048708 3FC0 80048707 00D3 8004870F 0006 80048713 0003 8004871B 0019 81048720 3FC0 8004871F 00D3 80048727 0006 8004872B 0003 812AEA50 476F 812AEA52 6C64 812AEA54 656E 812AEA56 2047 812AEA58 756E 812AEA5A 2046 812AEA5C 756E 802AEA5E 0000 cn Facility Back Zone In Multiplayer\Part 1\2 players cd All parts must be on for this code to work.this cheat allows you to play the Facility Back Zone In Multiplayer 811E6554 45E4 811E6558 43D5 811E655C C5A7 811E657C 801C 811E657E 6774 811E5164 45E4 811E5168 C383 811E516C 4492 811E518C 801C 811E518E D574 811E78C0 45AD 811E78C4 C383 811E78C8 4440 811E78E8 801C 811E78EA E464 811E4D18 45D0 811E4D1C 4307 811E4D20 C4FB 811E4D40 801C 811E4D42 75EC 811E6738 45CD 811E673C C383 811E6740 43F4 811E6760 801C 811E6762 A0DC 811E5450 45C2 811E5454 4356 811E5458 C598 811E5478 801C 811E547A 6A74 811E5240 4608 811E5244 4307 811E5248 43DC 811E5268 801C 811E526A 962C 811E691C 4606 811E6920 4321 811E6924 449D 811E6944 801C 811E6946 CBEC 801ED447 008A 801ED4DB 008B 801ED56F 008C 801ED603 008D 801ED697 008E 801ED72B 008F 801ED7BF 007D 801ED853 007E 801ED443 002A 801ED4D7 002A 801ED56B 002A 801ED5FF 002A 801ED693 002A 801ED727 002A 801ED7BB 002A 801ED84F 002A 801ED449 0000 801ED4DD 0000 801ED571 0000 801ED605 0000 801ED699 0000 801ED72D 0000 801ED7C1 0000 801ED855 0000 801ED44D 0000 801ED4E1 0000 801ED575 0000 801ED609 0000 801ED69D 0000 801ED731 0000 801ED7C5 0000 801ED859 0000 801EB743 002A 801EB745 0068 811EB746 277F 811EB748 1000 811EB74A 0262 811EB7C2 0190 801EB7C5 0000 811EB7C6 0258 cn Facility Back Zone In Multiplayer\Part 2\2 players cd All parts must be on for this code to work.this cheat allows you to play the Facility Back Zone In Multiplayer 811EB7C8 0000 811EB7CC FFFF 811EB7CE FFFF 811EB7D2 0000 801EB7D5 0000 801EB7DB 0000 811EB7E2 0000 801EB7E7 0000 801EB843 002A 801EB845 0068 811EB846 2780 811EB848 1000 811EB84A 0262 811EB8C2 0190 801EB8C5 0000 811EB8C6 0258 811EB8C8 0000 811EB8CC FFFF 811EB8CE FFFF 811EB8D2 0000 801EB8D5 0000 801EB8DB 0000 811EB8E2 0000 801EB8E7 0000 801EB943 002A 801EB945 0068 811EB946 2791 811EB948 1000 811EB94A 0262 811EB9C2 0190 801EB9C5 0000 811EB9C6 0258 811EB9C8 0000 811EB9CC FFFF 811EB9CE FFFF 811EB9D2 0000 801EB9D5 0000 801EB9DB 0000 811EB9E2 0000 801EB9E7 0000 801EBA43 002A 801EBA45 0068 811EBA46 2792 811EBA48 1000 811EBA4A 0262 811EBAC2 0190 801EBAC5 0000 811EBAC6 0258 811EBAC8 0000 811EBACC FFFF 811EBACE FFFF 811EBAD2 0000 801EBAD5 0000 801EBADB 0000 811EBAE2 0000 801EBAE7 0000 801EBB45 00A0 801EBC45 00A0 801EBD45 00A0 801EBE45 00A0 801EBB47 0075 801EBC47 0076 801EBD47 0077 801EBE47 0078 801EBBE7 0001 801EBCE7 0001 801EBDE7 0001 801EBEE7 0001 801EC247 0071 801ECD47 0072 801ECE47 0074 801ECF47 006C 801ED047 0079 801ED147 0083 D01EBFC5 005A 801EBFC5 0000 D11EBFC6 0000 811EBFC6 F333 D11EBFC8 03E8 811EBFC8 0000 cn Facility Back Zone In Multiplayer\Part 3\2 players cd All parts must be on for this code to work.this cheat allows you to play the Facility Back Zone In Multiplayer D11EBFCA 0000 811EBFCA F0C4 D11EBFCE 4CCC 811EBFCE 000A D11EBFD2 4CCC 811EBFD2 000A D11EBFD4 0003 811EBFD4 0000 D11EBFD6 0000 811EBFD6 02C4 801EBFD9 0004 801EBFDB 0000 811EBFE2 0384 801EBFE7 0004 801EBF45 009E 801EBF47 0084 801EBF48 0010 801EC2D9 0000 801EC447 0085 801EC547 0086 811EA6B6 2743 811EA73E 0114 811EA7F2 0115 811EA8A6 00A3 811EA92E 009D 811EA9E2 00A4 811EAA96 00DA 811EAB1E 00DB 811EABD2 00DF 811EAC86 0130 811EAD0E 008D 811EADC2 012E 811EAE76 0111 811EAEFE 2740 811EAFB2 2741 811EB066 00A0 811EB0EE 009E 811EB1A2 009F 811EB256 274F 811EB2DE 2750 811EB392 0117 811EB446 0131 811EB4CE 008E 811EB582 0132 811EB636 00A1 811EB6BE 0119 811EA62E 00FA 801ED3DF 0000 801ED2DF 0001 D0024337 0007 80024337 001F cn All 64 Characters In Multi Player 8002B197 0040 cn Secret Island on Dam Level cd For the above code to work,Get to the 2nd guard tower & go down the ladder on the left hand side & to the end of the Dock, Press L & GS and you will be transfered in the water. Just keep walking straight & you will get to it. Obviously you can't actually climb ladders or anything, you will simply walkthrough anything on that Part, if you want to walk back to the Dock, when you come near it click the cheat back on & keep pressing L & GS untill you are back on it. D0064F31 0020 800D33ED 0050 880D33ED 0000 cn Replace Cradle with Citadell hidden level 8002A8F7 0029 8104468A 8970 81044690 3F44 81044692 BDEA 81044694 3F80 81044696 0000 81044698 4219 8104469A D89D 80069F80 00C4 crc 98DF9DFC-6606C189-C:45 gn Harvest Moon (U) cn Infinite\Money 811FD60E FFFF cn Belongings\Slot 01 80189084 ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Belongings\Slot 02 80189085 ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Belongings\Slot 03 80189086 ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Belongings\Slot 04 80189087 ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Belongings\Slot 05 80189088 ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Belongings\Slot 06 80189089 ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Belongings\Slot 07 8018908A ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Belongings\Slot 08 8018908B ???? 0000:"Nothing",0001:"Weeds",0002:"Boulder",0003:"Lumber",0004:"Moondrop Plant",0005:"Pink-Cat-Mint Plant",0006:"Blue Plant",0007:"Cake",0008:"Pie",0009:"Cookie",000A:"Blue Feather",000B:"Pink Liquid In A Bottle",000C:"Red Box",000D:"Turnips",000E:"Potatoes",000F:"Cabbages",0010:"Tomatoes",0011:"Corn",0012:"Eggplant",0013:"Strawberries",0014:"Eggs",0015:"Milk",0016:"M Size Milk",0017:"L Size Milk",0018:"Gold Milk",0019:"Sheared Wool",001A:"High Quality Wool",001B:"Wild Grapes",001C:"Very Berry Fruit",001D:"Tropical Fruit",001E:"Walnuts",001F:"Mushrooms",0020:"Poisonous Mushroom",0021:"Green Box",0022:"Berry Of Full Moon Plant",0023:"Medicinal Herbs",0024:"Edible Herbs",0025:"Small Fish",0026:"Fish",0027:"Big Fish",0028:"Dumpling",0029:"Cotton Candy",002A:"Fried Octopus",002B:"Roasted Corn",002C:"Candy",002D:"Chocolate",002E:"Iron-Ore",002F:"Blue Rock",0030:"Rare Metal",0031:"Moonlight Stone",0032:"Pontata Root",0033:"Chicken",0034:"Chocolate Bar Picture",0035:"???",0036:"Blue Egg Shaped Device",0037:"??",0038:"Chocolate Bar Picture",0039:"Fodder",003A:"White Bag",003B:"Tan Bag",003C:"Green Bag",003D:"Red Bag",003E:"Yellow Bag",003F:"Purple Bag" cn Tool\Slot 01 80189075 ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Tool\Slot 02 80189076 ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Tool\Slot 03 80189077 ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Tool\Slot 04 80189078 ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Tool\Slot 05 80189079 ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Tool\Slot 06 8018907A ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Tool\Slot 07 8018907B ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Tool\Slot 08 8018907C ???? 0000:"Nothing",0001:"Sickle",0002:"Hoe",0003:"Axe",0004:"Hammer",0005:"Watering Can",0006:"Milker",0007:"Bell",0008:"Brush",0009:"Clippers",000A:"Turnip Seeds",000B:"Potato Seeds",000C:"Cabbage Seeds",000D:"Tomato Seeds",000E:"Corn Seeds",000F:"Eggplant Seeds",0010:"Strawberry Seeds",0011:"Moon Drop Grass Seeds",0012:"Pink-Cat-Mint Seeds",0013:"Blue Mist Seeds",0014:"Bird Feed",0015:"Ball No Picture",0016:"Feeding Bottle",0017:"??",0018:"Fishing Pole",0019:"Miracle Potion",001A:"Medicine For Cows",001B:"Grass Seeds",001C:"Blue Feather",001D:"Empty Bottle",001E:"??",001F:"Weeds No Picture",0020:"Boulder No Picture" cn Item\Slot 01 8018908E ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 02 8018908F ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 03 80189090 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 04 80189091 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 05 80189092 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 06 80189093 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 07 80189094 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 08 80189095 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 09 80189096 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 10 80189097 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 11 80189098 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 12 80189099 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 13 8018909A ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 14 8018909B ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 15 8018909C ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 16 8018909D ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 17 8018909E ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 18 8018909F ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 19 801890A0 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 20 801890A1 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 21 801890A2 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 22 801890A3 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 23 801890A4 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Item\Slot 24 801890A5 ???? 0000:"Nothing",0001:"Ocarina",0002:"Flower Card",0003:"Cake Card",0004:"Broken Music Box",0005:"??",0006:"Old Wine",0007:"??",0008:"??",0009:"Book From Library",000A:"Scroll To Bury",000B:"Marble",000C:"GoodLuck Charm",000D:"Empty Metal Bag",000E:"Horse Race Ticket",000F:"Dog Race Ticket",0010:"Potpourri",0011:"Embroidered Hankerchief",0012:"Hand - Knit Socks",0013:"Lucky Bracelet",0014:"Flower Bath Crystals",0015:"Stamina Carrot" cn Infinite\Watering Can Uses 8016FBCD 0004 cn Infinite\Fodder Spout (Sheep And Cows) 81180714 0063 cn Infinite\Chicken Feed 80237411 005C cn Infinite\Lumber 81189E50 03E7 cn Infinite\Stamina 80189060 00FF cn Infinite\Flower Card Points 802373F0 0063 cn Infinite\Medals For Horse & Dog Races 81189B06 270F 81205206 270F cn Infinite\Cake Card Points 80181B10 0063 cn Infinite\Horse Stamina 802F5015 0002 cn Make\Ann Love You 801C3F93 00FF cn Make\Elli Love You 801C3F92 00FF cn Make\Maria Love You 801C3F90 00FF cn Make\Popuri Love You 801C3F91 00FF cn Make\Karen Love You 801C3F94 00FF cn Have\All Pics 8118905A FFFF cn Have\Win Dog Races 801886B0 00FF cn Have\Max Shipped In Bin! 8023738A FFFF crc 7F3CEB77-8981030A-C:45 gn Hercules: The Legendary Journeys (U) cn Infinite Health 810CF93E 03E7 810CF942 03E7 cn Infinite Dinars 800B6043 00E8 800B6042 00E8 cn Infinite Magic 810B65CA 0063 810B65B2 0063 810B65E2 0063 810B65FA 0063 cn Press L to Levitate cd Press L Button to Levitate & Let go to come back down D017D2D5 0020 810CF994 44CB cn Press L for 1 Hit Kill Punch cd Press The L Button & Hold B & Then Let Go to Kill Enimies,Rocks,Tents etc with One Punch. D0103383 0020 800D9BCE 0000 crc 9CAB6AEA-87C61C00-C:45 gn Hexen (U) cn Invincibility\Player 1 8113DB4C FFFF cn Infinite\Blue Mana\Player 1 8013DB7D 00CF cn Infinite\Green Mana\Player 1 8013DB7F 00CF cn Infinite\Ammo & Items\Player 1 50002004 0000 8013DAC3 0064 cn Always Have\Fist,Mace,Staff\Player 1 8013DB75 00FF cn Always Have\Axe,Staff,Frost,Shards\Player 1 8013DB77 00FF cn Always Have\Hammer,Firestorm & Arc of Death\Player 1 8013DB79 00FF cn Always Have\Quietus,Wraithverge,Bloodscourge\Player 1 8013DB7B 00FF cn Open\Main Cheat Menu 80136773 0005 cn Open\All Options in Cheat Menu 81136696 FFFF cn Have All\Keys\Player 1 8113DB5C 07FF cn Boots Of Speed Always On\Player 1 8113DB58 03FF cn Icon Of The Defender Always On\Player 1 8113DB4C 03FF cn Wings Of Wraith Always On\Player 1 8013DB53 03FF cn Play As\Player 1 8014A749 ???? 0000:"Fighter",0000:"1 Cleric",0000:"2 Mage" cn Invincibility\Player 2 8113DCE8 FFFF cn Icon Of The Defender Always On\Player 2 8113DCE8 03FF cn Boots Of Speed Always On\Player 2 8113DCF4 03FF cn Wings Of Wraith Always On\Player 2 8113DCEE 03FF cn Have All\Keys\Player 2 8113DCF8 07FF cn Infinite\Blue Mana\Player 2 8013DD19 00CF cn Infinite\Green Mana\Player 2 8013DD1B 00CF cn Always Have\Fist,Mace,Staff\Player 2 8013DD11 00FF cn Always Have\Axe,Staff,Frost,Shards\Player 2 8013DD13 00FF cn Always Have\Hammer,Firestorm & Arc of Death\Player 2 8013DD15 00FF cn Always Have\Quietus,Wraithverge,Bloodscourge\Player 2 8013DD17 00FF cn Invincibility\Player 3 8113DE84 FFFF cn Icon Of The Defender Always On\Player 3 8113DE84 03FF cn Boots Of Speed Always On\Player 3 8113DE90 03FF cn Wings Of Wraith Always On\Player 3 8113DE8A 03FF cn Have All\Keys\Player 3 8113DE94 07FF cn Infinite\Blue Mana\Player 3 8013DEB5 00CF cn Infinite\Green Mana\Player 3 8013DEB7 00CF cn Always Have\Fist,Mace,Staff\Player 3 8013DEAD 00FF cn Always Have\Axe,Staff,Frost,Shards\Player 3 8013DEAF 00FF cn Always Have\Hammer,Firestorm & Arc of Death\Player 3 8013DEB1 00FF cn Always Have\Quietus,Wraithverge,Bloodscourge\Player 3 8013DEB3 00FF cn Invincibility\Player 4 8113E020 FFFF cn Icon Of The Defender Always On\Player 4 8113E020 03FF cn Boots Of Speed Always On\Player 4 8113E02C 03FF cn Wings Of Wraith Always On\Player 4 8113E026 03FF cn Have All\Keys\Player 4 8113E030 07FF cn Infinite\Blue Mana\Player 4 8013E051 00CF cn Infinite\Green Mana\Player 4 8013E053 00CF cn Always Have\Fist,Mace,Staff\Player 4 8013E049 00FF cn Always Have\Axe,Staff,Frost,Shards\Player 4 8013E04B 00FF cn Always Have\Hammer,Firestorm & Arc of Death\Player 4 8013E04D 00FF cn Always Have\Quietus,Wraithverge,Bloodscourge\Player 4 8013E04F 00FF crc C7C98F8E-42145DDE-C:45 gn Hot Wheels Turbo Racing (U) cn Infinite Turbos\Player 1 80118CFC 000A cn Infinite Turbos\Player 2 80119478 000A cn Start On Lap Modifier\Player 1 D0118AA8 0000 80118AA8 ???? 0000:"1st",0001:"2nd",0002:"3rd",0003:"4th" cn Start On Lap Modifier\Player 2 D0119224 0000 80119224 ???? 0000:"1st",0001:"2nd",0002:"3rd",0003:"4th" cn Max Tournament Points 81124A16 00FF cn Have\All Tracks 81124A0E FFFF cn Have\All Cars & Cups\Player 1 81124A0A FFFF cn Have\All Cars & Cups\Player 2 81124B4A FFFF cn Press L For Time Is Always 0:00:00\Player 1 D0137FE5 0020 810F3900 0000 D0137FE5 0020 810F3902 0000 cn Press L For Time Is Always 0:00:00\Player 2 D0137FED 0020 810F3900 0000 D0137FED 0020 810F3902 0000 cn Have\All Special Cars\Player 1 81124A04 FFFF 81124A06 FFFF 81124A0A FFFF cn Have\All Special Cars\Player 2 81124B44 FFFF 81124B46 FFFF 81124B4A FFFF cn Allways 1st 8111D7EA 0000 crc 102888BF-434888CA-C:45 gn Hybrid Heaven (U) cn Have All\Keys 50000410 0000 8017E130 0063 50000410 0000 8017E138 0063 cn Infinite\Weapons & Items 50000610 0000 8017E0D0 0063 50000610 0000 8017E0D8 0063 cn Infinite\Refresh Items 50000D10 0000 8017E008 0063 50000C10 0000 8017E010 0063 cn Infinite\Max Body Stats 8117DC48 270F 8117DC88 0063 50000C02 0000 8117DC50 270F 50000502 0000 8117DC80 270F 50000602 0000 8117DCA8 270F 50000602 0000 8117DCB6 270F cn Infinite\Max Health 8117DC40 270F 8117DC42 270F cn Level 999 8117DC88 270F cn Press L To Levitate D005CE51 0020 8124A0B0 3FCB cn Have All\Moves 50005306 0000 81183CE0 0100 50005306 0000 81183CE2 00FF cn Editor's Cheat Level and Battle Select 801CC8C4 0005 crc C8DC65EB-3D8C8904-C:45 gn Hydro Thunder (U) cn Always 1st 812C4C96 0001 cn Infinite\Time 812B4890 42C8 cn Infinite\Boosts\Player 1 812C4C9C 4190 cn Have All\Races 812B5C94 0101 812B5C96 0101 812B5C98 0101 812B5C9A 0101 812B5C9C 0101 812B5C9E 0101 812B5CA0 0101 cn Have All\Boats 812B5CA2 0101 812B5CA4 0101 812B5CA6 0101 812B5CA8 0101 812B5CAA 0101 812B5CAC 0101 812B5CAE 0101 cn Infinite\Boosts\Player 2 812C4FCC 4190 cn Hydro Speedway 802B5C94 ???? 0001:"Unlocked & Not Completed",0003:"Unlocked & Completed" crc E436467A-82DE8F9B-C:45 gn Indy Racing 2000 (U) cn Max Exp (Gold Cup - All Classes Unlocked) cd With the 'Max Exp' codes for the Gold Cup, start a new file and leave it and go back to it again. 81033918 7FFF 8103391A FFFF cn Driver Modifier (Champsionship Mode) 812CBEC6 ???? 0000:"Scott Goodyear #4",0001:"Greg Ray #2",0002:"Billy Boat #11",0003:"Eddie Cheever Jr.#51",0004:"Buddy Lazier #91",0005:"Davey Hamilton #9",0006:"Sam Schmidt #99",0007:"Scott Sharp #8",0008:"Buzz Calkins #12",0009:"Kenny Brack #14",000A:"Robbie Buyl #22",000B:"Tyce Carison #20",000C:"Mark Dismore #28",000D:"Roberto Guerrero #50",000E:"Johnny Unser #92",000F:"Robby Unser #81",0010:"Jeff Ward #21",0011:"Stephan Gregoire #7",0012:"Robby McGehee #55",0013:"John Hollansworth Jr. #42" cn Always Place 1st 8012955F 0001 cn Unlock\Gold Cup 1st Upgrade 81023100 0000 81023102 0000 cn Unlock\Gold Cup 2nd Upgrade 81023104 0000 81023106 0000 cn Unlock\Sprint Car Class 810230EE 0000 810230EC 0000 cn Unlock\Formula Cars Part 1 810230F0 0000 810230F2 0000 810230F4 0000 810230F6 0000 crc E616B5BC-C9658B88-C:45 gn Iggy's Reckin' Balls (U) cn Extra Characters 810C632E FFFF cn Always Have 99 Points 810D8EE0 0063 cn Infinite Credits 800BDEA5 0005 cn Enable All Courses 810CCDF2 0B00 810CCDF4 0B00 810CCDF6 0B00 crc 69256460-B9A3F586-C:45 gn Jeopardy (U) cn Max Money\Player 1 81058122 FFFF cn Max Money\Player 2 81058124 FFFF cn Max Money\Player 3 81058126 FFFF crc BB30B1A5-FCF712CE-C:45 gn Jeremy McGrath Supercross 2000 (U) cn Extra Points 800711E7 00FF cn Enable Tabletop Freestyle 81071832 0001 cn Enable Chasm Freestyle 81071834 0001 cn Enable Jim Jam Freestyle 81071838 0001 cn Enable Moon Freestyle 8107183C 0001 crc 8A6009B6-94ACE150-C:45 gn Jet Force Gemini (U) cn Access\All Characters 801E6040 FFFF cn Juno\Infinite Continues 800A3281 0002 cn Juno\Full & Max Health 801BF976 0040 801E61E5 000C 801E61E2 0040 cn Juno\Access\All Keys 811E6248 FFF7 cn Juno\Access\All Objects 811E624A FFFF cn Juno\Infinite\Mizar Tokens 811E61F4 02F4 cn Juno\Max Blue & White Heads 811E61EA 03E7 811E61E8 03E7 cn Juno\Infinite\Max Ammo All Weapons 50000302 0000 811E61F6 02F4 50000802 0000 811E61FC 02F4 50000402 0000 811E620C 02F4 cn Vela\Full & Max Health 801E616F 000C 801E616C 0040 cn Vela\Access\All Keys 811E61D2 FF70 cn Vela\Access\All Objects 811E61D4 FFFF cn Vela\Infinite\Mizar Tokens 811E617E 02F4 cn Vela\Max\Blue & White Heads 811E6174 03E7 811E6172 03E7 cn Vela\Infinite\Max Ammo All Weapons 50000302 0000 811E6180 02F4 50000802 0000 811E6186 02F4 50000402 0000 811E6196 02F4 cn Lupus\Full & Max Health 801BF9EC 0040 801E625B 000C 801E6258 0040 cn Lupus\Access\All Keys 811E62BE FF70 cn Lupus\Access\All Objects 811E62C0 FFFF cn Lupus\Infinite\Mizar Tokens 811E626A 02F4 cn Lupus\Max\Blue & White Heads 811E6260 03E7 811E625E 03E7 cn Lupus\Infinite\Max Ammo All Weapons 50000302 0000 811E626C 02F4 50000802 0000 811E6272 02F4 50000402 0000 811E6282 02F4 cn Access\All Floyd Awards cd only enable One character at a time when using this code 50000501 0000 801E6038 0005 cn Juno\Access\All Weapons cd Do not put this code on until you collect one Extra Weapon then you will have all ready to use 801E61EC 00FF 801E61ED 00FF cn Vela\Access\All Weapons cd Do not put this code on until you collect one Extra Weapon then you will have all ready to use 801E6176 00FF 801E6177 00FF cn Lupus\Access\All Weapons cd Do not put this code on until you collect one Extra Weapon then you will have all ready to use 801E6262 00FF 801E6263 00FF cn Tribals\Have All Tribals\Gold Wood 801E6014 000F cn Tribals\No Tribals Killed\Gold Wood 801E6015 0000 cn Tribals\Have No Tribals Remaining\Gold Wood 801E6016 0000 cn Wide Screen Always Off 800FECA8 0000 crc D0151AB0-FE5CA14B-C:45 gn John Romero's Daikatana (U) cn Infinite\Health 8020A965 0064 cn Infinite\Armor 8020A987 0064 cn Infinite\Experience 8020A967 00FF cn Max\Vitality 8020A969 0007 cn Max\Attack 8020A96B 0007 cn Max\Speed 8020A96D 0007 cn Max\Acro 8020A96F 0007 cn Max\Power 8020A971 0007 cn Infinite\Ammo\Sidewinder 8020A9B0 00FF cn Infinite\Ammo\Shock Wave 8020A9B1 00FF cn Infinite\Ammo\Chvizatergo 8020A9B2 00FF cn Infinite\Ammo\Shot Cycler 8020A9B3 00FF cn Infinite\Ammo\Ion Cannon 8020A9B4 00FF cn Infinite\Ammo\Disc Of Dredalus 8020A9B5 0063 cn Infinite\Ammo\Venomous 8020A9B6 00FF cn Infinite\Ammo\Poseidon Trident 8020A9B7 00FF cn Infinite\Ammo\Hammer 8020A9B8 0000 cn Infinite\Ammo\Sunflares 8020A9B9 00FF cn Infinite\Ammo\Bolter 8020A9BA 00FF cn Infinite\Ammo\Ballista 8020A9BB 00FF cn Infinite\Ammo\Stavros Stave 8020A9BC 00FF cn Infinite\Ammo\Wyndraxs Wisp 8020A9BD 00FF cn Have All Weapons 8120A8F6 FFFF crc 36281F23-009756CF-C:45 gn Ken Griffey Jr.'s Slugfest (U) cn Max\Batting 8105D6D8 4120 cn Max\Power 8105D270 4120 cn Max\Speed 8105CE68 4120 cn Max\Defense 8105CA60 4120 cn Max\Arm Strength 8105C5F8 4120 cn Max\Durability 8105C098 4120 cn Max\Clutch 8105BB98 4120 cn Max\Control 8105B760 4120 cn Max\Stamina 8105B2F8 4120 cn Max\Pitch Speed 8105AE90 4120 cn Infinite\Creation Points 81059408 420C cn Infinite\Strikes 8021AC48 0000 cn Infinite\Balls 8021AC47 0000 cn Inning Selection 8021AC42 ???? 0002:"2nd Inning",0003:"3rd Inning",0004:"4th Inning",0005:"5th Inning",0006:"6th Inning",0007:"7th Inning",0008:"8th Inning",0009:"9th Inning" crc 9E8FE2BA-8B270770-C:45 gn Killer Instinct Gold (U) (v1.0) cn Unlock All Options 8012834C 0006 cn Player 1\Untouchable 801D34D4 000A cn Player 1\Fast\Punch Kick 801D347E 0010 cn Player 1\Fast\Jump Walk 801D347C 0001 cn Player 1\Slow Jump Walk 801D347D 0050 cn Player 1\Infinite Energy 801D3484 0069 cn Player 1\Fight Gargos Immediately 8012834B 000A cn Player 1\Spinal Always Has All Skulls 801D3523 0006 cn Player 1\Fulgore\Always Invisible cd Do not use this with Fulgore Always Visible 801D3478 0020 801D3479 0090 801D34C5 0092 801D3527 005E cn Player 1\Fulgore\Always Visible cd Do not use this with Fulgore Always Invisible 801D3478 0023 801D3479 00F0 801D34C5 0080 801D3527 00AF cn Player 1\Wins Score 8012830A 00FF cn Player 1\Undefeated Players Scroll By Quickly 802C8CE8 0007 cn Player 1\Play As 802C8CB8 ???? 0000:"Jago",0001:"Combo",0002:"Spinal",0003:"Tusk",0004:"Glacius",0005:"Fulgore",0006:"Kim Wu",0007:"Sabrewulf",0008:"Orchid",0009:"Maya",000A:"Gargos" cn Player 1\1-Hit Death D01D3484 0078 801D3484 0001 cn Player 2\Spinal Always Has All Skulls 801D3623 0006 cn Player 2\Fulgore Always Invisible cd Do not use this with Fulgore Always Visible 801D3578 0020 801D3579 0090 801D35C5 0092 801D3527 005E cn Player 2\Fulgore Always Visible cd Do not use this with Fulgore Always Invisible 801D3578 0023 801D3579 00F0 801D35C5 0080 801D3527 00AF cn Player 2\Play As 8004EA9D ???? 0000:"Jago",0001:"Combo",0002:"Spinal",0003:"Tusk",0004:"Glacius",0005:"Fulgore",0006:"Kim Wu",0007:"Sabrewulf",0008:"Orchid",0009:"Maya",000A:"Gargos" cn Player 2\Infinite Energy 801D3584 0078 cn Player 2\Fast\Punch Kick 801D357E 0010 cn Player 2\Fast\Jump Walk 801D357C 0001 cn Player 2\Slow\Punch Kick 801D357F 0050 cn Player 2\Slow\Jump Walk 801D357D 0050 cn Player 2\Untouchable 801D34D5 000A crc 46039FB4-0337822C-C:45 gn Kirby 64 - The Crystal Shards (U) cn Get All Crystals 50000701 0000 800D6BC0 0001 50001701 0000 800D6BC8 0007 cn Unlock All Difficulty Levels\100 Yard Hop 800D6BB9 0003 cn Unlock All Difficulty Levels\Bumper Crop Bump 800D6BBA 0003 cn Unlock All Difficulty Levels\Checkerboard Chase 800D6BBB 0003 cn Infinite Lives 800D714F 0064 cn Infinite Health 810D6E50 40C0 cn Can Fly Forever 8112E7DE 00F0 cn All Stages Complete 50002B01 0000 800D6BE0 0002 crc FCE0D799-65316C54-C:45 gn Knife Edge - Nose Gunner (U) cn Infinite\Armor 8011D467 0064 cn Level 11 Vulcan Cannon 801239B3 000A cn Infinite\Bombs 8011D46F 0003 cn Press\L For Rapid Fire On Nuke & Laser cd Do not use this with Press L For Rapid Fire On Flak D011BE01 0020 8011D497 0028 cn Press\L For Rapid Fire On Flak cd Do not use this with Press L For Rapid Fire On Nuke & Laser D011BE01 0020 8011D497 0014 crc 0894909C-DAD4D82D-C:45 gn Knockout Kings 2000 (U) cn Player 1\Infinite\Health 8106B974 42C8 8106B976 0000 cn Player 2\Infinite\Health 8106BA7C 42C8 8106BA7E 0000 cn Player 1\No Health 8106B974 0000 8106B976 0000 cn Player 2\No Health 8106BA7C 0000 8106BA7E 0000 cn Player 1\Max\Power 8106B980 0000 8106B982 0BB2 cn Player 1\No Power 8106B980 0000 8106B982 0000 cn Player 2\Max\Power 8106BA88 0000 8106BA8A 0BB2 cn Player 2\No Power 8106BA88 0000 8106BA8A 0000 cn Infinite\Creation Points 81063742 0064 cn Big\Head Mode 800F401C 0001 cn Big\Glove Mode 800F401D 0001 cn Player 1\Power Punch After 1st Punch 8006B983 0064 cn Player 2\Power Punch After 1st Punch 8006BA8B 0064 cn Stop Timer 81067546 001C cn Player 1\Character Modifier 800EC6F3 ???? 0000:"Ali",0001:"Frazier",0002:"Holmes",0003:"Holyfield",0004:"Lewis",0005:"Tua",0006:"Spinks",0007:"Butterbean",0008:"De La Hoya",0009:"Leonard",000A:"Hagler",000B:"Duran",000C:"Whitaker",000D:"Quartey",000E:"Carr",000F:"Vargas",0010:"Reid",0011:"Moskey",0012:"Pryor",0013:"Argnello",0014:"O'Grady",0015:"Mayweather",0016:"Manfredy",0017:"Kelley",0018:"Romero",0019:"Random",001A:"Created Boxer",001B:"Creater Boxer",001C:"Dempsey",001D:"K. Orr",001E:"IUppa",001F:"S. Sandoval",0020:"S. Broadhurst",0021:"Pole",0022:"Hasson",0023:"Alameda",0024:"Wahlberg",0025:"Scott",0026:"Hopra",0027:"Eckhardt",0028:"Parker",0029:"Ruiz",002A:"F. Sandoval",002B:"Ang",002C:"Bristov",002D:"Botti",002E:"S. Orr",002F:"Zarifes",0030:"Giolito",0031:"Garrett",0032:"Barclay",0033:"Wynne",0034:"Lupidi",0035:"W. Aguitar",0036:"Di Ricco",0037:"Philippine",0038:"M. Broadhurst",0039:"Weaver",003A:"Lajoie",003B:"Greenberg",003C:"Quinn",003D:"Perone",003E:"Tool",003F:"Bunch",0040:"St. Aubyn",0041:"Wells",0042:"Dexter",0043:"Hsu",0044:"Bazzel",0045:"Thompson",0046:"Eklund",0047:"Tallarico",0048:"de Leon",0049:"Coallier" cn Player 2\Character Modifier 800EC6F7 ???? 0000:"Ali",0001:"Frazier",0002:"Holmes",0003:"Holyfield",0004:"Lewis",0005:"Tua",0006:"Spinks",0007:"Butterbean",0008:"De La Hoya",0009:"Leonard",000A:"Hagler",000B:"Duran",000C:"Whitaker",000D:"Quartey",000E:"Carr",000F:"Vargas",0010:"Reid",0011:"Moskey",0012:"Pryor",0013:"Argnello",0014:"O'Grady",0015:"Mayweather",0016:"Manfredy",0017:"Kelley",0018:"Romero",0019:"Random",001A:"Created Boxer",001B:"Creater Boxer",001C:"Dempsey",001D:"K. Orr",001E:"IUppa",001F:"S. Sandoval",0020:"S. Broadhurst",0021:"Pole",0022:"Hasson",0023:"Alameda",0024:"Wahlberg",0025:"Scott",0026:"Hopra",0027:"Eckhardt",0028:"Parker",0029:"Ruiz",002A:"F. Sandoval",002B:"Ang",002C:"Bristov",002D:"Botti",002E:"S. Orr",002F:"Zarifes",0030:"Giolito",0031:"Garrett",0032:"Barclay",0033:"Wynne",0034:"Lupidi",0035:"W. Aguitar",0036:"Di Ricco",0037:"Philippine",0038:"M. Broadhurst",0039:"Weaver",003A:"Lajoie",003B:"Greenberg",003C:"Quinn",003D:"Perone",003E:"Tool",003F:"Bunch",0040:"St. Aubyn",0041:"Wells",0042:"Dexter",0043:"Hsu",0044:"Bazzel",0045:"Thompson",0046:"Eklund",0047:"Tallarico",0048:"de Leon",0049:"Coallier" cn Ring Modifier 800EC703 ???? 0000:"Great Western Forum",0001:"Caesars Palace",0002:"Ecko Sports Arena",0003:"International Arena",0004:"Local 440",0005:"The Colosseum",0006:"Roppongi Palace",0007:"Wembley Arena",0008:"Knockout Kings Arena" crc 5354631C-03A2DEF0-C:45 gn Legend of Zelda 2, The - Majora's Mask (U) cn Infinite\Health 811EF6A6 0140 cn Infinite\Hearts Options cd If you need to clear the Infinite Max Hearts from the screen just choose the 6 or 4 Heart Options, take off the cheat & then make a save. 811EF6A4 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Have\All Quest/Status Items 801EF72D 0005 811EF72E F7CF cn Infinite\Rupees 811EF6AA 03E7 cn Infinite\Max & Double Magic Meter 801EF6A9 0060 811EF6B0 0101 cn Infinite\Items 801EF711 0063 801EF716 0063 801EF717 0063 801EF718 0063 801EF719 0063 801EF71A 0063 801EF71C 0063 801EF71D 0063 cn Have\Ocarina of Time 801EF6E0 0000 cn Have\Hero's Bow 801EF6E1 0001 cn Have\Arrows\Fire Arrow 801EF6E2 0002 cn Have\Arrows\Ice Arrow 801EF6E3 0003 cn Have\Arrows\Light Arrow 801EF6E4 0004 cn Have\Bombs 801EF6E6 0006 cn Have\Bombchu 801EF6E7 0007 cn Have\Deku Sticks 801EF6E8 0008 cn Have\Deku Nuts 801EF6E9 0009 cn Have\Magic Beans 801EF6EA 000A cn Have\Powder Kegs 801EF6EC 000C cn Have\Pictograph 801EF6ED 000D cn Have\Lens of Truth 801EF6EE 000E cn Have\Hookshot 801EF6EF 000F cn Have\Great Fairy's Sword 801EF6F0 0010 cn Maximum Visibility 80166118 0020 cn Fog\Blue 80166108 0020 cn Fog\Pink 8016610C 0020 cn Fog\Yellow 80166110 0020 cn Press L To Levitate cd Press L To Levitate & Let go to land D03E6B3B 0020 813FFE18 40CB cn Have\All Masks 801EF6F8 003E 801EF6F9 0038 801EF6FA 0047 801EF6FB 0045 801EF6FC 0040 801EF6FD 0032 801EF6FE 003A 801EF6FF 0046 801EF700 0039 801EF701 0042 801EF702 0048 801EF703 0033 801EF704 003C 801EF705 003D 801EF706 0037 801EF707 003F 801EF708 0036 801EF709 0034 801EF70A 0043 801EF70B 0041 801EF70C 003B 801EF70D 0044 801EF70E 0049 801EF70F 0035 cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D03E6B3B 0000 801EF672 ???? 0000:"Mama's House non Beta",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0003:"Southern Swamp Mr Tingle Entry",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",002E:"Woodfall Temple non Beta",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",0038:"Path to Romani Ranch non Beta",004A:"outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",0074:"Cave Portal to Last Boss Field",007F:"Waterfall Sothern Swamp",008A:"Giant Turtle In the Temple non beta",008B:"Room of Miau & Tijo Zora Great Hall",0094:"Recieving Gorans Mask non Beta",0095:"?",0096:"Hungry Goran in the Snow",00A2:"Statue in Stone Tower",00A6:"Stone Tower non Beta",00B9:"Recieving Deku Mask non Beta",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water",00FF:"Vamps House In Ikana Canyon" cn Fight Demo Majora's Mask cd With this code,load the game & put the cheat on. then press start to apear in the Demo mode. 8016A718 0020 cn Event Item\Modifier 1 801EF6E5 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 2 801EF6EB ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 3 801EF6F1 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Have\Item Modifier 801EF6F0 ???? 0005:"Japanese Flute?",000B:"Japanese Item?",0010:"Great Fairy's Sword",0011:"Japanese Hookshot?",0031:"Japanese Scroll?",004A:"Japanese Bow?" cn Bottles\Bottle 1 Modifier 801EF6F2 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 2 Modifier 801EF6F3 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 3 Modifier 801EF6F4 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 4 Modifier 801EF6F5 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 5 Modifier 801EF6F6 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 6 Modifier 801EF6F7 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Use C-Buttons Anywhere cd This code allows you to use C-Button Items where you normally can't use them. (Created by: The Gentleman) 811F3588 0000 811F358A 0000 cn All Equipment Upgrades 801EF6DD 0023 811EF72A 201B 801EF6BC 004F cn Replace Sword With cd Only put the Deity Link's Sword on, if using The Play As Fierce Deity Link Code, if not it will turn Fierce Deity Link into a crazed slashing Machine. You have been warned. 801EF6BC ???? 004A:"Fire Arrow w/ Bow",004B:"Ice Arrow w/ Bow",004C:"Light Arrow w/ Bow",004D:"Kokiri Sword",004E:"Razor Sword",004F:"Guilded Sword",0050:"Deity Link's Sword" cn Play As 801EF690 ???? 0000:"Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Warp Modifier cd Put this code on and it will now take where you wanted to go, turn it back off or it will infinite loop entering all the time. D03E6B3A 0000 803FF395 0001 813FF39A ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" crc B443EB08-4DB31193-C:45 gn Legend of Zelda, The - Majora's Mask (U) (GC Version) cn Infinite\Health 811ED866 0140 cn Infinite\Hearts Options cd If you need to clear the Infinite Max Hearts from the screen just choose the 6 or 4 Heart Options, take off the cheat & then make a save. 811ED864 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Have\All Quest/Status Items 801ED8ED 0005 811ED8EE F7CF cn Infinite\Rupees 811ED86A 03E7 cn Infinite\Max & Double Magic Meter 801ED869 0060 811ED870 0101 cn Infinite\Items 801ED8D1 0063 50000501 0000 801ED8D6 0063 50000201 0000 801ED8DC 0063 cn Have\Ocarina of Time 801ED8A0 0000 cn Have\Hero's Bow 801ED8A1 0001 cn Have\Arrows\Fire Arrow 801ED8A2 0002 cn Have\Arrows\Ice Arrow 801ED8A3 0003 cn Have\Arrows\Light Arrow 801ED8A4 0004 cn Have\Bombs 801ED8A6 0006 cn Have\Bombchu 801ED8A7 0007 cn Have\Deku Sticks 801ED8A8 0008 cn Have\Deku Nuts 801ED8A9 0009 cn Have\Magic Beans 801ED8AA 000A cn Have\Powder Kegs 801ED8AC 000C cn Have\Pictograph 801ED8AD 000D cn Have\Lens of Truth 801ED8AE 000E cn Have\Hookshot 801ED8AF 000F cn Have\Great Fairy's Sword 801ED8B0 0010 cn Maximum Visibility 801642D8 0020 cn Fog\Blue 801642C8 0020 cn Fog\Pink 801642CC 0020 cn Fog\Yellow 801642D0 0020 cn Press L To Levitate cd Press L To Levitate & Let go to land D038127B 0020 8139A558 40CB cn Have\All Masks 801ED8B8 003E 801ED8B9 0038 801ED8BA 0047 801ED8BB 0045 801ED8BC 0040 801ED8BD 0032 801ED8BE 003A 801ED8BF 0046 801ED8C0 0039 801ED8C1 0042 801ED8C2 0048 801ED8C3 0033 801ED8C4 003C 801ED8C5 003D 801ED8C6 0037 801ED8C7 003F 801ED8C8 0036 801ED8C9 0034 801ED8CA 0043 801ED8CB 0041 801ED8CC 003B 801ED8CD 0044 801ED8CE 0049 801ED8CF 0035 cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D038127B 0000 801ED832 ???? 0000:"Mama's House non Beta",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0003:"Southern Swamp Mr Tingle Entry",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",002E:"Woodfall Temple non Beta",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",0038:"Path to Romani Ranch non Beta",004A:"outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",0074:"Cave Portal to Last Boss Field",007F:"Waterfall Sothern Swamp",008A:"Giant Turtle In the Temple non beta",008B:"Room of Miau & Tijo Zora Great Hall",0094:"Recieving Gorans Mask non Beta",0095:"?",0096:"Hungry Goran in the Snow",00A2:"Statue in Stone Tower",00A6:"Stone Tower non Beta",00B9:"Recieving Deku Mask non Beta",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water",00FF:"Vamps House In Ikana Canyon" cn Fight Demo Majora's Mask cd With this code,load the game & put the cheat on. then press start to apear in the Demo mode. 801688D8 0020 cn Event Item\Modifier 1 801ED8A5 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 2 801ED8AB ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 3 801ED8B1 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Have\Item Modifier 801ED8B0 ???? 0005:"Japanese Flute?",000B:"Japanese Item?",0010:"Great Fairy's Sword",0011:"Japanese Hookshot?",0031:"Japanese Scroll?",004A:"Japanese Bow?" cn Bottles\Bottle 1 Modifier 801ED8B2 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 2 Modifier 801ED8B3 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 3 Modifier 801ED8B4 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 4 Modifier 801ED8B5 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 5 Modifier 801ED8B6 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 6 Modifier 801ED8B7 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Use C-Buttons Anywhere cd This code allows you to use C-Button Items where you normally can't use them. (Created by: The Gentleman) 811F1748 0000 811F174A 0000 cn All Equipment Upgrades 801ED89D 0023 811ED8EA 201B 801ED87C 004F cn Replace Sword With cd Only put the Deity Link's Sword on, if using The Play As Fierce Deity Link Code, if not it will turn Fierce Deity Link into a crazed slashing Machine. You have been warned. 801ED87C ???? 004A:"Fire Arrow w/ Bow",004B:"Ice Arrow w/ Bow",004C:"Light Arrow w/ Bow",004D:"Kokiri Sword",004E:"Razor Sword",004F:"Guilded Sword",0050:"Deity Link's Sword" cn Play As 801ED850 ???? 0000:"Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Warp Modifier cd Put this code on and it will now take where you wanted to go, turn it back off or it will infinite loop entering all the time. D03E4CFA 0000 803FD555 0001 813FD55A ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" crc EC7011B7-7616D72B-C:45 gn Legend of Zelda, The - Ocarina of Time (U) (V1.0) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 8111B99C 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C84B5 0010 8011A5D7 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 8111B7F2 0000 8111B7F4 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A66C 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A674 30FF 8111A676 FFFF cn Max\Heart Containers 8111A5FE 0140 cn Max\Gold Skulltulas Killed 8011A6A1 0064 cn Time of Day Modifier 8111A5DC ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 8111A600 0140 cn Infinite\Magic D011A609 0008 8011A60A 0001 8011A60C 0001 8011A603 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 8011A640 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011A65C 0009 cn Infinite\Deku Nuts 8011A65D 0009 cn Infinite\Bombs 8011A65E 0009 cn Infinite\Arrows 8011A65F 0009 cn Infinite\Deku Seeds 8011A662 0009 cn Infinite\Bombchu's 8011A664 0009 cn Infinite\Magic Beans 8011A66A 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 8011A678 0007 8011A679 0007 8011A67A 0007 8011A67B 0007 8011A67C 0007 8011A67D 0007 8011A67E 0007 8011A67F 0007 8011A680 0007 8011A681 0007 8011A682 0007 8011A68F 0009 8011A690 0009 8011A691 0009 8011A692 0009 8011A693 0009 8011A699 0009 8011A69C 0009 8011A697 0009 cn Have\Ocarina 8011A64B ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 8011A650 000E cn Have\Lens of Truth 8011A651 000F cn Have\Megaton Hammer 8011A653 0011 cn Have\Deku Stick 8011A644 0000 cn Have\Deku Nut 8011A645 0001 cn Have\Bombs 8011A646 0002 cn Have\Fairy Bow 8011A647 0003 cn Have\Fairy Slingshot 8011A64A 0006 cn Have\Bombchu 8011A64C 0009 cn Have\Arrows\Fire Arrow 8011A648 0004 cn Have\Arrows\Ice Arrow 8011A64E 000C cn Have\Arrows\Light Arrow 8011A654 0012 cn Have\Hookshot 8011A64D ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 8011A652 0010 cn Have\Magic\Fairie's Wind 8011A64F 000D cn Have\Magic\Nayru's Love 8011A655 0013 cn Have\Magic\Din's Fire 8011A649 0005 cn Bottles\Bottle 1 Modifier 8011A656 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 8011A657 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 8011A658 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 8011A659 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011A65A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011A65B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011A60E 0001 cn Have Quiver (Holds 30) 8011A671 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 8011A672 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 8011A673 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L\To Levitate cd Press L To Levitate & Let go to land D01C84B5 0020 811DAA90 40CB cn Press L\For infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C84B5 0020 811DB2B2 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C84B5 0020 811DAA90 40CB D01C84B5 0000 811DB2B2 000D 8011A640 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Beta Mode,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C84B5 0000 8011B9E3 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011B965 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 8011A69F 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 8111B998 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 8011B9A1 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F2208 0005 801EEC88 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 8011B9A5 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest 01). 80025614 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C84B5 0010 8111B936 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 8011B4B9 00FF 8011B92F ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 8011A672 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" cn Press L+R For FMV Select cd Hold down `L+R' after the Nintendo logo is spinning to see your favourite FMV D01C84B5 0030 8111A5D2 00A0 D01C84B5 0030 8111A5DA ???? FFF0:"Triforce FMV",FFF1:"fire FMV",FFF2:"Triforce FMV",FFF3:"Ganondorf FMV",FFF4:"Planet Making FMV",FFF5:"Fire FMV",FFF6:"Ganondorf FMV",FFF7:"More Triforce FMV",FFF8:"Ending" cn Dark Link\Make Dark Link Apear In TOT 8023E80F 0020 8023E815 0033 cn Dark Link\Play As Dark Link D01C84B5 0020 811DAB60 801E D01C84B5 0020 811F2C24 801D D01C84B5 0020 811F2C26 AA30 D01C84B5 0020 811CA0E4 801E D01C84B5 0020 811CA0E6 4B60 D01C84B5 0020 811E4B60 0000 D01C84B5 0020 811E4B62 02FF D01C84B5 0020 811DAA30 0033 D01C84B5 0020 811DAA32 0901 D01C84B5 0020 811DAB62 27E0 D01C84B5 0020 811E4C90 8009 D01C84B5 0020 811E4C92 7740 D01C84B5 0020 811C8710 801E D01C84B5 0020 811C8712 4B60 crc D43DA81F-021E1E19-C:45 gn Legend of Zelda, The - Ocarina of Time (U) (V1.1) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 8111BB5C 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C8675 0010 8011A797 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 8111B9B2 0000 8111B9B4 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A82C 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111A834 30FF 8111A836 FFFF cn Max\Heart Containers 8111A7BE 0140 cn Max\Gold Skulltulas Killed 8011A861 0064 cn Time of Day Modifier 8111A79C ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 8111A7C0 0140 cn Infinite\Magic D011A7C9 0008 8011A7CA 0001 8011A7CC 0001 8011A7C3 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 8011A800 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011A81C 0009 cn Infinite\Deku Nuts 8011A81D 0009 cn Infinite\Bombs 8011A81E 0009 cn Infinite\Arrows 8011A81F 0009 cn Infinite\Deku Seeds 8011A822 0009 cn Infinite\Bombchu's 8011A824 0009 cn Infinite\Magic Beans 8011A82A 0009 cn Infinite\Big Keys,Small Keys,Compass,& Map 8011A838 0007 8011A839 0007 8011A83A 0007 8011A83B 0007 8011A83C 0007 8011A83D 0007 8011A83E 0007 8011A83F 0007 8011A840 0007 8011A841 0007 8011A842 0007 8011A84F 0009 8011A850 0009 8011A851 0009 8011A852 0009 8011A853 0009 8011A859 0009 8011A85C 0009 8011A857 0009 cn Have\Ocarina 8011A80B ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 8011A810 000E cn Have\Lens of Truth 8011A811 000F cn Have\Megaton Hammer 8011A813 0011 cn Have\Deku Stick 8011A804 0000 cn Have\Deku Nut 8011A805 0001 cn Have\Bombs 8011A806 0002 cn Have\Fairy Bow 8011A807 0003 cn Have\Fairy Slingshot 8011A80A 0006 cn Have\Bombchu 8011A80C 0009 cn Have\Arrows\Fire Arrow 8011A808 0004 cn Have\Arrows\Ice Arrow 8011A80E 000C cn Have\Arrows\Light Arrow 8011A814 0012 cn Have\Hookshot 8011A80D ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 8011A812 0010 cn Have\Magic\Fairie's Wind 8011A80F 000D cn Have\Magic\Nayru's Love 8011A815 0013 cn Have\Magic\Din's Fire 8011A809 0005 cn Bottles\Bottle 1 Modifier 8011A816 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 8011A817 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 8011A818 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 8011A819 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011A81A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011A81B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011A7CE 0001 cn Have Quiver (Holds 30) 8011A831 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 8011A832 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 8011A833 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Press L To Levitate & Let go to land D01C8675 0020 811DAC50 40CB cn Press L For infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C8675 0020 811DB472 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C8675 0020 811DAC50 40CB D01C8675 0000 811DB472 000D 8011A800 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Hyrule Field,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C8675 0000 8011BBA3 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011BB25 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 8011A85F 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 8111BB58 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 8011BB61 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F3688 0005 801F3848 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 8011BB65 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 800257D4 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C8675 0010 8111BAF6 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 8011B679 00FF 8011BAEF ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 8011A832 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" cn Press L+R For FMV Select cd Hold down `L+R' after the Nintendo logo is spinning to see your favourite FMV D01C8675 0030 8011A793 00A0 D01C8675 0030 8011A79B ???? F000:"riforce FMV",F10F:"ire FMV",F200:"riforce FMV",F300:"anondorf FMV",F400:"lanet Making FMV",F50F:"ire FMV",F600:"anondorf FMV",F700:"ore Triforce FMV",F80E:"nding" cn Dark Link\Make Dark Link Apear In TOT 8023E9AF 0020 8023E9B5 0033 crc 693BA2AE-B7F14E9F-C:45 gn Legend of Zelda, The - Ocarina of Time (U) (V1.2) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 8111C04C 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C8D75 0010 8011AC87 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 8111BEA2 0000 8111BEA4 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111AD1C 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111AD24 30FF 8111AD26 FFFF cn Max\Heart Containers 8111ACAE 0140 cn Max\Gold Skulltulas Killed 8011AD51 0064 cn Time of Day Modifier 8111AC8C ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 8111ACB0 0140 cn Infinite\Magic D011ACB9 0008 8011ACBA 0001 8011ACBC 0001 8011ACB3 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 8011ACF0 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011AD0C 0009 cn Infinite\Deku Nuts 8011AD0D 0009 cn Infinite\Bombs 8011AD0E 0009 cn Infinite\Arrows 8011AD0F 0009 cn Infinite\Deku Seeds 8011AD12 0009 cn Infinite\Bombchu's 8011AD14 0009 cn Infinite\Magic Beans 8011AD1A 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 8011AD28 0007 8011AD29 0007 8011AD2A 0007 8011AD2B 0007 8011AD2C 0007 8011AD2D 0007 8011AD2E 0007 8011AD2F 0007 8011AD30 0007 8011AD31 0007 8011AD32 0007 8011AD3F 0009 8011AD40 0009 8011AD41 0009 8011AD42 0009 8011AD43 0009 8011AD49 0009 8011AD4C 0009 8011AD47 0009 cn Have\Ocarina 8011ACFB ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 8011AD00 000E cn Have\Lens of Truth 8011AD01 000F cn Have\Megaton Hammer 8011AD03 0011 cn Have\Deku Stick 8011ACF4 0000 cn Have\Deku Nut 8011ACF5 0001 cn Have\Bombs 8011ACF6 0002 cn Have\Fairy Bow 8011ACF7 0003 cn Have\Fairy Slingshot 8011ACFA 0006 cn Have\Bombchu 8011ACFC 0009 cn Have\Arrows\Fire Arrow 8011ACF8 0004 cn Have\Arrows\Ice Arrow 8011ACFE 000C cn Have\Arrows\Light Arrow 8011AD04 0012 cn Have\Hookshot 8011ACFD ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 8011AD02 0010 cn Have\Magic\Fairie's Wind 8011ACFF 000D cn Have\Magic\Nayru's Love 8011AD05 0013 cn Have\Magic\Din's Fire 8011ACF9 0005 cn Bottles\Bottle 1 Modifier 8011AD06 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 8011AD07 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 8011AD08 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 8011AD09 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011AD0A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011AD0B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011ACBE 0001 cn Have Quiver (Holds 30) 8011AD21 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 8011AD22 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 8011AD23 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Press L To Levitate & Let go to land D01C8D75 0020 811DB350 40CB cn Press L For infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C8D75 0020 811DBB72 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C8D75 0020 811DB350 40CB D01C8D75 0000 811DBB72 000D 8011ACF0 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Hyrule Field,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C8D75 0000 8011C093 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 8011C015 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 8011AD4F 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 8111C048 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 8011C211 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F3D38 0005 801F3EF8 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 8011C215 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 80025CC4 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C8B65 0010 8111BFE6 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset, 8011BB69 00FF 8011BFDF ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 8011AD22 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" cn Press L+R For FMV Select cd Hold down `L+R' after the Nintendo logo is spinning to see your favourite FMV D01C8D75 0030 8011AC83 00A0 D01C8D75 0030 8011AC8B ???? F000:"riforce FMV",F10F:"ire FMV",F200:"riforce FMV",F300:"anondorf FMV",F400:"lanet Making FMV",F50F:"ire FMV",F600:"anondorf FMV",F700:"ore Triforce FMV",F80E:"nding" cn Dark Link\Make Dark Link Apear In TOT 8023EFBF 0020 8023EFC5 0033 crc 096A40EA-8ABE0A10-C:45 gn LEGO Racers (U) cn Have All Tracks and Building Pieces 812576D4 FFFF 812576D6 FFFF crc 255018DF-57D6AE3A-C:45 gn Lode Runner 3D (U) cn Infinite Lives 8015299F 0063 cn High Gold 80152AFF 0032 8015293B 0032 cn All Navigation Pieces 8015298B 0005 crc 6B700750-29D621FE-C:45 gn Mace - The Dark Ages (U) cn Infinite Time To Choose Character D01340F6 0001 811340F6 0260 cn P2/CPU Never Wins 80138B43 0000 cn Sudden Death Mode\Player 1 D1138B2A 0120 8008B1E7 0001 cn Sudden Death Mode\Player 2 D1138B2A 0120 8008AE5F 0001 cn Infinite Health\Player 1 8008B1E7 0064 cn Infinite Health\Player 2 8008AE5F 0064 cn No Health\Player 1 8008B1E7 0000 cn No Health\Player 2 8008AE5F 0000 cn Extra Characters 8007F9F8 0001 cn R Button Health Restore\Player 1 D007CD2B 0010 8008B1E7 0064 cn Z Trigger Deathblow\Player 1 D007CD2A 0020 8008AE5F 0000 cn 1 Win to Win\Player 1 D0138B47 0000 80138B47 0001 cn 1 Win to Win\Player 2 D0138B43 0000 80138B43 0001 cn Infinite Time 81138B2A 0708 crc 0CB81686-5FD85A81-C:45 gn Madden 2000 (U) cn Enable\Stadium\Dodge City 80059198 00FF cn Enable\Stadium\Xmas Rush 80059199 00FF cn Enable\Stadium\Tib Bros 8005919A 00FF cn Enable\Stadium\Tiberium 8005919B 00FF cn Enable\Stadium\Salvage Field 8005919C 00FF cn Enable\Stadium\Gridiron 8005919D 00FF cn Enable\Stadium\Alpha Blitz 8005919E 00FF cn Enable\Stadium\Nile High 8005919F 00FF cn Enable\Stadium\4th And Incas 800591A0 00FF cn Enable\Stadium\Maddenstein 800591A1 00FF cn Enable\Stadium\Cosmodome 800591A2 00FF cn Enable\Stadium\EA Sports 800591A3 00FF cn Enable\Stadium\Tiburon 800591A4 00FF cn Enable\Stadium\Tampa Bay 800591A5 00FF cn Enable\Stadium\New Orleans 800591A6 00FF cn Enable\Stadium\San Diego 800591A7 00FF cn Enable\Team\All 60's 800598CC 00FF cn Enable\Team\All 70's 800598CD 00FF cn Enable\Team\All 80's 800598CE 00FF cn Enable\Team\All 90's 800598CF 00FF cn Enable\Team\Madden 1999 800598D0 00FF cn Enable\Team\Madden Millenium 800598D1 00FF cn Enable\Team\NFL Millenium 800598D2 00FF cn Enable\Team\EA Sports 800598D3 00FF cn Enable\Team\Tiburon 800598D4 00FF cn Enable\Team\Marshalls 800598D5 00FF cn Enable\Team\Toymakers 800598D6 00FF cn Enable\Team\Clows 800598D7 00FF cn Enable\Team\Praetorians 800598D8 00FF cn Enable\Team\Junkyard Dogs 800598D9 00FF cn Enable\Team\Industrials 800598DA 00FF cn Enable\Team\Sugarbuzz 800598DB 00FF cn Enable\Team\Mummies 800598DC 00FF cn Enable\Team\Vipers 800598DD 00FF cn Enable\Team\Monsters 800598DE 00FF cn Enable\Team\Comets 800598DF 00FF cn Level 1\Recover At Least One Fumble 800707C0 0040 cn Level 1\200 Yards Of Total Offense Or More 800707C1 0040 cn Level 1\Play And Win One Game of The Tournment 800707C2 0040 cn Level 1\Have A Minimium Of Three Players ON Team Catch One Pass 800707C3 0040 cn Level 1\Intercept At Least One Pass 800707BF 0040 cn Level 1\Play a Exhibition Game In A Stadium Other Than The Default One 800707BE 0040 cn Level 1\Sack The Opposing QB 800707BD 0040 cn Level 1\QB Passes For Two TDS Or More 800707BC 0040 cn Level 1\Play A Exhibition Game In A QTR Length Other Than 5 Minutes 800707BB 0040 cn Level 1\Create A Player And use Him In A Game 800707BA 0040 cn Level 1\Defeat San Francisco In Rain At 3COM Park 800707B9 0040 cn Level 1\Defeat Green Bay In Snow At Lambeau Field 800707B8 0040 cn Level 1\3 Tackles Or More By One Player 800707B7 0040 cn Level 1\Kick A 40 Yard Punt Or Longer 800707B6 0040 cn Level 1\Kick A 40 Yard Field Goal Or Longer 800707B5 0040 cn Level 1\Throw 0 Interceptions In A Game 800707B4 0040 cn Level 1\Hold Your Oppnent to 7 Points Or Less In a Game 800707B3 0040 cn Level 1\Score 21 Points Or More With A QTR Length Of 6 Minutes Or Less 800707B2 0040 cn Level 1\Complete A 20 Yard Run Or Longer 800707B1 0040 cn Level 1\Complete A 30 Yard Pass Or Longer 800707B0 0040 cn Level 2\Score 40 Points Or More Within A Quarter Length Of 6 Minutes Or Less 800707C4 0040 cn Level 2\100 Yards Of Rushing Or Greater By One Player 800707C5 0040 cn Level 2\100 Recption Yards Or Greater By One Player 800707C6 0040 cn Level 2\QB Passes 300 Yards Or More 800707C7 0040 cn Level 2\3 Field Goals Or More By One Player 800707C8 0040 cn Level 2\QB Passes For 4 TDS Or More 800707C9 0040 cn Level 2\Play And Win One Franchise Mode Game 800707CA 0040 cn Level 2\Play And Win One Season Mode Game Without Modified Divisions 800707CB 0040 cn Level 2\Play And Win One Season Mode Game With Modified Divisions 800707CC 0040 cn Level 2\Play And Win Two Games In A Tournment With The Same Team 800707CD 0040 cn Level 2\6 Receptions Or Greater By One Player 800707CE 0040 cn Level 2\Have A RB Who Rushes For 3 TDS Or More 800707CF 0040 cn Level 2\Hold Opposing Team To 150 Yards Total Offense Or Less 800707D0 0040 cn Level 2\QB Rushes For One Rushing TD Or More 800707D1 0040 cn Level 2\Commit No Fumbles In A Game 800707D2 0040 cn Level 2\Do Not Allow Your QB To Be Sacked In A Game 800707D3 0040 cn Level 2\Complete a 60 Yard Pass Or Longer 800707D4 0040 cn Level 2\Play And Win A Pro Bowl Game As The NFC Team 800707D5 0040 cn Level 2\Play And Win A Pro Bowl Game As The AFC Team 800707D6 0040 cn Level 2\2 TDS Or More By One Receiver 800707D7 0040 cn Level 3\150 Yards Rushing Or Greater By One Player 800707D8 0040 cn Level 3\150 Reception Yards Or Greater By One Player 800707D9 0040 cn Level 3\QB Who Passes For 400 Yards Or More 800707DA 0040 cn Level 3\3 Sacks Or More By One Player 800707DB 0040 cn Level 3\2 Interceptions Or More By One Player 800707DC 0040 cn Level 3\Recover 2 Fumbles Or More 800707DD 0040 cn Level 3\5 Successful Field Goals Or More By One Player 800707DE 0040 cn Level 3\3 Knockdowns Or More By One PLayer 800707DF 0040 cn Level 3\3 Tips Or More By One Player 800707E0 0040 cn Level 3\Play And Win A Superbowl In Franchise Mode 800707E1 0040 cn Level 3\Play And Win A Superbowl In Season Mode 800707E2 0040 cn Level 3\Successfully Kick 8 Extra Points Or More 800707E3 0040 cn Level 3\Play And Win An 8 Team Tournament 800707E4 0040 cn Level 3\Complete A 50 Yard Run Or Longer 800707E5 0040 cn Level 3\Commit No Penalties In A Game 800707E6 0040 cn Level 3\Break 2 Different All-Time Records Or More In A Game 800707E7 0040 cn Level 3\Score 55 Points Or Greater 800707E8 0040 cn Level 3\8 Tackles Or More By One Player 800707E9 0040 cn Level 3\400 Yards Of Total Defense Or More 800707EA 0040 cn Level 3\Have A RB Rush For Over 100 Yards And 50 Yards Receiving 800707EB 0040 cn Level 4\200 Yards Rushing Or Greater By One Player 800707EC 0040 cn Level 4\200 Receptions Yards Or Greater By One Player 800707ED 0040 cn Level 4\QB Who Passes For 500 Yards Or More 800707EE 0040 cn Level 4\Return A Punt For A Touchdown 800707EF 0040 cn Level 4\Return An Interception For A Touchdown 800707F0 0040 cn Level 4\6 Successful Two Point Conversions Or More 800707F1 0040 cn Level 4\25 Completions Or More By One QB 800707F2 0040 cn Level 4\Go Undefeated And Win A Superbowl In One Franchise Mode Season By Playing Every Game 800707F3 0040 cn Level 4\Go Undefeated And Win A Superbowl In One Season Mode Season By Playing Every Game 800707F4 0040 cn Level 4\QB Who Rushes For 75 Yards Or More 800707F5 0040 cn Level 4\Have A Minimum Of 7 Members Of Your Team Catch At Least 1 Pass 800707F6 0040 cn Level 4\Win A 16 Team Tournament 800707F7 0040 cn Level 4\7 Sacks Or More By One Player 800707F8 0040 cn Level 4\650 Yards Of Total Offense Or More By One Team 800707F9 0040 cn Level 4\Have One Reciever With 150 RAC Yards Or Greater 800707FA 0040 cn Level 4\Rush The Ball 40 Time Or More With A QTR Length Of 6 Minutes Or Less 800707FB 0040 cn Level 4\Rush For 100 Yards Or More With 2 Different Running Backs 800707FC 0040 cn Level 4\Win By A Margin Of 50 Points Or More 800707FD 0040 cn Level 4\40 First Downs Or More 800707FE 0040 cn Level 4\Kick A Punt Of 55 Yards Or More 800707FF 0040 cn Level 5\Return A Kickoff For A Touchdown 80070800 0040 cn Level 5\Have A QB With A Pass AVG Of 30 Yards Or Greater While Throwing At Least 5 Passes 80070801 0040 cn Level 5\Shut Out Opposing Team With A QTR Length Of 5 Minutes 80070802 0040 cn Level 5\Pass For 200 Yards Or More With 2 QBS 80070803 0040 cn Level 5\Have A RB With A Rushing AVG Of 20 Yards Or Greater While Rushing At least 3 Times 80070804 0040 cn Level 5\3 Receivers With 100 Yards Or More Recieving 80070805 0040 cn Level 5\200 Punt Return Yards Or Greater By One Player 80070806 0040 cn Level 5\QB Rushes For 3 Touchdowns Or More 80070807 0040 cn Level 5\Score 80 Points Or Greater 80070808 0040 cn Level 5\200 Kick Return Yards Or Greater By One Player 80070809 0040 cn Level 5\Complete A Run Play Of 80 Yards Or More 8007080A 0040 cn Level 5\Convert 10 4th Down Conversions Or More 8007080B 0040 cn Level 5\QB With A Minimum Of 150 Yards Passing And 100 Yards Rushing 8007080C 0040 cn Level 5\Break 4 Different All-Time Records Or More In A Game 8007080D 0040 cn Level 5\Successfully Kick A FG Of 55 Yards Or More 8007080E 0040 cn Level 5\Have A QB With A 100 Passing PCT While Throwing A Minimum Of 5 Passes 8007080F 0040 cn Level 5\Play And Win A Minimum Of Four Superbowls With The Same Team In Franchise Mode 80070810 0040 cn Level 5\RB With A Minimum Of 100 Yards Receiving And 100 Yards Rushing 80070811 0040 cn Level 5\Convert To 3RD Down Conversions Or More 80070812 0040 cn Level 5\250 Yards Rushing Or Greater By One Player 80070813 0040 cn Infinite\Time-Outs Home Team 8006CE7F 0003 cn No Time-Outs\Home Team 8006EC7F 0000 cn Infinite\Time-Outs Away Team 8006FE6F 0003 cn No Time-Outs\Away Team 8006EF6F 0000 cn Press L For First Down\Player 1 D00753DD 0020 81071B18 0001 cn Press L For First Down\Player 2 D00753E5 0020 81071B18 0001 cn Press L For First Down\Player 3 D00753ED 0020 81071B18 0001 cn Press L For First Down\Player 4 D00753F5 0020 81071B18 0001 cn Press R For Fourth Down\Player 1 D00753DD 0010 81071B18 0004 cn Press R For Fourth Down\Player 2 D00753E5 0010 81071B18 0004 cn Press R For Fourth Down\Player 3 D00753ED 0010 81071B18 0004 cn Press R For Fourth Down\Player 4 D00753F5 0010 81071B18 0004 cn Home Team\Always Has The Ball 810590A8 0000 810590AA 0001 cn Away Team\Always Has The Ball 810590A8 0001 810590AA 0000 cn Have All Secret Codes In Menu 81070788 FFFF 8107078A FFFF 8107078C FFFF 8107078E FFFF cn Press GS For More Time To Choose Play 890723E6 0024 cn Players\Jagged 8005F180 0080 cn Players\Polygon 8005F183 0001 cn Players\Evil Crystal 8005F183 000F cn Uniforms\Ghetto 8005F188 001F cn Uniforms\Bare 8005F188 008F cn Players\Pixel 8005F18D 0001 cn Particle Illusions\A 8005F19B 00FE cn Particle Illusions\B 8005F199 0002 cn Uniforms\Future 8005F207 0033 cn Players\Hallow 8005F233 0047 cn Players\Generic Black & White 8005F233 0058 cn Players\Super Red 8005F43E 0002 crc 13836389-265B3C76-C:45 gn Madden Football 64 (U) cn Infinite\Time Outs Home Team 80082D97 0003 cn Infinite\Time Outs Away Team 80084EE3 0003 cn No Time-Outs\Home Team 80082D97 0000 cn No Time-Outs\Away Team 80084EE3 0000 cn Enable\All Stadiums 50000901 0000 80073510 00FF cn Enable\All Teams 50000901 0000 80073CF8 00FF cn Invisible Players 800545A0 0000 800545A0 0001 800545A0 0002 800545A0 0003 cn Background\Gray Madden 810596E0 0000 cn Background\Pink Madden 810596E0 0001 cn Background\Green & Black Madden 810596E0 0002 cn Background\Coloured Madden 810596E0 0003 cn Background\Pink & Purple Madden 810596E0 0004 cn Background\Pinker Madden 810596E0 0006 crc DEB78BBA-52F6BD9D-C:45 gn Madden NFL 99 (U) cn Infinite\Time Outs Home Team 8005CF89 0003 cn Infinite\Time Outs Away Team 8005FA49 0003 cn No Time-Outs\Home Team 8005CF89 0000 cn No Time-Outs\Away Team 8005FA49 0000 cn Home Team\Scores 50 8005CF87 0032 cn Home Team\Scores 0 8005CF87 0000 cn Away Team\Scores 50 8005FA47 0032 cn Away Team\Scores 0 8005FA47 0000 cn Enable\All Stadiums 50000801 0000 8004A7F0 00FF cn Enable\All Teams 50000E01 0000 8004ADD0 00FF cn Press L For First Down\Player 1 D0066F2D 0020 810612E0 0001 cn Press L For First Down\Player 2 D0066F35 0020 810612E0 0001 cn Press L For First Down\Player 3 D0066F3D 0020 810612E0 0001 cn Press L For First Down\Player 4 D0066F45 0020 810612E0 0001 cn Press R For Fourth Down\Player 1 D0066F2D 0010 810612E0 0004 cn Press R For Fourth Down\Player 2 D0066F35 0010 810612E0 0004 cn Press R For Fourth Down\Player 3 D0066F3D 0010 810612E0 0004 cn Press R For Fourth Down\Player 4 D0066F45 0010 810612E0 0004 cn Press L For More Time To Choose Play\Player 1 D0066F2D 0020 80061245 0028 cn Press L For More Time To Choose Play\Player 2 D0066F35 0020 80061245 0028 cn Press L For More Time To Choose Play\Player 3 D0066F3D 0020 80061245 0028 cn Press L For More Time To Choose Play\Player 4 D0066F45 0020 80061245 0028 crc EB38F792-190EA246-C:45 gn Madden NFL 2001 (U) cn Home Team\Infinite Time-Outs 80071617 0003 cn Home Team\No Time-Outs 80071617 0000 cn Away Team\Infinite Time-Outs 800738E7 0003 cn Away Team\No Time-Outs 800738E7 0000 cn Have All\Cheats 50000402 0000 81070788 FFFF cn Have 99 Tokens 8115F9F0 0063 cn Have All\Stadiums 50000802 0000 81061850 FFFF cn Have All\Teams 50001102 0000 810C1628 FFFF cn Have All\Levels Completed 50001902 0000 8115FB2C FFFF cn Have All\Cards 50007802 0000 8115F9F2 FFFF crc 75B61647-7ADABF78-C:45 gn Magical Tetris Challenge (U) cn Always Get\Magical Tetris Pieces 811D267E DB20 cn Always Get\Straight Pieces 801D25F4 0000 cn Quick Score Gain 811D26A6 FFFF crc 664BA3D4-678A80B7-C:45 gn Mario Golf (U) cn Enable All Courses 81130CEE FFFF cn No Wind 810BA9F1 0000 800BA9F3 0000 cn Unlimited\Power Hits\Player 1 801B71F8 0004 cn Unlimited\Power Hits\Player 2 801B72B0 0004 cn Unlimited\Power Hits\Player 3 801B7368 0004 cn Unlimited\Power Hits\Player 4 801B7420 0004 cn Have All Characters 50000E02 0001 810C28E4 0000 cn Max Gold Mario Badges Player 1 800C545B 0063 cn Zero Strokes Taken 801B71F3 0000 crc 3E5055B6-2E92DA52-C:45 gn Mario Kart 64 (U) cn Infinite Items\2 player Mode\Player 1 80165F5D ???? 80165F8A ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\2 player Mode\Player 2 8016603D ???? 8016606A ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 1 8016611D ???? 8016614A ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 2 801661FD ???? 8016622A ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 3 801662DD ???? 8016630A ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Infinite Items\3-4 player Mode\Player 4 801663BD ???? 801663EA ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn No Laps to Race 81164390 0000 81164392 0002 cn Always Have\46 Pts\Bowser 8018D9CF 002D cn Always Have\46 Pts\D.K. 8018D9CC 002D cn Always Have\46 Pts\Luigi 8018D9C9 002D cn Always Have\46 Pts\Mario 8018D9C8 002D cn Always Have\46 Pts\Peach 8018D9CE 002D cn Always Have\46 Pts\Toad 8018D9CB 002D cn Always Have\46 Pts\Wario 8018D9CD 002D cn Always Have\46 Pts\Yoshi 8018D9CA 002D cn Press GS\To Play 2 Players In 1 Player Game 8918EDE4 0003 8918EDE4 0007 8918EDE4 0005 8918EDE4 0001 cn All Players Can Choose The Same Character 810B3924 2400 810B3936 7FFF 810B39A4 2400 810B39B6 7FFF 810B3A38 2400 810B3A4E 7FFF cn Press GS\For Full Debug Menu cd Press GS at the Press Start Menu to access the Debug Menu 8818EDEF 0002 cn Have Bonus Mode and All Gold Cups 50000401 0000 8018ED10 ???? 0000:"Off",00FF:"On" cn Press L To Levitate\Player 1 D00F6915 0020 810F69C8 4000 cn Press L To Levitate\Player 2 D00F6925 0020 810F77A0 4000 cn Press L To Levitate\Player 3 D00F6935 0020 810F8578 4000 cn Press L To Levitate\Player 4 D00F6945 0020 810F9350 4000 crc 2829657E-A0621877-C:45 gn Mario Party (U) cn Top Left Character\Coin Options cd If you want to have full 255 Coins,1st use the 100 Option then put on 255. this will stop the numbers from changing & spoiling the result. 800F32B8 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Left Character\Star Options 800F32BC ???? 0000:"0 Stars",0064:"99 Stars" cn Top Right Character\Coin Options 800F32E8 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Right Character\Star Options 800F32EC ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Left Character\Coin Options 800F3318 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Left Character\Star Options 800F331C ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Right Character\Coin Options 800F3348 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Right Character\Star Options 800F334C ???? 0000:"0 Stars",0064:"99 Stars" cn Top Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D62D3 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Top Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D6317 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D635B ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800D639F ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Mini Game\Unlimited 99 lives 800F3767 0063 cn Mini Game\Max 99 Coins 800F3770 0063 cn Board Select 800ED5C3 ???? 0000:"DK's Jungle Adventure",0001:"Peach's Birthday Cake",0002:"Yoshi's Tropical Island",0003:"Wario's Battle Canyon",0004:"Luigi's Engine Room",0005:"Mario's Rainbow Castle",0006:"Bowser's Magma Mountain",0007:"Eternal Star",0008:"Explaination Map",0009:"Mini Game Stadium" cn Mini Game Island\Press GS For 99 Lives 880F37BB 0063 cn Mini Game Island\99 Coins 800F37C4 0063 cn Mini Game Island\Always Clear Level 800F32BB 0063 cn Mini Game Island\World Level Select cd Select where you want to go then Enable the cheat. as soon as you enter turn the cheat back off so you can move on to the next level and not the same place. 810F32C4 ???? 0000:"Start Save and Return Space",0001:"1-1 Coin Block Blitz",0002:"1-2 Coin Block Bash",0003:"1-3 Coin Shower Flower",0004:"1-4 Paddle Battle",0005:"Save and Return Space 1",0006:"2-1 Memory Match",0007:"2-2 Ground Pound",0008:"2-3 Limbo Dance",0009:"2-4 Magical Mushroom",000A:"2-5 Piranha's Pursuit",0018:"3-1 Crazy Cutter",0019:"3-2 Buried Treasure",001A:"3-3 Desrt Dash",001B:"3-4 Tug O' War",001C:"3-5 Teetering Towers",001D:"Save and Return Space 2",001E:"World 4-1 to 4-3 - Entrance",0028:"World 4-4 Entrance",0029:"Save and Return Space 3",002A:"World 6-1 to 6-6 Castle Entrance",0048:"World 8-6 to 8-1 Castle Entrance 2",0049:"Save and Return Space 4",004A:"9-1 Hammer Drop",004B:"9-2 Slot Car Derby",004C:"9-3 Shell Game",004D:"9-4 Knock Block Tower",004E:"9-5 Platform Peril",004F:"Goal Space - Final Goal" crc 9EA95858-AF72B618-C:45 gn Mario Party 2 (U) cn Infinite Coins Main Menu 810F8CD2 FFFF cn Lower Right Char\Rolls 10 800DF5A9 000A cn Lower Right Char\Item On Pick-Up 800FD375 ???? 0000:"Mushroom",0001:"Skeleton Key",0002:"Plunder Chest",0003:"Bowser Bomb",0004:"Dueling Glove",0005:"Warp Block",0006:"Golden Mushroom",0007:"Boo Bell",0008:"Bowser Suit",0009:"Magic Lamp" cn Upper Left Char\Rolls 10 800DF4C5 000A cn Upper Left Char\Item On Pick-Up 800FD2D9 ???? 0000:"Mushroom",0001:"Skeleton Key",0002:"Plunder Chest",0003:"Bowser Bomb",0004:"Dueling Glove",0005:"Warp Block",0006:"Golden Mushroom",0007:"Boo Bell",0008:"Bowser Suit",0009:"Magic Lamp" cn Upper Right Char\Rolls 10 800DF511 000A cn Upper Right Char\Item On Pick-Up 800DF30D ???? 0000:"Mushroom",0001:"Skeleton Key",0002:"Plunder Chest",0003:"Bowser Bomb",0004:"Dueling Glove",0005:"Warp Block",0006:"Golden Mushroom",0007:"Boo Bell",0008:"Bowser Suit",0009:"Magic Lamp" cn Lower Left Char\Rolls 10 800DF55D 000A cn Lower Left Char\Item On Pick-Up 800FD341 ???? 0000:"Mushroom",0001:"Skeleton Key",0002:"Plunder Chest",0003:"Bowser Bomb",0004:"Dueling Glove",0005:"Warp Block",0006:"Golden Mushroom",0007:"Boo Bell",0008:"Bowser Suit",0009:"Magic Lamp" crc 7C3829D9-6E8247CE-C:45 gn Mario Party 3 (U) cn Top Left Character\Coin Options cd If you want to have full 255 Coins,1st use the 100 Option then put on 255. this will stop the numbers from changing & spoiling the result. 810D1112 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Left Character\Star Options 800D1116 ???? 0000:"0 Stars",0064:"99 Stars" cn Top Right Character\Coin Options 810D114A ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Right Character\Star Options 800D114E ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Left Character\Coin Options 810D1182 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Left Character\Star Options 800D1186 ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Right Character\Coin Options 810D11BA ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Right Character\Star Options 800D11BE ???? 0000:"0 Stars",0064:"99 Stars" cn Top Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDBD5 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Top Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDC21 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDC6D ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDCB9 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" crc 5001CF4F-F30CB3BD-C:45 gn Mario Tennis (U) cn Have All\Characters Available 810653C8 FFFF cn Have All\Courts Available 810653CC FFFF cn Score\Player 1 8015344A ???? 0000:"0",0001:"15",0002:"30",0003:"40" cn Score\Player 2 8015344B ???? 0000:"0",0001:"15",0002:"30",0003:"40" cn Press C-Down For Easy Win Ring Shot - Game cd Do Not use with Time,Balls,Points Option D0066985 0004 8015350B 0082 cn Press C-Down Easy Win Ring Shot - Time,Balls,Points cd Do Not use with Game Option D0066985 0004 80153527 0082 D0066985 0004 80153523 0082 crc 0EC158F5-FB3E6896-C:45 gn Mega Man 64 (U) cn Rapid Fire 80204EB3 0002 cn Infinite\Health 81204A1E 0050 cn Infinite\Zenny 811BC404 E0FF 811BC406 05F5 cn Have\Normal Items 81205650 FFFF 81205652 FFFF 81205654 FFFF 81205656 FFFF cn Have\Special Items 8120564C FFFF 8120564E FFFF cn Infinite\Ammo 81204EBA 0080 81204EC2 0010 81204ECA 0708 81204ED2 0018 81204EDA 0010 81204EE2 0708 81204EEA 0020 81204EF2 0020 81204EFA 0020 81204F02 0018 81204F0A 012C 81204F12 0258 cn Have\All Special Weapons cd With this code, Roll is the one that has to equip the weapons before you can use them. 81205640 FFFF crc FA8C4571-BBE7F9C0-C:45 gn Mickey's Speedway USA (U) cn Play As 800D3081 ???? 0000:"Mickey Mouse",0001:"Daisy Duck",0002:"Goofy",0003:"Pete",0004:"Minnie Mouse",0005:"Donald Duck",0006:"Huey",0007:"Dewey",0008:"Louie",0009:"Lugwig Von Drake" cn Traffic Troubles\Indianapolis\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018E782 0063 cn Traffic Troubles\San Fransisco\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80191A52 0063 cn Traffic Troubles\New Mexico\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018FD52 0063 cn Traffic Troubles\Grand Canyon\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80193142 0063 cn Motor Way Mania\Los Angeles\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018DBE2 0063 cn Motor Way Mania\Alaska\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018E372 0063 cn Motor Way Mania\Las Vegas\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80192A02 0063 cn Motor Way Mania\Philadelphia\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80193882 0063 cn Freewayphobia\Dakota\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018D102 0063 cn Freewayphobia\Seattle\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018FCE2 0063 cn Freewayphobia\New York\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018F402 0063 cn Freewayphobia\Chicago\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80191F32 0063 cn Victory Vehicles\Yellowstone\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018D3B2 0063 cn Victory Vehicles\Washington DC\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80197552 0063 cn Victory Vehicles\Everglades\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018FB12 0063 cn Victory Vehicles\Malibu\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801915A2 0063 cn Frantic Finale\Hawaii\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80191F62 0063 cn Frantic Finale\Oregon\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018E932 0063 cn Frantic Finale\Texas\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 8018F0D2 0063 cn Frantic Finale\Colorado\Max Tokens cd Only use one Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 80191882 0063 cn Level Select 801875A9 ???? 0000:"Traffic Troubles",0001:"Motor Way Mania",0002:"Freewayphobia",0003:"Vitory Vehicles",0004:"Frantic Finale",0005:"Time Trial",0006:"Practice",0007:"Contest",0008:"Options" cn Difficulty Select 8007BF00 ???? 0000:"Amateur",0001:"Intermediate",0002:"Professional",0003:"Mirror Mode" cn Unlock Everything cd This will unlock all characters, tracks, mirror mode, all in-game cheats, postcards, pluto's collar and give you all Trophies for every track and difficulties. To have this cheat save to mempak, enable it and then go into the Options Menu and disable the cheat. Go to the Wide-Screen Settings and Change it to Wide-Screen [16.9] and then the B button to get back to Wide-Screen Settings, now go back into Wide-Screen [16.9] and change it back to Normal [4.3].and press the B button until you come back to the main Options Menu.Close the game and load it again to see everything saved to the Mempak and unlocked. 800D3128 008F 800D3129 0094 800D312A 0003 800D312C 0001 800D312F 0080 50000502 0000 800D3130 0009 50000502 0000 800D3131 0024 800D313A 0015 800D313B 007F 800D313C 0001 800D313D 00FF 800D313E 0004 800D313F 0022 cn Always 1st & final time 00:00.00 cd All Levels 50000301 0000 801CE609 0000 cn Re-name Characters\Mickey\Letter 1 801BE591 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 2 801BE592 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 3 801BE593 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 4 801BE594 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 5 801BE595 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 6 801BE596 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 1 801BE598 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 2 801BE599 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 3 801BE59A ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 4 801BE59B ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 5 801BE59C ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 6 801BE59D ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 1 801BE59F ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 2 801BE5A0 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 3 801BE5A1 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 4 801BE5A2 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 5 801BE5A3 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 6 801BE5A4 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 1 801BE5A6 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 2 801BE5A7 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 3 801BE5A8 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 4 801BE5A9 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 5 801BE5AA ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 1 801BE5AC ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 2 801BE5AD ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 3 801BE5AE ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 4 801BE5AF ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 5 801BE5B0 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 1 801BE5B2 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 2 801BE5B3 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 3 801BE5B4 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 4 801BE5B5 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 1 801BE5B7 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 2 801BE5B8 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 3 801BE5B9 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 4 801BE5BA ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 1 801BE5BC ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 2 801BE5BD ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 3 801BE5BE ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 4 801BE5BF ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 5 801BE5C0 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 1 801BE5C2 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 2 801BE5C3 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 3 801BE5C4 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 4 801BE5C5 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 5 801BE5C6 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 1 801BE5C8 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 2 801BE5C9 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 3 801BE5CA ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 4 801BE5CB ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 5 801BE5CC ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 6 801BE5CD ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Traffic Troubles\Indianapolis\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018E75B 0063 cn Traffic Troubles\San Fransisco\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 80191A2B 0063 cn Traffic Troubles\New Mexico\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018FD2B 0063 cn Traffic Troubles\Grand Canyon\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8019311B 0063 cn Motor Way Mania\Los Angeles\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018DBBB 0063 cn Motor Way Mania\Alaska\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018E34B 0063 cn Motor Way Mania\Las Vegas\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801929DB 0063 cn Motor Way Mania\Philadelphia\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8019385B 0063 cn Freewayphobia\Dakota\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018D0DB 0063 cn Freewayphobia\Seattle\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018FCBB 0063 cn Freewayphobia\New York\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018F3DB 0063 cn Freewayphobia\Chicago\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 80191F0B 0063 cn Victory Vehicles\Yellowstone\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018D38B 0063 cn Victory Vehicles\Washington DC\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8019752B 0063 cn Victory Vehicles\Everglades\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018FAEB 0063 cn Victory Vehicles\Malibu\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8019157B 0063 cn Frantic Finale\Hawaii\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 80191F3B 0063 cn Frantic Finale\Oregon\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018E90B 0063 cn Frantic Finale\Texas\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8018F0AB 0063 cn Frantic Finale\Colorado\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 8019185B 0063 crc F1850C35-ACE07912-C:45 gn Micro Machines 64 Turbo (U) cn Always Place 1st 802083F1 0001 cn Infinite\Lives 800BAFD2 0009 cn Infinite\Specials On Pickup 80208401 0005 crc 09D53E16-3AB268B9-C:45 gn Mike Piazza's Strike Zone (U) cn Infinite\Balls 801606D0 0000 cn Almost Always Hit A Home Run 80195714 0001 cn Fast Game 80195729 0001 cn Increased Gravity 80195727 0001 cn Low Gravity 80195726 0001 cn Slow Game 8019572A 0001 cn Home Team\Score 0 cd Do not use with Home Team Scors 30 801606B7 0000 cn Home Team\Score 30 cd Do not use with Home Team Scors 0 801606B7 001E cn Away Team\Score 0 cd Do not use with Away Team Scors 30 801606B5 0000 cn Away Team\Score 30 cd Do not use with Away Team Scors 30 801606B5 001E cn Infinite\Strikes 801606D1 0000 cn Stadium Modifier 800DE7E5 ???? 0000:"Edison Into Field",0001:"The Ball Park At Arlington",0002:"The Astrodome",0003:"Bank One Ballpark",0004:"Milwaukee County Stadium",0005:"Baltimore",0006:"3com Park at Candle Stick Park",0007:"Comiskey Park",0008:"Coors Field",0009:"Olympics Stadium",000A:"Fenway Park",000B:"Jacobs Field",000C:"Proplayer Stadium",000D:"Kauffman Stadium",000E:"The Kingdom",000F:"Dodger Stadium",0010:"Oakland Alameda Country Stadium",0011:"Qualcomm Stadium at Jack Murphy Field",0012:"Cinergy Field",0013:"Shea Stadium",0014:"Skydome",0015:"Bush Stadium",0016:"3 Rivers Stadium",0017:"Tiger Stadium",0018:"Tropicane Field",0019:"Turner Field",001A:"Hubert Humphrey Metrodome",001B:"Veterans Stadium",001C:"Wrigley Field",001D:"Yankee Stadium",001E:"Devil's Thumb Stadium" crc 2E955ECD-F3000884-C:45 gn Milo's Astro Lanes (U) cn Bowl A Perfect Game 5000090C 0000 800AC9F0 000A 800ACA5E 000A crc 0B93051B-603D81F9-C:45 gn Mischief Makers (U) cn Infinite\Red Gems 81175B66 270F cn Infinite\Health 810ED0E0 03E8 crc 26035CF8-802B9135-C:45 gn Mission Impossible (U) cn Invincibility 810862B4 0101 cn Infinite\Ammo All Guns 50000610 0000 800A8EA7 00FF cn Infinite\Health 810862B2 FFFF cn Access All Levels 8008A5C6 0001 8008A5DA 0001 8008A602 0001 8008A652 0001 8008A666 0001 8008A67A 0001 8008A68E 0001 8008A6A2 0001 8008A6B6 0011 8008A6CA 0021 8008A6DE 0001 8008A706 0011 8008A71A 0041 8008A72E 0021 8008A742 0081 8008A756 0001 8008A76A 0081 8008A77E 0001 8008A7A6 0001 8008A7CE 0001 8008A7E2 0011 8008A7F6 0021 8008A846 0001 8008AB2A 0001 8008AB3E 0001 8008AB52 0001 8008AB66 0001 cn Freeze All Timers 81093D40 0063 81093D42 0063 81093D44 0063 cn Weapon Select 800A8EA5 ???? 800A8EB5 ???? 800A8EC5 ???? 0000:"9MM Hi Power",0001:"Silenced Pistol",0002:"Uzi",0003:"Fists",0032:"Gas Spray",0036:"Blow Torch",001F:"Fire Extinguisher",0024:"Spray Paint",0027:"Electrostunner",000B:"Blow Dart Gun",000C:"Dart Hand Gun",002D:"Mini Rocket Launcher" cn Walk Through Walls & Objects cd This will allow you to pass through anything & even walk on water.if you amerge somewhere in the ground just press the A button. 80093EF5 ???? 0080:"On",0000:"Off" crc 5AC383E1-D712E387-C:45 gn Monopoly (U) cn Infinite\Money\Player 1 81324B46 270F cn Infinite\Money\Player 2 81324B5A 270F cn Infinite\Money\Player 3 81324B6E 270F cn Infinite\Money\Player 4 81324B82 270F cn [Language Select] cd To use this load the game then enable this cheat and Reset (F1) you will now be on your chosen Language and Relative Local Language Board and Money. D009675F 0001 80096758 ???? 0000:"American",0001:"British",0002:"France",0003:"German" crc B19AD999-7E585118-C:45 gn Monster Truck Madness 64 (U) cn Have\Aztec Valley Track 801256BF 0001 cn Have\Alpine Challenge Track 801256DF 0001 cn Have\Death Trap Track 801256FF 0001 cn Infinite Missiles (Upon Pickup) D0164BBF 0001 801A6054 0009 crc 417DD4F4-1B482FE2-C:45 gn Mortal Kombat 4 (U) cn Big Head Mode 80048CB5 0001 cn Infinite\Health Player 1 810FE0D8 0001 810FE0DA 0000 cn Infinite\Health Player 2 81126F54 0001 81126F56 0000 cn 1 Round To Win Player 1 D01050F3 0000 801050F3 0001 cn 99 Wins Player 1 800FE27F 0063 cn Infinite\Credits 800493BF 00FF cn Infinite\Time 8010511B 0063 cn Play\As Goro Player 1 800FE293 000F cn Play\As Noob Saibot Player 1 800FE293 0011 crc C34304AC-2D79C021-C:45 gn Mortal Kombat Mythologies - Sub-Zero (U) cn Infinite Lives 8010BCFF 0009 cn Invincible 8009F742 0001 cn Level Select D009A913 0000 8009A913 ???? 0000:"Level 1 - Shaolin Temple - China",0001:"Level 2 - Wind Realm",0002:"Level 3 - Earth Realm",0003:"Level 4 - Water Realm",0004:"Level 5 - Fire Ream",0005:"Level 6 - Prison",0006:"Level 7 - Bridge",0007:"Level 8 - Fortress" cn Max Experience 8111200E FC9A crc D9F75C12-A8859B59-C:45 gn Mortal Kombat Trilogy (U) (v1.0) cn Player 1\No Energy 8016984D 0000 cn Player 2\No Energy 80169B21 0000 cn Player 2\Unlimited Energy 80169B21 00A6 cn Player 1\Unlimited Energy 8016984D 00A6 crc 2AF9B65C-85E2A2D7-C:45 gn MRC - Multi Racing Championship (U) cn Infinite Time 80094E97 0064 cn Low Course Time 8009483B 0000 cn Always Place 1st 800A960F 0000 crc 1938525C-586E9656-C:45 gn Ms. Pac-Man Maze Madness (U) cn Infinite\Health 8111D55C 003C cn Infinite\Lives 8010A3D7 0009 cn Have All Dots 8111D55E 03E7 cn Max Score 8111EF14 E0FF 8111EF16 05F5 crc FCBCCB21-72903C6B-C:45 gn Mystical Ninja - Starring Goemon (U) cn Infinite\Health 8015C5E7 0028 cn Infinite\Lives 8015C5EF 0009 cn Infinite\Money 8115C5EA 270F cn Press\L To Levitate D00C7D3B 0020 8116A044 4000 cn Press\R To Use Chargeable Weapon D00C7D3B 0010 8120C896 005D cn Max Heart Containers 8015C5E3 0027 cn Play As 8015C5DF ???? 0000:"Goemon,01 Ebisumaru,02 Sasuke,03 Yae" cn Goemon\Have\Chain Pipe 8015C6BF 0002 cn Goemon\Have\Medal of Flames 8015C6DF 0001 cn Goemon\Have\Magic Sudden Impact 8015C6EF 0001 cn Goemon\Pipe Modifier 8015C6AF ???? 0000:"Normal Pipe,01 Silver Pipe,02 Gold Pipe" cn Yae\Have\Bazooka 8015C6DB 0001 cn Yae\Have\Flute 8015C6CB 0001 cn Yae\Have\Magic Mermaid 8015C6FB 0001 cn Yae\Katana Modifier 8015C6BB ???? 0000:"Normal Katana,01 Silver Katana,02 Gold Katana" cn Ebisumaru\Automatically Complete Ebisumaru's Training 803B52F4 0008 cn Ebisumaru\Have\Windup Camera 8015C6D3 0001 cn Ebisumaru\Have\Meat Saw Hammer 8015C6C3 0001 cn Ebisumaru\Have\Magic Mini Ebisu 8015C6F3 0001 cn Ebisumaru\Saw Hammer Modifier 8015C6B3 ???? 0000:"Normal Saw Hammer",0001:"Silver Saw Hammer",0002:"Gold Saw Hammer" cn Sasuke\Have\Fire Cracker Bomb 8015C6C7 0001 cn Sasuke\Have\Kunai of Severe Cold 8015C6D7 0001 cn Sasuke\Have\Magic Flying 8015C6F7 0001 cn Sasuke\Kunai Modifier 8015C6B7 ???? 0000:"Normal Kunai,01 2 Kunai's,02 Gold Kunai" cn Have\Triton Shell 8015C6FF 0001 cn Have\Brown Item 8015C703 0001 cn Have\Silver Fortune Doll 8015C707 0001 cn Have\Brown Round Item 8015C70F 0001 cn Have\Gold Key 8015C713 0001 cn Have\Blue Sausage 8015C717 0001 cn Have\Pink Fish 8015C71B 0001 cn Have\Gold Fish 8015C71F 0001 cn Have\Blue Fish 8015C723 0001 cn Goemon\D-Pad Up To Refill Oil D0067D3A 0008 812F706A 03E7 cn Goemon\Maximum Money 812F70EA 03E7 cn Goemon\Robot Boss' Has No Health 812F7062 0000 cn Goemon\D-Pad Left To Charge Laser D00C7D3A 0002 802F706F 0064 crc 8D2BAE98-D73725BF-C:45 gn Nagano Winter Olympics '98 (U) cn Press [START] To Reset Timer 81137886 0000 cn Infinite Stamina 81138400 447A 81138404 447A crc 5129B6DA-9DEF3C8C-C:45 gn Namco Museum 64 (U) cn Dig-Dug\Infinite\Credits 800FE67E 0063 cn Dig-Dug\Infinite\Lives\Player 1 800FE709 0002 cn Dig-Dug\Score\Player 1 810FE704 9999 cn Dig-Dug\Infinite\Lives\Player 2 800FE76B 0004 cn Dig-Dug\Score\Player 2 810FE768 9999 cn Galaga\Infinite\Credits 800D76A4 0063 cn Galaga\Infinite\Lives\Both Players 800D7510 0002 cn Galaxian\Infinite\Credits 800CD3D0 0063 cn Galaxian\Infinite\Lives 800CD3AD 0003 cn Galaxian\Score\Player 1 810BCE7C 9999 cn Galaxian\Score\Player 2 810BC780 9999 cn Ms Pac-Man\Infinite\Credits 800BBE4B 0063 cn Ms Pac-Man\Infinite\Lives\Player P1 800BBE23 0004 cn Ms Pac-Man\Score Modifier\Player 1 810BC7E8 9999 cn Ms Pac-Man\Infinite\Lives\Player 2 800BBE27 0004 cn Ms Pac-Man\Score\Player 2 810BC7EC 9999 cn Ms Pac-Man\High Score Modifier 810BC1F8 9999 cn Ms Pac-Man\Eat All Ghosts All The Time 810BC100 0000 810BC102 0000 810BC12C 0000 810BC12E 0000 810BC158 0000 810BC15A 0000 810BC184 0000 810BC186 0000 cn Pac-Man\Infinite\Credits 800A8817 0063 cn Pac-Man\Infinite\Lives\Player 1 800BBE23 0004 cn Pac-Man\Score\Player 1 810A86F0 9999 cn Pac-Man\Infinite\Lives\Player 2 800BBE27 0004 cn Pac-Man\Score\Player 2 810A86F4 9999 cn Pac-Man\High Score 810A86F8 9999 cn Pac-Man\Eat All Ghosts All The Time 810A8760 0000 810A8762 0000 810A878C 0000 810A878E 0000 810A87B8 0000 810A87BA 0000 810A87E4 0000 810A87E6 0000 cn Pole Position\Infinite Time 8010A243 0063 cn Pole Position\Score 81107BF8 9999 crc 23749578-80DC58FD-C:45 gn NASCAR 99 (U) cn 1 Lap to Race 800438B3 0009 D021FBAB 0000 8021FBAB 0008 D022359B 0000 8022359B 0008 cn Total Laps to Race Modifier 800438B3 ???? 0001:"1 lap",0002:"2 lap",0003:"3 lap",0004:"4 lap",0005:"5 lap",0006:"6 lap",0007:"7 lap",0008:"8 lap",0009:"9 lap" cn Max Gear Ratios 810C9E90 7F1E 810C9E82 707F crc DF331A18-5FD4E044-C:45 gn NASCAR 2000 (U) cn Total Number Of Laps 80046553 ???? 0001:"1 lap",0002:"2 lap",0003:"3 lap",0004:"4 lap",0005:"5 lap",0006:"6 lap",0007:"7 lap",0008:"8 lap",0009:"9 lap" cn 1 Lap Race cd Do not put this on with Total Number of Laps Code 810495AE 0001 cn Infinite Fuel\Player 1 81220502 3E80 cn Infinite Fuel\Player 2 81230472 3E80 cn Maximum\Pit Distance 800C7110 0000 cn Maximum\Top Speed 800C7111 0000 cn Maximum\Acceleration 800C7113 0000 cn Beat Championship Mode Easily 80223E3B 0255 cn Race Forever 810465AE FDE8 cn Both Players Can Be Dale E 80046538 0003 cn Have CPU Control Car Player 1 D0092985 0020 8015CC5C 0001 D0092985 0010 8015CC5C 0000 crc 4E69B487-FE18E290-C:45 gn NBA Hangtime (U) cn Team 1 Scores 150 pts 800A6689 0096 cn Team 2 Scores 150 pts 800A668B 0096 crc EBEEA8DB-F2ECB23C-C:45 gn NBA JAM 2000 cn Infinite Shot Clock 801378DF 0016 cn Infinite Violation Clock 8013783B 005D cn Infinite Turbo\Team 1\Player 1 8115B512 FF00 cn Infinite Turbo\Team 1\Player 2 8115B516 FF00 cn Team 1 Score Select 80137117 ???? 0000:"00",0096:"150" cn Infinite Turbo\Team 2\Player 1 8115B50A FF00 cn Infinite Turbo\Team 2\Player 2 8115B50E FF00 cn Team 2 Score Select 80137113 ???? 0000:"00",0096:"150" crc 810729F6-E03FCFC1-C:45 gn NBA Jam 99 (U) cn Home Team\Scores 150 81160FFA 0096 cn Home Team\Scores 0 81160FFA 0000 cn Away Team\Scores 150 81160FFE 0096 cn Home Team\Scores 0 81160FFE 0000 cn Infinite\Time Outs\Home 800D5C75 0007 cn No Time Outs\Home 800D5C7F 0000 cn Infinite\Time Outs\Away 800D5C9B 0007 cn No Time Outs\Away 800D5C9B 0000 cn Away Team\Full Court Dunks 81182E4E 0004 8118305A 0004 81183266 0004 81183472 0004 8118367E 0004 cn Away Team\Giant Players 81182DF6 0032 81182DFE 003C 81183002 0032 8118300A 003C 8118320E 0032 81183216 003C 8118341A 0032 81183422 003C 81183626 0032 8118362E 003C cn Away Team\Tiny Players 81182DF6 0011 81182DFE 0014 81183002 0011 8118300A 0014 8118320E 0011 81183216 0014 8118341A 0011 81183422 0014 81183626 0011 8118362E 0014 cn Creation Points (L / R) D0061269 0020 8117E008 0200 D0061269 0010 8117E008 0000 cn Home Team\Full Court Dunks 81182412 0004 8118261E 0004 8118282A 0004 81182A36 0004 81182C42 0004 cn Home Team\Giant Players 811823BA 0032 811823C2 003C 811825C6 0032 811825CE 003C 811827D2 0032 811827DA 003C 811829DE 0032 811829E6 003C 81182BEA 0032 81182BF2 003C cn Home Team\Tiny Players 811823BA 0011 811823C2 0014 811825C6 0011 811825CE 0014 811827D2 0011 811827DA 0014 811829DE 0011 811829E6 0014 81182BEA 0011 81182BF2 0014 crc 6A121930-665CC274-C:45 gn NBA In The Zone '98 (U) cn Options\FT. Penalty Situations 80144999 ???? 0000:"2",0001:"4",0002:"6",0003:"No" cn Home Team\Scores 8013C2B1 ???? 0000:"No Points",000A:"10 Points",0014:"20 Points",0028:"40 Points",003C:"60 Points",0050:"80 Points",0064:"100 Points",00C8:"200 Points",00FA:"250 Points" cn Away Team\Scores 8013C2B3 ???? 0000:"No Points",000A:"10 Points",0014:"20 Points",0028:"40 Points",003C:"60 Points",0050:"80 Points",0064:"100 Points",00C8:"200 Points",00FA:"250 Points" cn Home Team\Infinite Time-Outs cd Do not use this with the No Time Out's Cheat 8013C2D6 0009 80140862 0009 cn Away Team\Infinite Time-Outs cd Do not use this with the No Time Out's Cheat 8013C2D7 0009 80140863 0009 cn Home Team\No Time-Outs cd Do not use this with the Infinite Time Out's Cheat 8013C2D6 0000 80140862 0000 cn Away Team\No Time-Outs cd Do not use this with the Infinite Time Out's Cheat 8013C2D7 0000 80140863 0000 cn No Shot Clock 81140E1E FFFF cn Create A Player\Max Field Goal 8013FF98 0063 cn Create A Player\Max 3 Point 8013FF99 0063 cn Create A Player\Max Free Throw 8013FF9A 0063 cn Create A Player\Max Rebound 8013FF9C 0063 cn Create A Player\Max Block 8013FF9D 0063 cn Create A Player\Max Steal 8013FF9E 0063 cn Create A Player\Max Speed 8013FF9F 0063 cn Create A Player\Max Ball Control 8013FFA1 0063 cn Create A Player\Max Power 8013FFA2 0063 cn Options\Quarter Length 8013D865 ???? 0000:"3:00",0001:"5:00",0002:"8:00",0003:"12:00" cn Options\Level 8013D864 ???? 0000:"Enjoy",0001:"Exciting",0002:"Super Challenge" cn Options\Stamina 8013D866 ???? 0000:"On",0001:"Off" cn Options\27 Time Out Limit 8013D867 ???? 0000:"Yes",0001:"No" cn Options\Replay 8013D868 ???? 0000:"Yes",0001:"No" cn Options\Player Display 8013D869 ???? 0000:"Name",0001:"Number",0002:"None" cn Options\Camera View 8013D86A ???? 0000:"1",0001:"2",0002:"3",0003:"4",0004:"5",0005:"6",0006:"7",0007:"8",0008:"9",0009:"10" cn Options\Out Of Bounds 80144990 ???? 0000:"1",0001:"2",0002:"3",0003:"4",0004:"5",0005:"6",0006:"7",0007:"8",0008:"9",0009:"10" cn Options\Shot Clock Violation 80144991 ???? 0000:"1",0001:"2",0002:"3",0003:"4",0004:"5",0005:"6",0006:"7",0007:"8",0008:"9",0009:"10" cn Options\Second Violation 80144992 ???? 0000:"1",0001:"2",0002:"3",0003:"4",0004:"5",0005:"6",0006:"7",0007:"8",0008:"9",0009:"10" cn Options\5 Second Violation 80144993 ???? 0000:"1",0001:"2",0002:"3",0003:"4",0004:"5",0005:"6",0006:"7",0007:"8",0008:"9",0009:"10" cn Options\3 Second Violation 80144994 ???? 0000:"1",0001:"2",0002:"3",0003:"4",0004:"5",0005:"6",0006:"7",0007:"8",0008:"9",0009:"10" cn Options\Foul Out 80144995 ???? 0000:"2",0001:"4",0002:"6",0003:"No" cn Options\Back Court 80144996 ???? 0000:"2",0001:"4",0002:"6",0003:"No" cn Options\Traveling 80144997 ???? 0000:"2",0001:"4",0002:"6",0003:"No" cn Options\Goal Tending 80144998 ???? 0000:"2",0001:"4",0002:"6",0003:"No" crc A292524F-3D6C2A49-C:45 gn NBA In The Zone '99 (U) cn No Shot Clock 812010C4 43FF cn Home Team\Score 81290378 ???? 0000:"o Points",0A01:"0 Points",1402:"0 Points",2804:"0 Points",3C06:"0 Points",5008:"0 Points",6401:"00 Points",C802:"00 Points",FA02:"50 Points" cn Away Team\Score 8129195C ???? 0000:"o Points",0A01:"0 Points",1402:"0 Points",2804:"0 Points",3C06:"0 Points",5008:"0 Points",6401:"00 Points",C802:"00 Points",FA02:"50 Points" cn Home Team\Time Outs Home 80290374 ???? 0000:"None",0007:"Infinite" cn Away Team\Time Outs 80291958 ???? 0000:"None",0007:"Infinite" cn Create A Player Codes\Max Shooting 802C5EFB 0063 cn Create A Player Codes\Max 3 Point 802C5EFC 0063 cn Create A Player Codes\Max Free Throw 802C5EFD 0063 cn Create A Player Codes\Max Offensive 802C5EFE 0063 cn Create A Player Codes\Max Defensive 802C5EFF 0063 cn Create A Player Codes\Max Rebound 802C5F00 0063 cn Create A Player Codes\Max Techinque 802C5F01 0063 cn Create A Player Codes\Max Capaility 802C5F02 0063 crc 5F25B0EE-6227C1DB-C:45 gn NBA Live 2000 (U) cn Home Team\Infinite Time Outs 811344D0 0700 cn Home Team\No Time Outs 811344D0 0000 cn Away Team\Infinite Time Outs 81135098 0700 cn Away Team\No Time Outs 81135098 0000 cn Infinite Shot Clock 811318F2 05A0 cn Max Inside Scoring 8017B7AC 0064 cn Jump Shooting 8017B7AD 0064 cn Max\3 Pointers 8017B7AE 0064 cn Max\Free Throws 8017B7AF 0064 cn Max\Dunking 8017B7B0 0064 cn Max\Stealing 8017B7B1 0064 cn Max\Blocking 8017B7B2 0064 cn Max\Off. Awareness 8017B7BA 0064 cn Max\Def. Awareness 8017B7B3 0064 cn Max\Quickness 8017B7B4 0064 cn Max\Off. Rebounds 8017B7B5 0064 cn Max\Def. Rebounds 8017B7B6 0064 cn Max\Jumping 8017B7B7 0064 cn Max\Strength 8017B7B8 0064 cn Max\Passing 8017B7B9 0064 cn Max\Speed 8017B7BB 0064 cn Max\Dribbling 8017B7BC 0064 cn Max\Endurance 8017B7BD 0064 cn Max\Shooting Range 8017B7BE 0064 crc 6DFDCDC3-4DE701C8-C:45 gn =NHL Breakaway 98 (U) cn Activate Cheat Menu 80053F38 0001 cn Home Team Goals 8012BBBC ???? 0000:"No Score",00FF:"Max Score" cn Away Team Goals 8012BBBD ???? 0000:"No Score",00FF:"Max Score" crc 82EFDC30-806A2461-C:45 gn NHL Blades Of Steel '99 (U) cn Away Team Scores 50 801F6407 0032 802004C0 0032 cn Home Team Scores 50 801F6406 0032 802004BF 0032 crc 36FA35EB-E85E2E36-C:45 gn NFL Blitz 2001 (U) cn Fire Team 1\Player 1 800EC0CB ???? 0001:"Always On",0000:"Never On" cn Always On Fire Team 2\Player 2 800EC0CF ???? 0001:"Always On",0000:"Never On" cn Infinite Turbo\Player 1 810EC12C 42C8 810EC12E 0000 cn Infinite Turbo\Player 2 81DEC164 42C8 81DEC166 0000 crc 28784622-FFB22985-C:45 gn NFL Quarterback Club 2001 (U) cn Infinite Player Creation Pts 8107A0F2 00C8 cn Always 1st Down 800785D2 0001 cn 1 Down Per Possession 800785D2 0004 crc BE76EDFF-20452D09-C:45 gn NFL Quarterback Club 99 (U) cn Home Team\Infinite Time Outs 8004C0B6 0003 cn Home Team\No Time Outs 8004C0B6 0000 cn Away Team\Infinite Time Outs 8004C62E 0003 cn Away Team\No Time Outs 8004C62E 0000 cn Infinite\Time to Choose Play 81080152 0028 cn Infinite\Character Creation Points 81072F30 015E cn Max\Accuracy 8106FDB8 0064 cn Max\Range 8106FDBA 0064 cn Max\Scramble 8106FDBC 0064 cn Max\Hands 8106FDBE 0064 cn Max\Speed 8106FDC0 0064 cn Max\Catch 8106FDC2 0064 cn Max\Endurance 8106FDC4 0064 crc E3AB4ED0-83040DD2-C:45 gn NFL Quarterback Club 2000 (U) cn Home Team\Infinite Time Outs 80054956 0003 cn Home Team\No Time Outs 80054956 0000 cn Away Team\Infinite Time Outs 80054ED6 0003 cn Away Team\No Time Outs 80054ED6 0000 cn Infinite\Time To Choose Play 81081448 2800 cn Max\Acc 8007526D 0064 cn Max\Cat 8007527B 0063 cn Max\Clu 80075275 0063 cn Max\End 8007527D 0063 cn Max\Hnd 80075279 0063 cn Max\Rcg 80075273 0063 cn Max\Rng 8007526F 0063 cn Max\Scr 80075271 0063 cn Max\Spd 80075277 0063 cn Infinite\Creation Points 8107B36E 03E7 crc 2153143F-992D6351-C:45 gn New Tetris, The (U) cn Press L + C-Down For Cheat Screen D01101B3 0024 8103BFE0 0000 D01101B3 0024 8103BFE2 0000 crc 2857674D-CC4337DA-C:45 gn Nightmare Creatures (U) cn Infinite\Ammo 50000D02 0000 800A4BAF 0009 cn Infinite\Spider Cards 810A4BAE 0009 cn Infinite\Proximity Mines 810A4BB0 0009 cn Infinite\Repulsive Smoke 810A4BB2 0009 cn Infinite\Freeze Spell 810A4BB4 0009 cn Infinite\Dynamite 810A4BB6 0009 cn Infinite\Flash 810A4BB8 0009 cn Infinite\Fire Bombs 810A4BBA 0009 cn Infinite\Multi-Gun 810A4BBC 0009 cn Infinite\Berzerkers 810A4BBE 0009 cn Infinite\Super Healing 810A4BC0 0009 cn Infinite\Healing 810A4BC2 0009 cn Infinite\Chaos 810A4BC4 0009 cn Infinite\Gun 810A4BC6 0009 cn Infinite\Lives 800A4B53 0009 cn Level Select D00978B1 0000 810978B0 ???? 0000:"Chelsea",0001:"Spitafields",0002:"Thames Tunnel",0003:"Sewer Snake",0004:"India Docks",0005:"Highgate Cemetery",0006:"Hampstead Heath",0007:"Queenhite Docks",0008:"City",0009:"Smithfield",000A:"Snowman",000B:"Regent's",000C:"London Zoo",000D:"St. Marilebone",000E:"Bloomsbury",000F:"Pimlico",0010:"Jose Manuel",0011:"Westminister",0012:"Westminister II",0013:"The Roofs",0014:"Map" cn Brightness Modifier 810B96EC ???? 7FFF:"Very Well Lit Up",8000:"Very Dark" cn Ignatius\Infinite Health\Chelsea Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 802EC6E6 0010 cn Ignatius\Infinite Health\Spitafields Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 803215FE 0010 cn Ignatius\Infinite Health\Thames Tunnel Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031AB6E 0010 cn Ignatius\Infinite Health\Sewer Snake Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80255E46 0010 cn Ignatius\Infinite Health\India Docks Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80321546 0010 cn Ignatius\Infinite Health\Highgate Cemetery Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031B2E6 0010 cn Ignatius\Infinite Health\Hampstead Heath Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 803218B6 0010 cn Ignatius\Infinite Health\Queenhite Docks Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80320C1E 0010 cn Ignatius\Infinite Health\City Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80328256 0010 cn Ignatius\Infinite Health\Smithfield Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8030B05E 0010 cn Ignatius\Infinite Health\Snowman Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80251496 0010 cn Ignatius\Infinite Health\Regent's Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80315326 0010 cn Ignatius\Infinite Health\London Zoo Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031E00E 0010 cn Ignatius\Infinite Health\St. Marilebone Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031CD4E 0010 cn Ignatius\Infinite Health\Bloomsbury Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8032C4F6 0010 cn Ignatius\Infinite Health\Pimlico Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031F9CE 0010 cn Ignatius\Infinite Health\Jose Manuel Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8025F196 0010 cn Ignatius\Infinite Health\Westminister Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 802F4ECE 0010 cn Ignatius\Infinite Health\Westminister II Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 802F5DE6 0010 cn Ignatius\Infinite Health\The Roofs Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 802848FE 0010 cn Nadia\Infinite Health\Chelsea Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 802EB6D6 000C cn Nadia\Infinite Health\Spitafield Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80320116 000C cn Nadia\Infinite Health\Thames Tunnel Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80319AC6 000C cn Nadia\Infinite Health\Sewer Snake Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80254926 000C cn Nadia\Infinite Health\India Docks Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 803202CE 000C cn Nadia\Infinite Health\Highgate Cemetary Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031A58E 000C cn Nadia\Infinite Health\Hampstead Heath Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 803203D6 000C cn Nadia\Infinite Health\Queenhite Dock's Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031FB7E 000C cn Nadia\Infinite Health\City Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80326A36 000C cn Nadia\Infinite Health\Smithfield Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8030A0CE 000C cn Nadia\Infinite Health\Snowman Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80250036 000C cn Nadia\Infinite Health\Regent's Canal Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80313E36 000C cn Nadia\Infinite Health\London Zoo Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031CB66 000C cn Nadia\Infinite Health\St. Marilebone Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031B686 000C cn Nadia\Infinite Health\Bloomsbury Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8032B256 000C cn Nadia\Infinite Health\Pimlico Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8031E4B6 000C cn Nadia\Infinite Health\Jose Manuel Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 8025DA0E 000C cn Nadia\Infinite Health\Westminister Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 802F360E 000C cn Nadia\Infinite Health\Westminister II Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 802F4C76 000C cn Nadia\Infinite Health\The Roofs Level cd Only use one Infinite Health cheat at a time or the game will freeze or suffer from sever GFX Errors. 80282DB6 000C crc 4998DDBB-F7B7AEBC-C:45 gn Nuclear Strike 64 (U) cn Infinite\Lives 800A5DF0 0009 cn Play Mission\1 800A5DF1 0000 cn Play Mission\2 800A5DF1 0001 cn Play Mission\3 800A5DF1 0002 cn Play Mission\4 800A5DF1 0003 cn Play Mission\5 800A5DF1 0004 cn Play Mission\6 800A5DF1 0005 cn Invulnerability 800A9730 0001 cn Infinite\Lives 800A5DF0 0009 cn Infinite\Ammo 800A9731 0001 cn Infinite\Attempts 800A9732 0001 cn Infinite\Fuel 800A9733 0001 cn Infinite\Chaingun 800A9737 0001 cn Infinite\Rockets 800A9738 0001 cn Infinite\Missiles 800A9739 0001 cn Infinite\Wingtips 800A973A 0001 cn Wingtips Do Double Damage 800A973B 0001 cn Stealth Mode 800A9734 0001 cn Double MPG 800A9735 0001 cn Quad Damage 800A9736 0001 cn Max Armor Increased 50% 800A973C 0001 cn Agility 800A973D 0001 cn Overhead View 800A973E 0001 cn Level Skip 800A973F 0001 cn Debug Menu 800A9740 0001 cn Auto Win Scenario 800A9741 0001 crc 2655BB70-667D9925-C:45 gn O.D.T (Or Die Trying) (U) (M3) (Unreleased Final) cn Play As Select 800FCD45 ???? 0000:"Ike Hawkings (Corporal)",0001:"Sophia Hawkings (Stowaway)",0002:"Julia Chase (Cartographer)",0003:"Karma (The Ex-Deviant)",0004:"Max Havok (Chief Enginer)",0005:"Solaar (Archbishop)",0006:"Mr Bodybolt (7th Passenger)" cn Infinite Max\999 Lives 810C8B78 03E8 cn Infinite Max\Health 800C8959 0066 cn Infinite Max\Light Ammo 800C8B2B 0066 cn Infinite Max\Fire Ammo 800C8B33 0066 cn Infinite Max\Ionic Ammo 800C8B3B 0066 cn Infinite Max\Fusion Ammo 800C8B43 0066 cn Infinite Max\Mana 800C8B7F 0066 cn Have\All Magic 800CE9C8 0010 800CE9CD 0000 800CE9D7 0001 800CE9E1 0002 800CE9EB 0003 800CE9F5 0005 800CE9FF 0006 800CEA09 0008 800CEA13 0009 800CEA1D 000B 800CEA27 000E 800CEA31 000F 800CEA3B 0010 800CEA45 0011 800CEA4F 000A 800CEA59 000C 800CEA63 000D cn Have\Magic On Level 4 810C8B5D FFFF 810C8B5E FFFF 810C8B5F FFFF 810C8B60 FFFF 810C8B61 FFFF 810C8B62 FFFF cn Have\Weapons On Max Upgrade 50000408 0000 800C8B2C 0009 cn Have\Max Armour Level 800C8B80 0064 cn Have\Max Spirit Level 800C8B84 0064 cn Have\Max Weapon Level 800C8B82 0064 cn Have\Max Experience Level 800C8B7C 00FF cn Infinite Air Under Water 800C8A64 0069 cn Press A For Bionic Jump cd This will make you jump to a great height D00C8A4A 0080 810C8968 ???? 0250:"Medium Jump",0800:"Max Jump" cn Matts D00C8A4A 0080 810C8963 0100 crc 319093EC-0FC209EF-C:45 gn Off Road Challenge (U) cn 1 Player\Always Place 1st 80103C57 0000 cn Multi and 1 Player\Infinite Gent Turbos\Player 1 cd Can be used in 1 Player and Multiplayer Modes for Player 1 81103EBA 02F4 cn 1 Player\Max\Acceleration 8012C49F 000A cn 1 Player\Max\Shocks 8012C4A7 000A cn 1 Player\Max\Speed 8012C4A3 000A cn 1 Player\Max\Tires 8012C4AB 000A cn Multi and 1 Player\Max Crash Helmets\Player 1 cd Can be used in 1 Player and Multiplayer Modes for Player 1 80103EB3 0064 cn Multi and 1 Player\Infinite Gent Turbos\Player 2 cd Multiplayer Mode Only for Player 2 811041AE 02F4 cn Multi and 1 Player\Max Crash Helmets\Player 2 cd Multiplayer Mode Only for Player 2 801041A7 0064 crc E6419BC5-69011DE3-C:45 gn Ogre Battle 64 - Person of Lordly Caliber (U) cn Infinite Goth 81196A6E FFFF cn Max Goth 81196A6C 0098 81196A6E 967F cn Open All Paths 81196A80 01FF 81196A82 677F 81196A84 FCFF cn Finish All Levels 81196A86 5454 81196A88 5140 81196A8A 4555 81196A8C 9514 81196A8E 5515 cn Always Have Retreat & Elem Pedra Opened D01A1C72 0000 811A1C72 0003 cn Hour Always 00 81196A2C 0000 cn Day Always 00 811F106C 0000 cn Magnus\Level 99 80193C0B 0063 cn Magnus\Max HP 81193C0E 03E7 cn Magnus\Infinite HP 81193C10 03E7 cn Magnus\Max Str 81193C14 03E7 cn Magnus\Max Vit 81193C16 03E7 cn Magnus\Max Int 81193C18 03E7 cn Magnus\Max Mem 81193C1A 03E7 cn Magnus\Max Agi 81193C1C 03E7 cn Magnus\Max Dex 81193C1E 03E7 crc 3E198D9E-F2E1267E-C:45 gn Paperboy (U) cn Enable Level Select cd Also accesses All Bonus Levels 8006A5F7 0001 cn Invincibility 812688FE 0001 cn Infinite Newspapers 81268B12 0001 cn Big Newspapers 81268B5A 0001 cn Turbo Mode 81268B36 0001 cn Super Jump Springs 81268B3A 0001 cn Rocket Boosters 81268B3E 0001 cn 99 Total Houses 8106A56A 0063 cn Infinite Health 8006A5D2 0064 crc 65EEE53A-ED7D733C-C:45 gn Paper Mario (U) cn Lots Of Coins 8110F29C 03E7 cn Infinite\HP 8010F292 0063 8010F293 0063 cn Infinite\FP 8010F295 0063 8010F296 0063 cn Have All Spirits 8010F51E 0007 cn Max\Level 8010F299 0063 cn Max\Star Points 8010F2A0 0063 cn Max\Badge Points 8010F298 ???? 003C:"60 Badge Points",007F:"127 Badge Points" cn Max\Star Pieces 8010F29F 0063 cn Have member\Goomario 8010F2AC 0001 cn Have member\Kooper 8010F2B4 0001 cn Have member\Bombette 8010F2BC 0001 cn Have member\Parrakary 8010F2C4 0001 cn Have member\Watt 8010F2D4 0001 cn Have member\Sushie 8010F2DC 0001 cn Have member\Lakitu 8010F2E4 0001 cn Have member\Bow 8010F2EC 0001 cn Upgrade member\Level 1\Goomario cd Do not use with level 2 upgrade cheats 8010F2AD 0001 cn Upgrade member\Level 1\Kooper cd Do not use with level 2 upgrade cheats 8010F2B5 0001 cn Upgrade member\Level 1\Bombette cd Do not use with level 2 upgrade cheats 8010F2BD 0001 cn Upgrade member\Level 1\Parrakary cd Do not use with level 2 upgrade cheats 8010F2C5 0001 cn Upgrade member\Level 1\Watt cd Do not use with level 2 upgrade cheats 8010F2D5 0001 cn Upgrade member\Level 1\Sushie cd Do not use with level 2 upgrade cheats 8010F2DD 0001 cn Upgrade member\Level 1\Lakitu cd Do not use with level 2 upgrade cheats 8010F2E5 0001 cn Upgrade member\Level 1\Bow cd Do not use with level 2 upgrade cheats 8010F2ED 0001 cn Upgrade member\Level 2\Goomario cd Do not use with level 1 upgrade cheats 8010F2AD 0002 cn Upgrade member\Level 2\Kooper cd Do not use with level 1 upgrade cheats 8010F2B5 0002 cn Upgrade member\Level 2\Bombette cd Do not use with level 1 upgrade cheats 8010F2BD 0002 cn Upgrade member\Level 2\Parrakary cd Do not use with level 1 upgrade cheats 8010F2C5 0002 cn Upgrade member\Level 2\Watt cd Do not use with level 1 upgrade cheats 8010F2D5 0002 cn Upgrade member\Level 2\Sushie cd Do not use with level 1 upgrade cheats 8010F2DD 0002 cn Upgrade member\Level 2\Lakitu cd Do not use with level 1 upgrade cheats 8010F2E5 0002 cn Upgrade member\Level 2\Bow cd Do not use with level 1 upgrade cheats 8010F2ED 0002 cn Have hammer\Level 1 cd Do not use with other level hammer cheats 8010F291 0000 cn Have hammer\Level 2 cd Do not use with other level hammer cheats 8010F291 0001 cn Have hammer\Level 3 cd Do not use with other level hammer cheats 8010F291 0002 cn Have jump boots\Level 1 cd Do not use with other level jump boots cheats 8010F290 0000 cn Have jump boots\Level 2 cd Do not use with other level jump boots cheats 8010F290 0001 cn Have jump boots\Level 3 cd Do not use with other level jump boots cheats 8010F290 0002 cn No Star Points (0) cd If emulator hangs at level up, enable this cheat and don't disable it whatsoever! 8010F2A0 0000 cn Infinite\Star Power 8010F520 0007 8010F521 0007 cn Have\Attack item cd Only use One Have item Option at one time. 8110F444 ???? 0800:"Fire Flower",0081:"Snowman Doll",0082:"Thunder Rage",0083:"Shooting Star",0084:"Thunder Bolt",0085:"Pebble",0086:"Dusty Hammer" cn Have\Defense item cd Only use One Have item Option at one time. 8110F444 ???? 0088:"Stone Cap",008A:"Mushroom",008B:"Volt Shroom",0097:"Repel Gel" cn Have\Enemy Stats item cd Only use One Have item Option at one time. 8110F444 ???? 008F:"Sleep Sheep",0090:"POW Block",0092:"Stop Watch",0098:"Fright Jar",009A:"Dizzy Dial" cn Have\Recovery Items Option 1 cd Only use One Have item Option at one time. 8110F444 ???? 0094:"Apple",00B1:"Apple Pie",00C0:"Big Cookie",00BD:"Bland Meal",009E:"Blue Berry",00D8:"Boiled Egg",00A1:"Bubble Berry",00AA:"Cake Mix",00AA:"Cake Mix",00CF:"Coco Pop",00BE:"Deluxe Feast",00A8:"Dried Fruit",00A7:"Dried Pasta",008D:"Dried Shroom",005F:"Egg",00CC:"Electro Pop",00CD:"Fire Pop",00C9:"Fried Egg",00B6:"Fried Shroom",00D4:"Frozen Fries",00A5:"Goomnut",00BC:"Healthy Juice",00CB:"Honey Candy",00CA:"Honey Shroom",00C4:"Honey Super" cn Have\Recovery Items Option 2 cd Only use One Have item Option at one time. 8110F444 ???? 00A4:"Honey Syrup",00B2:"Honey Ultra",00B9:"Hot Shroom",00AF:"Iced Potato",00A2:"Jammin' Jelly",00D1:"Jelly Pop",00DA:"Jelly Shroom",00C6:"Jelly Super",00B4:"Jelly Ultra",00D3:"Kooky Cookie",00A6:"Koopa Leaf",00C3:"Koopa Tea",00B5:"KooPasta",009C:"Lemon",00D0:"Lemon Candy",0095:"Life Shroom",009D:"Lime",0C0E:"Lime Candy",00D7:"Maple Shroom",00C5:"Maple Super",00A3:"Maple Syrup",00B3:"Maple Ultra",00AD:"Melon",00C2:"Mistake",008A:"Mushroom" cn Have\Recovery Items Option 3 cd Only use One Have item Option at one time. 8110F444 ???? 00D6:"Nutty Cake",00D5:"Potato Salad",009F:"Red Berry",00B7:"Shroom Cake",00B8:"Shroom Steak",00C7:"Spaghetti",00BF:"Special Shake",00B0:"Spicy Soup",00AE:"Stinky Herb",00A9:"Strange Leaf",008C:"Super Shroom",009B:"Super Soda",00BA:"Sweet Shroom",0089:"Tasty Tonic",008E:"Ultra Shroom",0093:"Whacka's Bump",00A0:"Yellow Berry",00D9:"Yoshi Cookie",00BB:"Yummy Meal" cn Have\Special Items Options 1 cd Only use One Have item Option at one time 8110F444 ???? 0101:"Jump",010E:"Diploma",010F:"Ultra Stone",0110:"Fortress Key",0115:"Lunar Stone",0118:"Golden Jar",0119:"Kooper's Shell",0122:"Record",0125:"Mystery Note",012A:"Jade Raven",012C:"Magical Seed Purple",012D:"Magical Seed Blue",0131:"Bucket",0150:"Letter",0156:"Dolly",0157:"Water Stone",0158:"Magical Bean",0159:"Fertile Soil",015A:"Miracle Water",015B:"Volcano Vase",0053:"Artifact",0067:"Lyrics",001D:"Boo's Portrait" cn Have\Special Items Option 1 cd Only use One Have item Option at one time. 8110F444 ???? 0030:"Calculator",0029:"Cook Book",001E:"Crystal Berry",0017:"Diamond Stone",0024:"Dictonary",000E:"Diploma",0032:"Scarf",000A:"First Degree Card",000B:"Second Degree Card",000C:"Third Degree Card",000D:"Fourth Degree Card",0023:"Frying Pan",0004:"Hammer",002A:"Jade Raven",0019:"Kooper's Shell,Lunar Stone",0058:"Magical Bean",002B:"Magical Seed Red",002D:"Magical Seed Green",002E:"Magical Seed Brown-Orange",0069:"Mailbag",0031:"Bucket",0021:"Toy Train",0068:"Melody",006C:"Star Stone",005B:"Volcano Vase" crc 73ABB1FB-9CCA6093-C:45 gn Penny Racers (U) cn Super Speed cd This is Turbo fast,So to slow it down a little more keep the B button pressed down 8122AEB8 4800 cn Always 1st 8022AD06 0001 cn Class Select cd This code is useful because you can play Class AA without having to beat a level! 8021E1A7 ???? 0000:"Class C",0001:"Class B",0003:"Class AA",0004:"1 Play",0005:"2 Play",0006:"3 Play",0007:"4 Play" crc DDF460CC-3CA634C0-C:45 gn Perfect Dark (U) (v1.0) cn Have All\Weapons\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80207F10 0007 801EEF10 0007 801D5F10 0007 cn Infinite\Ammo\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8020769F 00FF 801EE69F 00FF 801D569F 00FF 80206EFB 00FF 801EDEFB 00FF 801D4EFB 00FF cn Infinite\Health\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8120677C 3F80 811ED77C 3F80 811D477C 3F80 cn Infinite\Shield\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 81206790 3F80 811E4950 3F80 811CB950 3F80 cn Have All\Weapons\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80209B80 0007 801F0B80 0007 801D7B80 0007 cn Infinite\Ammo\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8020930F 00FF 801F030F 00FF 801D730F 00FF 80208B6B 00FF 801EFB6B 00FF 801D6B6B 00FF cn Infinite\Health\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 812083EC 3F80 811EF3EC 3F80 811D63EC 3F80 cn Infinite\Shield\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 811FF5C0 3F80 811E65C0 3F80 811CD5C0 3F80 cn The Ultimate All In One cd The Ultimate All In One activate's solo missions, give all medals on solo missions, activate cheats, activate cinemas, and who knows what else. I just don't have the time to identify these codes. I know that some of this is creditted to Zap2. I don't have the time to cut those codes out. 800884F3 0001 8008850E 0001 80088575 0001 50000302 0000 80088572 0001 8008858C 0001 8008858D 0001 800885A6 0001 800885A9 0001 800885C0 0001 800885DA 0001 800885DC 0001 800885F4 0001 800885F5 0001 8008860E 0001 80088610 0001 80088612 0001 80088628 0001 50000501 0000 80088642 0001 50000501 0000 8008865C 0001 50000501 0000 80088676 0001 50000501 0000 80088690 0001 50000501 0000 800886AA 0001 50000501 0000 800886C4 0001 50000501 0000 800886DE 0001 50000501 0000 800886F8 0001 50000501 0000 80088712 0001 50000501 0000 8008872C 0001 50000501 0000 80088746 0001 50000501 0000 80088760 0001 50000501 0000 8008877A 0001 50000501 0000 80088794 0001 50000501 0000 800887AE 0001 800A2219 0001 50003E02 0000 800A221D 0001 50000B01 0000 800ACCC9 0001 50000901 0000 800ACCD5 0001 50000401 0000 800ACCDF 0001 50000301 0000 800ACCE4 0001 800ACCE8 0001 800ACCE9 0001 800ACCEB 0001 800ACCEC 0001 50000901 0000 800ACCEE 0001 800ACCF8 0001 50002101 0000 800ACCFA 0001 800ACD12 0001 800ACD15 0001 800ACD16 0001 800ACDEA 0001 800ACD3A 0001 cn Carrington Institute\Have 999 points in Firing Range 810B1E32 03E7 cn Carrington Institute\Have Infinite time in Firing Range 810B1E2E 004D cn Carrington Institute\Have 255 targets destroyed 810B1E34 00FF cn All levels Compleate 50004002 0000 810A2218 0001 cn Single & Co-Op\Press B To Levitate\Player 1 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7E4 0040 81206720 40F2 D009C7E4 0040 802066D3 0000 D009C7E4 0040 811ED720 40F2 D009C7E4 0040 801ED6D3 0000 D009C7E4 0040 811D4720 40F2 D009C7E4 0040 801D46D3 0000 cn Single & Co-Op\Press B To Levitate\Player 2 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7EC 0040 81208390 40F2 D009C7EC 0040 80208343 0000 D009C7EC 0040 811EF390 40F2 D009C7EC 0040 801EF343 0000 D009C7EC 0040 811D6390 40F2 D009C7EC 0040 801D6343 0000 cn Multi\Press B To Levitate\Player 1 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7E4 0040 811BB720 40F2 D009C7E4 0040 801BB6D3 0000 cn Multi\Press B To Levitate\Player 2 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7EC 0040 811BD390 40F2 D009C7EC 0040 801BD343 0000 cn Multi\Press B To Levitate\Player 3 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7F4 0040 811BF000 40F2 D009C7F4 0040 801BEFB3 0000 cn Multi\Press B To Levitate\Player 4 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7FC 0040 811C0C70 40F2 D009C7FC 0040 801C0C23 0000 crc 41F2B98F-B458B466-C:45 gn Perfect Dark (U) (v1.1) cn Have All\Weapons\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80207F10 0007 801EEF10 0007 801D5F10 0007 cn Infinite\Ammo\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8020769F 00FF 801EE69F 00FF 801D569F 00FF 80206EFB 00FF 801EDEFB 00FF 801D4EFB 00FF cn Infinite\Health\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8120677C 3F80 811ED77C 3F80 811D477C 3F80 cn Infinite\Shield\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 81206790 3F80 811E4950 3F80 811CB950 3F80 cn Have All\Weapons\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80209B80 0007 801F0B80 0007 801D7B80 0007 cn Infinite\Ammo\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8020930F 00FF 801F030F 00FF 801D730F 00FF 80208B6B 00FF 801EFB6B 00FF 801D6B6B 00FF cn Infinite\Health\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 812083EC 3F80 811EF3EC 3F80 811D63EC 3F80 cn Infinite\Shield\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 811FF5C0 3F80 811E65C0 3F80 811CD5C0 3F80 cn The Ultimate All In One cd The Ultimate All In One activate's solo missions, give all medals on solo missions, activate cheats, activate cinemas, and who knows what else. I just don't have the time to identify these codes. I know that some of this is creditted to Zap2. I don't have the time to cut those codes out. 800884F3 0001 8008850E 0001 80088575 0001 50000302 0000 80088572 0001 8008858C 0001 8008858D 0001 800885A6 0001 800885A9 0001 800885C0 0001 800885DA 0001 800885DC 0001 800885F4 0001 800885F5 0001 8008860E 0001 80088610 0001 80088612 0001 80088628 0001 50000501 0000 80088642 0001 50000501 0000 8008865C 0001 50000501 0000 80088676 0001 50000501 0000 80088690 0001 50000501 0000 800886AA 0001 50000501 0000 800886C4 0001 50000501 0000 800886DE 0001 50000501 0000 800886F8 0001 50000501 0000 80088712 0001 50000501 0000 8008872C 0001 50000501 0000 80088746 0001 50000501 0000 80088760 0001 50000501 0000 8008877A 0001 50000501 0000 80088794 0001 50000501 0000 800887AE 0001 800A2219 0001 50003E02 0000 800A221D 0001 50000B01 0000 800ACCC9 0001 50000901 0000 800ACCD5 0001 50000401 0000 800ACCDF 0001 50000301 0000 800ACCE4 0001 800ACCE8 0001 800ACCE9 0001 800ACCEB 0001 800ACCEC 0001 50000901 0000 800ACCEE 0001 800ACCF8 0001 50002101 0000 800ACCFA 0001 800ACD12 0001 800ACD15 0001 800ACD16 0001 800ACDEA 0001 800ACD3A 0001 cn Carrington Institute\Have 999 points in Firing Range 810B1E32 03E7 cn Carrington Institute\Have Infinite time in Firing Range 810B1E2E 004D cn Carrington Institute\Have 255 targets destroyed 810B1E34 00FF cn Single & Co-Op\Press B To Levitate\Player 1 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7E4 0040 81206720 40F2 D009C7E4 0040 802066D3 0000 D009C7E4 0040 811ED720 40F2 D009C7E4 0040 801ED6D3 0000 D009C7E4 0040 811D4720 40F2 D009C7E4 0040 801D46D3 0000 cn Single & Co-Op\Press B To Levitate\Player 2 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7EC 0040 81208390 40F2 D009C7EC 0040 80208343 0000 D009C7EC 0040 811EF390 40F2 D009C7EC 0040 801EF343 0000 D009C7EC 0040 811D6390 40F2 D009C7EC 0040 801D6343 0000 cn Multi\Press B To Levitate\Player 1 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7E4 0040 811BB720 40F2 D009C7E4 0040 801BB6D3 0000 cn Multi\Press B To Levitate\Player 2 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7EC 0040 811BD390 40F2 D009C7EC 0040 801BD343 0000 cn Multi\Press B To Levitate\Player 3 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7F4 0040 811BF000 40F2 D009C7F4 0040 801BEFB3 0000 cn Multi\Press B To Levitate\Player 4 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D009C7FC 0040 811C0C70 40F2 D009C7FC 0040 801C0C23 0000 crc B54CE881-BCCB6126-C:45 gn PGA European Tour (U) cn Hole In One\Hole 01 800FF713 0000 cn Hole In One\Hole 02 800FF715 0000 cn Hole In One\Hole 03 800FF717 0000 cn Hole In One\Hole 04 800FF719 0000 cn Hole In One\Hole 05 800FF71B 0000 cn Hole In One\Hole 06 800FF71D 0000 cn Hole In One\Hole 07 800FF71F 0000 cn Hole In One\Hole 08 800FF721 0000 cn Hole In One\Hole 09 800FF723 0000 cn Hole In One\Hole 10 800FF725 0000 cn Hole In One\Hole 11 800FF727 0000 cn Hole In One\Hole 12 800FF729 0000 cn Hole In One\Hole 13 800FF72B 0000 cn Hole In One\Hole 14 800FF72D 0000 cn Hole In One\Hole 15 800FF72F 0000 cn Hole In One\Hole 16 800FF731 0000 cn Hole In One\Hole 17 800FF733 0000 cn Hole In One\Hole 18 800FF735 0000 crc C851961C-78FCAAFA-C:45 gn Pilot Wings64 (U) cn Infinite Fuel\Gyrocopter 80362821 0081 cn Infinite Fuel\Rocket Belt 80362841 0081 cn Time Always 00'00'10 cd This Cheat code is for All Events 80362750 0001 cn Choose Vehicle cd Make your Choice & then Press GS To Activate,But do not use with any other Press GS Cheat Codes. 883626A7 ???? 0000:"Hang Glider",0001:"Rocket Belt",0002:"Gyrocopter",0003:"Cannonball",0004:"Skydiving",0005:"Jumble Hopper",0006:"Birdman" cn Fly As Yellow Plane In USA Level cd Press GS To Activate,But do not use with any other Press GS Cheat Codes. 89362748 0009 813627B0 3EE0 8024CDF5 006E cn Fly As Gray Plane In USA Level cd Press GS To Activate,But do not use with any other Press GS Cheat Codes. 89362748 0008 813627B0 3F30 8024CDF5 006E cn Have Perfect Score in all Class & Level's cd With these codes, if you want them to save, you have to play a level, and lose and just choose quit after it tallies up your score. Also dont keep the code active once you save the level at 100%, turn the code off and continue with the other levels! 8036427D 0064 803642AD 0064 803642DD 0064 80364911 0064 80364A61 0064 80364941 0064 80364A91 0064 80364971 0064 80364AC1 0064 80364FA5 0064 803650F5 0064 80365245 0064 80364FD5 0064 80365125 0064 80365275 0064 80365005 0064 80365155 0064 803652A5 0064 80365639 0064 80365789 0064 803658D9 0064 80365669 0064 803657B9 0064 80365909 0064 80365699 0064 803657E9 0064 80365939 0064 8036430D 0019 8036445D 0019 803645AD 0019 803646FD 0019 8036433D 0064 8036436D 0064 803649A1 0019 80364AF1 0019 80364C41 0019 80364D91 0019 803649D1 0064 80364A01 0064 80365035 0019 80365185 0019 803652D5 0019 80365425 0019 80365065 0064 80365095 0064 crc CA12B547-71FA4EE4-C:45 gn Pokemon Snap (U) cn Press L\To Stop On Tunnel Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801DDC55 0001 cn Press L\To Stop On Volcano Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801FC5C5 0001 cn Press L\To Stop On River Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801EF96D 0001 cn Press L\To Stop On Cave Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 80202225 0001 cn Press L\To Stop On Beach Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 802020F5 0001 cn Press L\To Stop On Valley Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801D9ABD 0001 cn Have\Rapid Fire Apples and Bombs 80382CB7 0000 cn Have\Apples Bombs and Flute 803AE51F 0004 cn Have\Apple & Bomb 803AE51F 0002 cn Have\Apple 803AE51F 0001 cn [Enable All Levels] 810C2212 0006 cn Hide First Digit In Roll Of Film 80388F5A 009D cn See Entire Introduction Fully & Various In-Game Effects 81049C7E 025A crc 39119872-07722E9F-C:45 gn Pokemon Snap Station (U) cn Press L\To Stop On Tunnel Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801DDC55 0001 cn Press L\To Stop On Volcano Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801FC5C5 0001 cn Press L\To Stop On River Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801EF96D 0001 cn Press L\To Stop On Cave Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 80202225 0001 cn Press L\To Stop On Beach Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 802020F5 0001 cn Press L\To Stop On Valley Level cd To Activated thos Cheat Code, Press L To Stop & Press Start to Continue Again. D00489E1 0020 801D9ABD 0001 cn Have\Rapid Fire Apples and Bombs 80382CB7 0000 cn Have\Apples Bombs and Flute 803AE51F 0004 cn Have\Apple & Bomb 803AE51F 0002 cn Have\Apple 803AE51F 0001 cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C2212 0006 cn Hide First Digit In Roll Of Film 80388F5A 009D cn See Entire Introduction Fully & Various In-Game Effects 81049C7E 025A crc 90F5D9B3-9D0EDCF0-C:45 gn Pokemon Stadium (U) cn Pokemon\Max HP\Player 1 810AE586 03E7 810AE5DA 03E7 810AE62E 03E7 cn Pokemon\Max HP\Player 2 810AE7A2 03E7 810AE7F6 03E7 810AE84A 03E7 cn Pokemon\Inf Spells\Player 1 810AE580 FFFF 810AE582 FFFF 810AE5D4 FFFF 810AE5D6 FFFF 810AE628 FFFF 810AE62A FFFF cn Pokemon\Inf Spells\Player 2 810AE79C FFFF 810AE79E FFFF 810AE7F0 FFFF 810AE7F2 FFFF 810AE844 FFFF 810AE846 FFFF cn Have All Pikachus Magnemites 801183BC 0000 801183BD 0000 801183BE 0000 cn Inf HP\In Battle All Pokemon\Player 1 81285A18 03E7 cn Inf HP\In Battle All Pokemon\Player 2 81286438 03E7 cn Ultimate Code cd what's so ultimate about this code is it raises your Pokemon to its full potential. Even at Level 100, most Pokemon still have a way to go to raise their stats to the max. But with this code, you can instantly boost any Pokemon to its greatest potential!!! 81171F3C FF01 81171F3E FF01 81171F40 FF01 81171F42 FF01 81171F44 FF01 crc 03571182-892FD06D-C:45 gn Pokemon Stadium 2 (U) cn One Hit KO cd To Win you must get at least one hit or just return your pokemon. 8014576F 0000 801457C7 0000 8014581F 0000 cn Press R To Reset Time cd Press R To Reset Time 801CE066 0010 81183ACC 0063 cn Max Score D117F812 03E7 8117F812 03E7 cn Press R+L to KO Opponents cd Press R+L Activate D10CE066 0030 80145767 0000 D10CE066 0030 801457C7 0000 D10CE066 0030 8014576F 0000 D10CE066 0030 8014581F 0000 cn Infinite\Continues 8114738C 0009 cn Instant\Win\Topsy Turvy\Player 1 80176887 0005 cn Instant\Win\Barrier Ball\Player 1 8016EA97 0005 cn Instant\Win\Pichu's Power Plant\Player 1 8016D64F 0050 cn Infinite\Dirt Rollout Rampage\Player 1 8017DFEB 0002 cn Press Z\for Max HP\1st Pokemon cd This will give them Max HP when they are not in use. Just call a Pokemon out and he will then have Max HP. When your Pokemon faints, just press Z again and it will revive itIn Battle Only,Do not use with anyother Press Z Cheat Code. D112B554 2000 8114528E 00FF D112B554 2000 81145290 00FF cn Press Z\for Max L.\1st Pokemon\Player 1 cd Do not use with anyother Press Z Cheat Code. D112B554 2000 81145284 0063 cn Press Z\for Max HP\2nd Pokemon\Player 1 cd This will give them Max HP when they are not in use. Just call a Pokemon out and he will then have Max HP. When your Pokemon faints, just press Z again and it will revive itIn Battle Only,Do not use with anyother Press Z Cheat Code. D112B554 2000 811452E6 00FF D112B554 2000 811452E8 00FF cn Press Z\for Max L.\2nd Pokemon\Player 1 cd Do not use with anyother Press Z Cheat Code. D112B554 2000 811452DC 0063 cn Press Z\for Max HP\3rd Pokemon\Player 1 cd This will give them Max HP when they are not in use. Just call a Pokemon out and he will then have Max HP. When your Pokemon faints, just press Z again and it will revive itIn Battle Only,Do not use with anyother Press Z Cheat Code. D112B554 2000 8114533E 00FF D112B554 2000 81145340 00FF cn Press Z\for Max L.\3rd Pokemon\Player 1 cd Do not use with anyother Press Z Cheat Code. D112B554 2000 81145334 0063 crc CF8957AD-96D57EA9-C:45 gn Power Rangers - Lightspeed Rescue (U) cn Unlock All\Characters 50000C01 0000 8006252D 0001 cn Infinite\Health cd For Overhead & Driving Levels 81064DF0 42C8 cn Unlock All\Levels 50000301 0000 80062508 0001 50000801 0000 8006250C 0001 50000801 0000 80062516 0001 50000A01 0000 8006251F 0001 crc FC74D475-9A0278AB-C:45 gn Powerpuff Girls, The - Chemical X-traction (U) cn 1 Win Needed\Player 1 D00BAD0F 0000 800BAD0F 0001 cn Infinite Health\Player 1 810BACDC 42C8 cn Max Chemical X\Player 1 800BAD28 0003 cn Never Win\Player 1 800BAD0F 0000 cn No Chemical X\Player 1 800BAD28 0000 cn No Health\Player 1 810BACDC 0000 cn 1 Win Needed\Player 2 D00BB04F 0000 800BB04F 0001 cn Infinite Health\Player 2 810BB01C 42C8 cn Max Chemical X\Player 2 800BB068 0003 cn Never Win\Player 2 800BB04F 0000 cn No Chemical X\Player 2 800BB068 0000 cn No Health\Player 2 810BB01C 0000 cn Infinite Time 810E69AC 42F0 crc 9F5BF79C-D2FE08A0-C:45 gn Quake cn Infinite\Ammo 50000402 0000 80163A2D 0064 50000402 0000 81163A2C 03E7 cn Have\All Weapons 801639EB 007F cn Debug Mode 8006C4C2 0001 cn Have\All Keys 801639E9 000F cn Infinite\Armor 81163944 42C8 cn Infinite\Health 81163930 42C8 cn Infinite\Bio Suit 81163980 42C8 cn Have\Quad Damage 8116397C 42C8 cn Have\Ring of Shadows 811639E8 ???? 42C8:"On",0000:"Off" cn Rapid Fire D00CA9E0 0020 8016396D 0001 cn Multi\Infinite Health\Player 1 81166290 42C8 cn Multi\Infinite Armor\Player 1 811662A4 42C8 cn Multi\Infinite Bio Suit\Player 1 811662E0 42C8 cn Multi\Have All Weapons\Player 1 8016634B 007F cn Multi\Infinite Ammo\Player 1 50000402 0000 8116638C 03E7 cn Multi\Infinite Health\Player 2 81166560 42C8 cn Multi\Infinite Armor\Player 2 81166574 42C8 cn Multi\Infinite Bio Suit\Player 2 811665B0 42C8 cn Multi\Have All Weapons\Player 2 8016661B 007F cn Multi\Infinite Ammo\Player 2 50000402 0000 8116665C 03E7 crc BDA8F143-B1AF2D62-C:45 gn QUAKE II cn The Ultimate cd The Ultimate Gives you on Solo Play Infinite Health, Infinite Armor, All Guns, and Infinite Ammo On all Levels 8104AD2C 0800 8104AD2E 0018 81000060 8E30 81000062 0068 81000064 241B 81000066 03E7 81000068 AE1B 8100006A 0030 8100006C AC9B 8100006E 0204 81000070 A219 81000072 004B 81000074 A219 81000076 004C 81000078 1000 8100007A 0005 8100007C A219 8100007E 0050 50000604 0000 81000090 A219 50000604 0004 81000092 0054 50000504 0000 810000A8 AE1B 50000504 0004 810000AA 006C 810000BC 0801 810000BE 2B4D 810000C0 AE1B 810000C2 0080 cn Multi\Agony\Have\All Weapons\Player 1 801832B7 0001 801832BB 0001 801832BF 0001 801832C3 0001 801832C7 0001 801832CB 0001 801832CF 0001 801832D3 0001 801832D7 0001 801832DB 0001 cn Multi\Agony\Infinite\Ammo\Player 1 801832DF 0063 801832E3 0063 801832E7 0063 801832EB 0063 801832EF 0063 801832F3 0063 cn Multi\Agony\Have\All Weapons\Player 2 8018361B 0001 8018361F 0001 80183623 0001 80183627 0001 8018362B 0001 8018362F 0001 80183633 0001 80183637 0001 8018363B 0001 8018363F 0001 cn Multi\Agony\Infinite\Ammo\Player 2 80183643 0063 80183647 0063 8018364B 0063 8018364F 0063 80183653 0063 80183657 0063 cn Multi\Cold Steel\Have\All Weapons\Player 1 8017B577 0001 8017B57B 0001 8017B57F 0001 8017B583 0001 8017B587 0001 8017B58B 0001 8017B58F 0001 8017B593 0001 8017B597 0001 8017B59B 0001 cn Multi\Cold Steel\Infinite\Ammo\Player 1 8017B59F 0063 8017B5A3 0063 8017B5A7 0063 8017B5AB 0063 8017B5AF 0063 8017B5B3 0063 cn Multi\Cold Steel\Have\All Weapons\Player 2 8017B8DB 0001 8017B8DF 0001 8017B8E3 0001 8017B8E7 0001 8017B8EB 0001 8017B8EF 0001 8017B8F3 0001 8017B8F7 0001 8017B8FB 0001 8017B8FF 0001 cn Multi\Cold Steel\Infinite\Ammo\Player 2 8017B903 0063 8017B907 0063 8017B90B 0063 8017B90F 0063 8017B913 0063 8017B917 0063 cn Multi\Corridors\Have\All Weapons\Player 1 8017D1C7 0001 8017D1CB 0001 8017D1CF 0001 8017D1D3 0001 8017D1D7 0001 8017D1DB 0001 8017D1DF 0001 8017D1E3 0001 8017D1E7 0001 8017D1EB 0001 cn Multi\Corridors\Infinite\Ammo\Player 1 8017D1E7 0063 8017D1F3 0063 8017D1F7 0063 8017D1FB 0063 8017D1FF 0063 8017D203 0063 cn Multi\Corridors\Have\All Weapons\Player 2 8017D52B 0001 8017D52F 0001 8017D533 0001 8017D537 0001 8017D53B 0001 8017D53F 0001 8017D543 0001 8017D547 0001 8017D54B 0001 8017D54F 0001 cn Multi\Corridors\Infinite\Ammo\Player 2 8017D553 0063 8017D557 0063 8017D55B 0063 8017D55F 0063 8017D567 0063 cn Multi\Dying Halls\Have\All Weapons\Player 1 801BF937 0001 801BF93B 0001 801BF93F 0001 801BF943 0001 801BF947 0001 801BF94B 0001 801BF94F 0001 801BF953 0001 801BF957 0001 801BF95B 0001 cn Multi\Dying Halls\Infinite\Ammo\Player 1 801BF95F 0063 801BF963 0063 801BF967 0063 801BF96B 0063 801BF96F 0063 801BF973 0063 cn Multi\Dying Halls\Have\All Weapons\Player 2 801BFC9B 0001 801BFC9F 0001 801BFCA3 0001 801BFCA7 0001 801BFCAB 0001 801BFCAF 0001 801BFCB3 0001 801BFCB7 0001 801BFCBB 0001 801BFCBF 0001 cn Multi\Dying Halls\Infinite\Ammo\Player 2 801BFCC3 0063 801BFCC7 0063 801BFCCB 0063 801BFCCF 0063 801BFCD3 0063 801BFCD7 0063 cn Multi\Empty Space\Have\All Weapons\Player 1 80179B27 0001 80179B2B 0001 80179B2F 0001 80179B33 0001 80179B37 0001 80179B3B 0001 80179B3F 0001 80179B43 0001 80179B47 0001 80179B4B 0001 cn Multi\Empty Space\Infinite\Ammo\Player 1 80179B4F 0063 80179B53 0063 80179B57 0063 80179B5B 0063 80179B5F 0063 80179B63 0063 cn Multi\Empty Space\Have\All Weapons\Player 2 80179E8B 0001 80179E8F 0001 80179E93 0001 80179E97 0001 80179E9B 0001 80179E9F 0001 80179EA3 0001 80179EA7 0001 80179EAB 0001 80179EAF 0001 cn Multi\Empty Space\Infinite\Ammo\Player 2 80179EB3 0063 80179EB7 0063 80179EBB 0063 80179EBF 0063 80179EC3 0063 80179EC7 0063 cn Multi\Fortress\Have\All Weapons\Player 1 8017D617 0001 8017D61B 0001 8017D61F 0001 8017D623 0001 8017D627 0001 8017D62B 0001 8017D62F 0001 8017D633 0001 8017D637 0001 8017D63B 0001 cn Multi\Fortress\Infinite\Ammo\Player 1 8017D63F 0063 8017D643 0063 8017D647 0063 8017D64B 0063 8017D64F 0063 8017D653 0063 cn Multi\Fortress\Have\All Weapons\Player 2 8017D97B 0001 8017D97F 0001 8017D983 0001 8017D987 0001 8017D98B 0001 8017D98F 0001 8017D993 0001 8017D997 0001 8017D99B 0001 8017D99F 0001 cn Multi\Fortress\Infinite\Ammo\Player 2 8017D9A3 0063 8017D9A7 0063 8017D9AB 0063 8017D9AF 0063 8017D9B3 0063 8017D9B7 0063 cn Multi\Mad Dash\Have\All Weapons\Player 1 801AE9A7 0001 801AE9AB 0001 801AE9AF 0001 801AE9B3 0001 801AE9B7 0001 801AE9BB 0001 801AE9BF 0001 801AE9C3 0001 801AE9C7 0001 801AE9CB 0001 cn Multi\Mad Dash\Infinite\Ammo\Player 1 801AE9CF 0063 801AE9D3 0063 801AE9D7 0063 801AE9DB 0063 801AE9DF 0063 801AE9E3 0063 cn Multi\Mad Dash\Have\All Weapons\Player 2 801AED0B 0001 801AED0F 0001 801AED13 0001 801AED17 0001 801AED1B 0001 801AED1F 0001 801AED23 0001 801AED27 0001 801AED2B 0001 801AED2F 0001 cn Multi\Mad Dash\Infinite\Ammo\Player 2 801AED33 0063 801AED37 0063 801AED3B 0063 801AED3F 0063 801AED43 0063 801AED47 0063 cn Multi\Overflow\Have\All Weapons\Player 1 80197907 0001 8019790B 0001 8019790F 0001 80197913 0001 80197917 0001 8019791B 0001 8019791F 0001 80197923 0001 80197927 0001 8019792B 0001 cn Multi\Overflow\Infinite\Ammo\Player 1 8019792F 0063 80197933 0063 80197937 0063 8019793B 0063 8019793F 0063 80197943 0063 cn Multi\Overflow\Have\All Weapons\Player 2 80197C6B 0001 80197C6F 0001 80197C73 0001 80197C77 0001 80197C7B 0001 80197C7F 0001 80197C83 0001 80197C87 0001 80197C8B 0001 80197C8F 0001 cn Multi\Overflow\Infinite\Ammo\Player 2 80197C93 0063 80197C97 0063 80197C9B 0063 80197C9F 0063 80197CA3 0063 80197CA7 0063 cn Multi\Twists\Have\All Weapons\Player 1 801ABE47 0001 801ABE4B 0001 801ABE4F 0001 801ABE53 0001 801ABE57 0001 801ABE5B 0001 801ABE5F 0001 801ABE63 0001 801ABE67 0001 801ABE6B 0001 cn Multi\Twists\Infinite\Ammo\Player 1 801ABE6F 0063 801ABE73 0063 801ABE77 0063 801ABE7B 0063 801ABE7F 0063 801ABE83 0063 cn Multi\Twists\Have\All Weapons\Player 2 801AC1AB 0001 801AC1AF 0001 801AC1B3 0001 801AC1B7 0001 801AC1BB 0001 801AC1BF 0001 801AC1C3 0001 801AC1C7 0001 801AC1CB 0001 801AC1CF 0001 cn Multi\Twists\Infinite\Ammo\Player 2 801AC1D3 0063 801AC1D7 0063 801AC1DB 0063 801AC1DF 0063 801AC1E3 0063 801AC1E7 0063 cn Multi\War Room\Have\All Weapons\Player 1 801A2E57 0001 801A2E5B 0001 801A2E5F 0001 801A2E63 0001 801A2E67 0001 801A2E6B 0001 801A2E6F 0001 801A2E73 0001 801A2E77 0001 801A2E7B 0001 cn Multi\War Room\Infinite\Ammo\Player 1 801A2E7F 0063 801A2E83 0063 801A2E87 0063 801A2E8B 0063 801A2E8F 0063 801A2E93 0063 cn Multi\War Room\Have\All Weapons\Player 2 801A31BB 0001 801A31BF 0001 801A31C3 0001 801A31C7 0001 801A31CB 0001 801A31CF 0001 801A31D3 0001 801A31D7 0001 801A31DB 0001 801A31DF 0001 cn Multi\War Room\Infinite\Ammo\Player 2 801A31E3 0063 801A31E7 0063 801A31EB 0063 801A31EF 0063 801A31F3 0063 801A31F7 0063 crc C8BB4DD9-CC5F430B-C:45 gn Quest 64 (U) cn Have All Elements 8107BAA4 3232 8107BAA6 3232 cn Infinite Health 8107BA84 01F4 8107BA86 01F4 cn Infinite Magic Points 8107BA88 01F4 8107BA8A 01F4 cn Super Agility 8107BA8E 01F4 cn Super Defense 8107BA8C 01F4 crc 73A88E3D-3AC5C571-C:45 gn Rally Challenge 2000 (U) cn Infinite Time 81104998 49F2 cn Arcade Mode\Car Modifier 802818B3 ???? 0000:"Mitsubishi Lancer Evolution V",0001:"Subaru Impreza WRC",0002:"Toyota Corolla WRC",0003:"Nissan Almera Kit Car",0004:"Seat Cordoba WRC",0005:"Skoda Octavia",0006:"VW Golf GTI MK IV",0007:"Proton WIRA",0008:"Hyundai Coupe EVO 2" cn Easy Courses\Australia\Have 1st 80178F87 0000 cn Easy Courses\Australia\Always Low Lap Timer 81178F90 0000 81178F92 0000 cn Easy Courses\Spain\Have 1st 801870D7 0000 cn Easy Courses\Spain\Always Low Lap Timer 811870E0 0000 811870E2 0000 cn Easy Courses\Great Britian\Have 1st 801766A7 0000 cn Easy Courses\Great Britian\Always Low Lap Timer 811766B0 0000 811766B2 0000 cn Medium Courses\Italy\Have 1st 8017E4E7 0000 cn Medium Courses\Italy\Always Low Lap Timer 8117E4D0 0000 8117E4D2 0000 cn Medium Courses\Brazil\Have 1st 801748C7 0000 cn Medium Courses\Brazil\Always Low Lap Timer 811748D0 0000 811748D2 0000 cn Medium Courses\France\Have 1st 80172477 0000 cn Medium Courses\France\Always Low Lap Timer 81172480 0000 81172482 0000 cn Expert Courses\Germany\Have 1st 8017DF87 0000 cn Expert Courses\Germany\Always Low Lap Timer 8117DF90 0000 8117DF92 0000 cn Expert Courses\Canada\Have 1st 8017CF87 0000 cn Expert Courses\Canada\Always Low Lap Timer 8117CF90 0000 8117CF92 0000 cn Expert Courses\USA\Have 1st 8017EF87 0000 cn Expert Courses\USA\Always Low Lap Timer 8117EF90 0000 8117EF92 0000 cn Championship Mode\Have 255 Race Points 80101D1A 00FF cn Championship Mode\Australia\Start On 3rd Lap D0178F6F 0001 80178F6F 0003 cn Championship Mode\Australia\Infinite Damage\Front End 80178FA0 003E cn Championship Mode\Australia\Infinite Damage\Left Side 80178FA4 0040 cn Championship Mode\Australia\Infinite Damage\Right Side 80178FA8 0040 cn Championship Mode\Australia\Infinite Damage\Tires 80178FAC 0040 cn Championship Mode\Spain\Start On 3rd Lap D01870BF 0001 801870BF 0003 cn Championship Mode\Spain\Infinite Damage\Front End 801870F0 0040 cn Championship Mode\Spain\Infinite Damage\Left Side 801870F4 0040 cn Championship Mode\Spain\Infinite Damage\Right Side 801870F8 0040 cn Championship Mode\Spain\Infinite Damage\Tires 801870FC 0040 cn Championship Mode\Brazil\Start On 3rd Lap D01748AF 0001 801748AF 0003 cn Championship Mode\Brazil\Infinite Damage\Front End 801748E0 0040 cn Championship Mode\Brazil\Infinite Damage\Left Side 801748E4 0040 cn Championship Mode\Brazil\Infinite Damage\Right Side 801748E8 0040 cn Championship Mode\Brazil\Infinite Damage\Tires 801748EC 0040 cn Championship Mode\USA\Start On 3rd Lap D017EF6F 0001 8017EF6F 0003 cn Championship Mode\USA\Infinite Damage\Front End 8017EFA0 0040 cn Championship Mode\USA\Infinite Damage\Left Side 8017EFA4 0040 cn Championship Mode\USA\Infinite Damage\Right Side 8017EFA8 0040 cn Championship Mode\USA\Infinite Damage\Tires 8017EFAC 0040 cn Championship Mode\Italy\Start On 3rd Lap D017E4CF 0001 8017E4CF 0003 cn Championship Mode\Italy\Infinite Damage\Front End 8017E500 0040 cn Championship Mode\Italy\Infinite Damage\Left Side 8017E504 0040 cn Championship Mode\Italy\Infinite Damage\Right Side 8017E508 0040 cn Championship Mode\Italy\Infinite Damage\Tires 8017E50C 0040 cn Championship Mode\Germany\Start On 3rd Lap D017DF6F 0001 8017DF6F 0003 cn Championship Mode\Germany\Infinite Damage\Front End 8017DFA0 0040 cn Championship Mode\Germany\Infinite Damage\Left Side 8017DFA4 0040 cn Championship Mode\Germany\Infinite Damage\Right Side 8017DFA8 0040 cn Championship Mode\Germany\Infinite Damage\Tires 8017DFAC 0040 cn Championship Mode\Canada\Start On 3rd Lap D017CF6F 0001 8017CF6F 0003 cn Championship Mode\Canada\Infinite Damage\Front End 8017CFA0 0040 cn Championship Mode\Canada\Infinite Damage\Left Side 8017CFA4 0040 cn Championship Mode\Canada\Infinite Damage\Right Side 8017CFA8 0040 cn Championship Mode\Canada\Infinite Damage\Tires 8017CFAC 0040 cn Championship Mode\Great Britain\Start On 3rd Lap D017668F 0001 8017668F 0003 cn Championship Mode\Great Britain\Infinite Damage\Front End 801766C0 0040 cn Championship Mode\Great Britain\Infinite Damage\Left Side 801766C4 0040 cn Championship Mode\Great Britain\Infinite Damage\Right Side 801766C8 0040 cn Championship Mode\Great Britain\Infinite Damage\Tires 801766CC 0040 cn Championship Mode\France\Start On 3rd Lap D017245F 0001 8017245F 0003 cn Championship Mode\France\Infinite Damage\Front End 80172490 0040 cn Championship Mode\France\Infinite Damage\Left Side 80172494 0040 cn Championship Mode\France\Infinite Damage\Right Side 80172498 0040 cn Championship Mode\France\Infinite Damage\Tires 8017249C 0040 crc C29FF9E4-264BFE7D-C:45 gn Rampage - World Tour (U) cn Unlock Cheat Menu 810D5710 0001 cn Infinite Time to Choose A Character 8118CF9A 06CB cn Curtis\Infinite\Health 811541B8 0044 cn Curtis\1-Hit Death D01541B9 0044 811541B8 0001 cn Curtis\Infinite\Special 811541C0 0044 cn Curtis\Max Score 811541E8 000F 811541EA 423F cn Curtis\Infinite\Lives 811541B4 0063 cn Boris\Infinite\Health 811543D4 0044 cn Boris\1-Hit Death D01543D5 0044 811543D4 0001 cn Boris\Infinite\Special 811543DC 0044 cn Boris\Max Score 81154404 000F 81154406 423F cn Boris\Infinite\Lives 811543D0 0063 cn Ruby\Infinite\Health 811545F0 0044 cn Ruby\1-Hit Death D01545F1 0044 811545F0 0001 cn Ruby\Infinite\Special 811545F8 0044 cn Ruby\Max Score 81154620 000F 81154622 423F cn Ruby\Infinite\Lives 811545EC 0063 cn George\Infinite\Health 8115480C 0044 cn George\1-Hit Death D015480D 0044 8115480C 0001 cn George\Infinite\Special 81154814 0044 cn George\Max Score 8115483C 000F 8115483E 423F cn George\Infinite\Lives 81154808 0063 cn Lizzie\Infinite\Health 81154A28 0044 cn Lizzie\1-Hit Death D0154A29 0044 81154A28 0001 cn Lizzie\Infinite\Special 81154A30 0044 cn Lizzie\Max Score 81154A58 000F 81154A5A 423F cn Lizzie\Infinite\Lives 81154A24 0063 cn Ralph\Infinite\Health 81154C44 0044 cn Ralph\1-Hit Death D0154C45 0044 81154C44 0001 cn Ralph\Infinite\Special 81154C4C 0044 cn Ralph\Max Score 81154C74 000F 81154C76 423F cn Ralph\Infinite\Lives 81154C40 0063 cn Myukus Codes\Infinite\Health 81154E60 0044 cn Myukus Codes\1-Hit Death D0154E61 0044 81154E60 0001 cn Myukus Codes\Infinite\Special 81154E68 0044 cn Myukus Codes\Max Score 81154E90 000F 81154E92 423F cn Myukus Codes\Infinite\Lives 81154E5C 0063 crc 673D099B-A4C808DE-C:45 gn Rampage 2: Universal Tour (U) cn Always Full Special\Myukus 81554E68 0044 cn Always Full Special\Ralph 81154C4C 0044 cn Enable\Myukus 8118CF98 0000 cn Infinite\Health\Myukus 81154E60 0044 cn Infinite\Lives\Myukus 81154EFC 0063 cn Infinite\Lives\Ruby 811545EC 0063 cn Enable\Lizzie 8118CF94 0000 cn Enable\Ralph 8118CF96 0000 cn Infinite Health\George 8115480C 0044 cn Infinite Health\Lizzie 81154A28 0044 cn Infinite Health\Ralph 81154C44 0044 cn Infinite Lives\George 81154808 0063 cn Infinite Lives\Lizzie 81154A24 0063 cn Infinite Lives\Ralph 81154C40 0063 cn Always Full Special\Boris 811543DC 0044 cn Always Full Special\Curtis 811541C0 0044 cn Always Full Special\Ruby 811545F8 0044 cn Always Full Special\George 81154814 0044 cn Always Full Special\Lizzie 81154A30 0044 cn Enable George 8118CF92 0000 cn Infinite\Health\Boris 811543D4 0044 cn Infinite\Health\Curtis 811541B8 0044 cn Infinite\Health\Ruby 811545F0 0044 cn Infinite\Lives\Boris 811543D0 0063 cn Infinite\Lives\Curtis 811541B4 0063 crc 0304C48E-AC4001B8-C:45 gn Rat Attack (U) cn Play As/Player 1 801514F3 ???? 0000:"Hai Jinx",0001:"Sparky",0002:"Manx",0003:"Muffy Dupont",0004:"Bob Cat",0005:"Smokey",0006:"Atomicat",0007:"Pearl" cn Play As/Player 2 80151503 ???? 0000:"Hai Jinx",0001:"Sparky",0002:"Manx",0003:"Muffy Dupont",0004:"Bob Cat",0005:"Smokey",0006:"Atomicat",0007:"Pearl" cn Play As/Player 3 80151513 ???? 0000:"Hai Jinx",0001:"Sparky",0002:"Manx",0003:"Muffy Dupont",0004:"Bob Cat",0005:"Smokey",0006:"Atomicat",0007:"Pearl" cn Play As/Player 4 80151523 ???? 0000:"Hai Jinx",0001:"Sparky",0002:"Manx",0003:"Muffy Dupont",0004:"Bob Cat",0005:"Smokey",0006:"Atomicat",0007:"Pearl" cn Max Score 81158440 05F5 81158442 E0FF crc F3C5BF9B-160F33E2-C:45 gn Rayman 2 The Great Escape (U) cn Have All\Crates 810C70F8 7FFF 810C70FA FFFF 810C70FC FFFF 810C70FE FFFF 810C7100 FFFF 800C7102 00FF cn All Masks cd Press GS To Activate All Masks 891F1210 8780 cn Start with Full Health 811BC64C 001E cn Have All\Levels 811F1200 FFFF 811F1202 FFFF 811F1201 03E7 811F1203 03E7 cn Have All\Yellow Lums 50006401 0000 800C7108 00FF 50001901 0000 800C70BD 00FF 811F1182 0005 50005702 0000 811F1188 FFFF cn Have All\Pirate Cages 801F1142 0050 811F11F0 FFFF 811F11F2 FFFF 811F11F4 FFFF 811F11F6 FFFF 811F11F8 00FF 811F11FA FFFF cn Open Map 810C70F0 FFFF 810C70F2 FFFF cn Infinite\Oxygen 810F4B90 4396 crc 3918834A-15B50C29-C:45 gn Razor Freestyle Scooter (U) [!] cn Freeze Timer 800CE4EE 0077 cn Max\Wheels Collected 800CE513 ???? 0000:"0 Wheels",001E:"30 Wheels",0028:"40 Wheels" cn Zero Crash Counts 800CE49F 0000 cn Max\Tricks Landed 810CE4A6 03E7 810CE4A2 03E7 cn Max\Combos Landed 810CE4AA 03E7 810CE4AE 03E7 cn Have All Charcters & Levels Unlocked 50000740 0000 800CB951 0001 50000304 0000 800CB945 0001 50000304 0000 800CB985 0001 50000304 0000 800CB9C5 0001 50000304 0000 800CBA05 0001 50000304 0000 800CBA45 0001 50000304 0000 800CBA85 0001 crc EAB7B429-BAC92C57-C:45 gn Ready 2 Rumble Boxing (U) cn Infinite\Money 810EC932 FFFF cn Sudden Death Mode\Player 1 D00E7596 03D7 810DAF78 0000 810D9F7A 0001 cn Sudden Death Mode\Player 2 D00E7596 03D7 810DA790 0000 810DA792 0001 cn Player 1\Health 810D9F78 0000 810D9F7A ???? 0064:"Infinite",0000:"No Health" cn Player 1\Stamina 810D9F7C 0000 810D9F7E ???? 0064:"Infinite",0000:"No Stamina" cn Player 1\RUMBLE 810D9F84 0000 810D9F86 ???? 0030:"Max",0000:"Never Rumble" cn Player 2\Health 810DA790 0000 810DA792 ???? 0064:"Infinite",0000:"No Health" cn Player 2\Stamina 810DA794 0000 810DA796 ???? 0064:"Infinite",0000:"No Stamina" cn Player 2\RUMBLE 810DA7A0 0000 810DA7A2 ???? 0030:"Max",0000:"Never Rumble" cn Infinite\Time 810E7596 0E10 cn Have All Characters 5000125C 0000 810EC938 0000 5000125C 0000 810EC93A 0003 crc E9219533-13FBAFBD-C:45 gn Ready 2 Rumble Boxing: Round 2 (U) cn Infinite\Health\Player 1 cd Do not use this with No Health 810FF6B6 0064 cn No Health\Player 1 cd Do not use this with Infinite Health 810FF6B6 0000 cn Infinite\Stamina\Player 1 cd Do not use this with No Stamina 810FF6BA 0064 cn No Stamina\Player 1 cd Do not use this with Infinite Stamina 810FF6BA 0000 cn Max RUMBLE\Player 1 cd Do not use this with Never RUMBLE 810FF6C2 0090 cn Never RUMBLE\Player 1 cd Do not use this with Max RUMBLE 810FF6C2 0000 cn Infinite\Health\Player 2 cd Do not use this with No Health 81100316 0064 cn No Health\Player 2 cd Do not use this with Infinite Health 81100316 0000 cn Infinite\Stamina\Player 2 cd Do not use this with No Stamina 8110031A 0064 cn No Stamina\Player 2 cd Do not use this with Infinite Stamina 8110031A 0000 cn Max RUMBLE\Player 2 cd Do not use this with Never RUMBLE 81100322 0090 cn Never RUMBLE\Player 2 cd Do not use this with Max RUMBLE 81100322 0000 cn Infinite\Time 810FE352 0E10 cn Championship Mode\Top Rank 810F81BA 000A cn Championship Mode\Max Money 810F81C8 7FFF 810F81CA FFFF cn Championship Mode\Infinite Money 810F81CA FFFF cn Championship Mode\Max Strength 810F81CC 447A 810F81CE 0000 cn Championship Mode\Max Stamina 810F81D0 447A 810F81D2 0000 cn Championship Mode\Max Endurance 810F81D4 447A 810F81D6 0000 cn Championship Mode\Max Dexterity 810F81D8 447A 810F81DA 0000 cn Championship Mode\Max Experience 810F81DC 447A 810F81DE 0000 cn Enable Extra Characters 80101E6F 0003 80101E73 0003 80101E77 0003 80101E7B 0003 80101E7F 0003 80101E83 0003 80101E87 0003 cn Win 1 Fight to Complete Arcade Mode 80101F0B 000B crc AA18B1A5-07DB6AEB-C:45 gn Resident Evil 2 (U) cn Max Item Modifier\Slot 01 800E8EC8 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8EC9 00FF cn Max Item Modifier\Slot 02 800E8ECC ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8ECD 00FF cn Max Item Modifier\Slot 03 800E8ED0 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8ED1 00FF cn Max Item Modifier\Slot 04 800E8ED4 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8ED5 00FF cn Max Item Modifier\Slot 05 800E8ED8 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8ED9 00FF cn Max Item Modifier\Slot 06 800E8EDC ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8EDD 00FF cn Max Item Modifier\Slot 07 800E8EE0 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8EE1 00FF cn Max Item Modifier\Slot 08 800E8EE4 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8EE5 00FF cn Max Item Modifier\Slot 09 800E8EE8 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8EE9 00FF cn Max Item Modifier\Slot 10 800E8EEC ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E8EED 00FF cn Infinite\Health 810E1322 00C8 cn Always Have Fine Condition 810E13E4 0000 cn Play As 810E1138 ???? 0080:"Leon Original",0180:"Claire Original",0280:"Leon Original",0380:"Claire Original",0480:"Leon Wounded",0580:"Claire without jacket",0680:"Leon Wounded",0780:"Claire without jacket",0880:"Leon as Stars",0980:"Claire as Biker",0A80:"Leon as Biker",0B80:"Claires body Leons outfit",0C80:"Hunk (can crash the game)",0D80:"To Fu",0E80:"Ada (can crash the game)",0F80:"Cheryl" cn Play Extra Mission 810E10EE ???? 0048:"The 4th Survior",0049:"To-Fu" cn Infinite\Time 800E8CBF 0010 crc 0F1FA987-BFC1AFA6-C:45 gn Re-Volt (U) cn Access All\Cars & Tracks 8104ACA6 0001 cn Access All\Cups 5000032C 0000 810542FA 00FF cn Always 1st 8111565E 0001 81115666 0000 8110C1EE 02F4 cn Infinite Continues 8110C1E2 0006 cn Drones Have No Weapons 8111CD7E 0000 cn Infinite Weapons\Player 1 81115648 0000 8111564A ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 8111564E 0001 cn Laps To Race 8107DBCE ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Number Of Drones In The Race 8110FEA6 ???? 0001:"1 Drone",0002:"2 Drones",0003:"3 Drones",0004:"4 Drones",0005:"5 Drones",0006:"6 Drones",0007:"7 Drones",0008:"8 Drones",0009:"9 Drones" cn 99 Points Player 1 8010C1EF 0063 cn Infinite Weapons\Player 2 81117B10 0000 81117B12 ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 81117B16 0001 cn Infinite Weapons\Player 3 81119FD8 0000 81119FDA ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 81119FDE 0001 cn Infinite Weapons\Player 4 8111C4A0 0000 8111C4A2 ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 8111C4A6 0001 crc 0B6B4DDB-9671E682-C:45 gn Roadsters Trophy (U) (M3) cn Cheats Enabled Modifier 8108F840 ???? 0004:"Fast Bucks (You Get 250",0008:"Easy Money (You Get 1",0010:"Trophies (Second And Third Championships Wins)",0020:"Smurfing (High Pitched Voices)",0040:"Big Wheels (Big Foot Cars)",0080:"Skywalker (Hover Cars)",0100:"Car Radio (Remote Control Cars)",0200:"Chopper (Top Down View)",0400:"Anyway (Race Circuits Backwards)",0800:"Extra Resolution (Able To Change Resolution In Options Screen)" crc F050746C-247B820B-C:45 gn ROAD RASH 64 cn Always 1st 810D7856 0000 cn Always Have\Max Cash 810D6A7A FFFF cn Access\All Bikes & Tracks 800A77D5 0063 cn Access\Infinite & All Weapons 50000E02 0000 811B8D7A 0505 cn Infinite\Damage 801C0D17 0002 cn Infinite\Health\To Bike 811B8A38 42F0 811B8A3C 42F0 cn Infinite\Health\To Character 811BFE10 4489 811BFE12 8000 cn Always Have\Weapon 801C00B3 ???? 0001:"Fists",0002:"Spiked Club",0003:"Tiring Iron",0004:"Bat",0005:"Billie Club",0006:"Sledge Hammer",0007:"Pool Cue",0008:"Monkey Wrench",0009:"Banana",000A:"Cattle Prod",000B:"Taser",000C:"Bace",000D:"Nunchuk",000E:"Chain" crc AC8E4B32-E7B47326-C:45 gn Robotron 64 (U) cn Infinite Lives 8009B1AF 0009 cn Max Score 8009B1AA 00FF cn Level Select In Setup Menu 81076FF6 6F8C crc 0C5EE085-A167DD3E-C:45 gn Rocket: Robot On Wheels (U) cn Infinite\Max Health 8109F702 000C 8109F706 000C cn Max\Tinker Toys 810A599E 270F cn Max\Ticket Switches 810A59A2 00C8 cn Have All\Machine Parts 810A5960 FFFF cn Have All\Vechicles 810A5968 FFFF cn Activate Cheat 810A63C6 F5FF cn Whoopie World\Max Tickets 810A58F0 FFFF 810A58F2 FFFF 810A58F4 FFFF 810A58F6 FFFF 810A58F8 FFFF 810A58FA FFFF 810A58FC FFFF cn Whoopie World\Infinite Time 810A58FE FFFF cn Clowney Island\Max Tickets 810A5900 FFFF 810A5902 FFFF 810A5904 FFFF 810A5906 FFFF 810A5908 FFFF 810A590A FFFF 810A590C FFFF cn Clowney Island\Infinite Time 810A590E FFFF cn Paint Misbehaving\Max Tickets 810A5910 FFFF 810A5912 FFFF 810A5914 FFFF 810A5916 FFFF 810A5918 FFFF 810A591A FFFF 810A591C FFFF cn Paint Misbehaving\Infinite Time 810A591E FFFF cn Mine Blowing\Max Tickets 810A5920 FFFF 810A5922 FFFF 810A5924 FFFF 810A5926 FFFF 810A5928 FFFF 810A592A FFFF 810A592C FFFF cn Mine Blowing\Infinite Time 810A592E FFFF cn Arabian Flights\Max Tickets 810A5930 FFFF 810A5932 FFFF 810A5934 FFFF 810A5936 FFFF 810A5938 FFFF 810A593A FFFF 810A593C FFFF cn Arabian Flights\Infinite Time 810A593E FFFF cn Pyramid Scheme\Max Tickets 810A5940 FFFF 810A5942 FFFF 810A5944 FFFF 810A5946 FFFF 810A5948 FFFF 810A594A FFFF 810A594C FFFF cn Pyramid Scheme\Infinite Time 810A594E FFFF cn Food Fright\Max Tickets 810A5950 FFFF 810A5952 FFFF 810A5954 FFFF 810A5956 FFFF 810A5958 FFFF 810A595A FFFF 810A595C FFFF cn Food Fright\Infinite Time 810A595E FFFF crc 2500267E-2A7EC3CE-C:45 gn RR64 - Ridge Racer 64 (U) cn All Modes\Always Have 1st Place 81056444 0001 cn All Modes\Infinite Time 811269CA 0700 cn All Modes\Press R Button For Turbo D103E1EA 0010 8105641A 0800 cn Grand Prix Mode\Car Modifier 8113CF5A ???? 0000:"F/A Racing",0001:"RT Ryukyu",0002:"PAC Racing",0003:"RT Solvalou",0004:"RT Pink Mappy",0005:"RT Blue Mappy",0006:"Galaga RT Prid's",0007:"Galaga RT Carrot",0008:"RT Bosconian",0009:"RT Nebulasray",000A:"RT Xevious Red",000B:"RT Xevious Green",000C:"Dig Racing Team",000D:"Micro Mouse Mappy",000E:"13th Racing Kid",000F:"White Angel",0010:"Digipen Racing",0011:"Assoluto Infinito",0012:"Age Solo Supernova",0013:"Atomic Purple",0014:"Extreme Green",0015:"Terrazi Terrific",0016:"Lizard Nightmare",0017:"Screamin' Eagle",0018:"Ultra 64 (Full Stats)",0019:"00-Agent",001A:"Galaga' 88",001B:"Blinky",001C:"Red Shirt Rage",001D:"Crazy Canuck",001E:"Caddy Car",001F:"Pooka" cn Grand Prix Mode\Track Modifier 8113CF6A ???? 0000:"Ridge Racer Novice",0001:"Revolution Novice",0002:"Renegade Novice",0003:"Ridge Racer Intermediate",0004:"Revolution Intermediate",0005:"Renegade Intermediate",0006:"Ridge Racer Expert",0007:"Revolution Expert",0008:"Renegade Expert",0009:"Ridge Racer Extreme" cn Grand Prix Mode\Enlarge Cars 81119758 3FC0 811197AC 3FC0 81119800 3FC0 cn Grand Prix Mode\Shrink Cars 80119758 003E 801197AC 003E 80119800 003E cn Grand Prix Mode\Microscopic Cars 80119758 003D 801197AC 003D 80119800 003D cn Grand Prix Mode\2 Tier Cars 80119BB0 0039 cn Grand Prix Mode\Press GS For Overhead View 8811AB0F 0002 cn Grand Prix Mode\Unlock\All Engine Classes All Levels 50001E08 0000 8102FAB0 0004 50001E08 0000 8102FAB2 0403 cn Grand Prix Mode\Unlock\All Cars 8102F19C FFFF 8102F19E FFFF cn Grand Prix Mode\Unlock\All Tracks & Trophies 81043530 FFFF 81043532 FFFF cn Grand Prix Mode\Laps to Race 8111B32E ???? 0101:"lap",0202:"laps",0303:"laps",0404:"laps",0505:"laps",0606:"laps",0707:"laps",0808:"laps",0909:"laps" cn Grand Prix Mode\All Cars Have Perfect Stats 50008002 0000 8102F314 05DC crc 1FC21532-0B6466D4-C:45 gn Rugrats in Paris - The Movie (U) cn Red Tickets\Player 1 D00BE8C1 0000 8111F7F6 02F4 cn Gold Tickets\Player 1 D00BE8C1 0000 8111F7F8 02F4 cn Red Tickets\Player 2 D00BE8C1 0001 8111F7F6 02F4 cn Gold Tickets\Player 2 D00BE8C1 0001 8111F7F8 02F4 cn Red Tickets\Player 3 D00BE8C1 0002 8111F7F6 02F4 cn Gold Tickets\Player 3 D00BE8C1 0002 8111F7F8 02F4 cn Red Tickets\Player 4 D00BE8C1 0003 8111F7F6 02F4 cn Gold Tickets\Player 4 D00BE8C1 0003 8111F7F8 02F4 crc EDD6E031-68136013-C:45 gn Rush 2 - Extreme Racing USA (U) cn Always Place 1st 80112589 0000 cn Have\Extra Cars 50000902 0000 810C1DBC FFFF cn Have\Game Timer Off 800D9E88 0001 cn Have\Midway Track 800E7D19 0001 cn Have\Stunts All Tracks 8010C200 0001 cn Press R to Shrink Car D00D0193 0010 8010C43C 0001 cn Track Modifier 8010C3F0 ???? 0000:"Las Vegas",0001:"New York Downtown",0002:"Hawaii",0003:"New York Uptown",0004:"Alcatraz",0005:"Los Angeles",0006:"Seattle",0007:"Half Pipe",0008:"Crash",0009:"Pipe",000A:"Midway",000B:"Stunt" cn Best Points\In Stunt Mode\Player 1 8010C068 00FF cn Total Points\In Stunt Mode\Player 1 8010C075 00FF cn Best Points\In Stunt Mode\Player 2 8010C069 00FF cn Total Points\In Stunt Mode\Player 2 8010C077 00FF cn Car Select\Player 1 803CB362 ???? 0000:"Pickup",0001:"Compact",0002:"Muscle Car",0003:"Mobster",0004:"Sedan",0005:"Bandit",0006:"Coupe",0007:"Exotic",0008:"Van",0009:"Sportster",000A:"Subcompact",000B:"Concept",000C:"Stallion",000D:"Cruiser",000E:"Stallion",000F:"4x4",0010:"Taxi",0011:"Hot Rod",0012:"Formula",0013:"Prototype",0014:"Rocket",0015:"Mtn Dew" cn Car Select\Player 2 803CB363 ???? 0000:"Pickup",0001:"Compact",0002:"Muscle Car",0003:"Mobster",0004:"Sedan",0005:"Bandit",0006:"Coupe",0007:"Exotic",0008:"Van",0009:"Sportster",000A:"Subcompact",000B:"Concept",000C:"Stallion",000D:"Cruiser",000E:"Stallion",000F:"4x4",0010:"Taxi",0011:"Hot Rod",0012:"Formula",0013:"Prototype",0014:"Rocket",0015:"Mtn Dew" cn Press R For Nitrous Boost D00D0193 0010 810F58DC 44CB D00D0193 0010 810F5938 44CB cn Have\All Keys & Cans\Midway Track 810C1DD0 FFFF cn Have\All Keys & Cans\Stunt Track 810C1DD2 FFFF cn Front Pickup Tire Size\Player 1 800C0AC5 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Rear Pickup Tire Size\Player 1 800C0BCD ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Mt. Dew Front Tire Size\Player 1 800C0B19 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Mt. Dew Rear Tire Size\Player 1 800C0C21 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Rocket Front Tire Size\Player 1 800C0B15 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Rocket Rear Tire Size\Player 1 800C0C1D ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Prototype Front Tire Size\Player 1 800C0B11 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Prototype Rear Tire Size\Player 1 800C0C19 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Formula Front Tire Size\Player 1 800C0B0D ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Formula Rear Tire Size\Player 1 800C0C15 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Hot Rod Front Tire Size\Player 1 800C0B09 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Hot Rod Rear Tire Size\Player 1 800C0C11 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Cruiser Front Tire Size\Player 1 800C0AF9 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Cruiser Rear Tire Size\Player 1 800C0C01 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Van Front Tire Size\Player 1 800C0AE5 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Van Rear Tire Size\Player 1 800C0BED ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Pickup Front Tire Size\Player 2 800C0B1D ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Rear Tire Size\Player 2 800C0C25 ???? 0000:"Tiny",0001:"Medium",00FF:"Gigantic" cn Misc\Auto Abort Disable 8010C168 0001 cn Misc\Resurrect In Place 8010C210 0001 cn Misc\New York Cabs 800D9E89 0001 cn Misc\Car Collisions Off 8011249A 0001 cn Misc\Cone Mines On 8010C166 0001 cn Misc\Car Mines On 8010C167 0001 cn Misc\Super Speed 80111950 0001 cn Misc\Damage Off 8011CDB0 0001 cn Misc\Light Gravity 800E7D22 0000 cn Misc\Heavy Gravity 800E7D22 0002 cn Misc\Jovian Gravity 800E7D22 0003 cn Misc\Brakes Off 80125C64 0001 cn Misc\Heavy Mass 8010C179 0001 cn Misc\Massive Mass 8010C179 0002 cn Misc\Invincible 80119634 0001 cn Misc\Invisible Cars 8010C170 0001 cn Misc\Invisible Tracks 8010C178 0001 cn Misc\Large Frame 8010C43C 0003 cn Misc\Killer Rats On 8010C17C 0001 cn Misc\Inside-Out Car On 801174E0 0001 cn Misc\Upside Down Mode 800D0171 0001 cn Misc\Suicide Mode On 80119628 0001 cn Misc\Suicide Mode Humans On 80119628 0002 cn Misc\Levitation 8010C254 0001 cn Misc\Super Tires 8010D3A6 0002 cn Misc\Have All Cars In Pipe 810C1DCE FFFF cn Press GS Activate Cheat Menu 880C2132 0001 cn Misc\Your Car Is Invisible 801127A1 0001 cn Misc\Laps to Race 8010C0E3 ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Misc\Drones In Race 800D5761 ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps" cn Misc\Difficulty Mod 8010C211 ???? 0000:"Very Easy",0001:"Easy",0002:"Medium",0003:"Hard",0004:"Very Hard",0005:"Extremely Hard" cn Unlock All Cheats 50000E02 0000 810C20E8 0101 cn Have All Keys Found\Las Vegas Normal 810C1DBC FFFF cn Have All Keys Found\New York-Downtown\Normal 810C1DBE FFFF cn Have All Keys Found\Hawaii\Normal 810C1DC0 FFFF cn Have All Keys Found\New York-Uptown\Normal 810C1DC2 FFFF cn Have All Keys Found\Alcatraz\Normal 810C1DC4 FFFF cn Have All Keys Found\Los Angeles\Normal 810C1DC6 FFFF cn Have All Keys Found\Seattle\Normal 810C1DC8 FFFF crc 769147F3-2033C10E-C:45 gn SCARS (U) cn Have All\Cars 50000402 0000 803DF94B 0001 cn Have All\Cups,Tracks & Challenges 50000302 0000 802CB4A9 0001 50000402 0000 803DD109 0001 cn Infinite Credits 80388C1D 0009 cn Max Score Points 8139AFB6 02F4 cn Game Speed 802C9339 ???? 0000:"Novice",0001:"Default",0002:"Advanced",0003:"Master" cn Always Have Equipped\Player 1 8039B144 ???? 8039B147 ???? 0000:"Turbo",0001:"Magnet",0003:"Stinger",0004:"Boomerang",0005:"Seeker",0006:"Stopper",0007:"Bullets",0008:"Shield" 8039B149 0009 cn Always Have Equipped\Player 2 8039B3E4 ???? 8039B3E7 ???? 0000:"Turbo",0001:"Magnet",0003:"Stinger",0004:"Boomerang",0005:"Seeker",0006:"Stopper",0007:"Bullets",0008:"Shield" 8039B3E9 0009 cn Always Have Equipped\Player 3 8039B684 ???? 8039B687 ???? 0000:"Turbo",0001:"Magnet",0003:"Stinger",0004:"Boomerang",0005:"Seeker",0006:"Stopper",0007:"Bullets",0008:"Shield" 8039B689 0009 cn Always Have Equipped\Player 4 8039B924 ???? 8039B927 ???? 0000:"Turbo",0001:"Magnet",0003:"Stinger",0004:"Boomerang",0005:"Seeker",0006:"Stopper",0007:"Bullets",0008:"Shield" 8039B929 0009 crc 2A6B1820-6ABCF466-C:45 gn San Francisco Rush - Extreme Racing (U) cn Activate\Stop Timer 800F4090 0001 cn Activate\Auto Abort Disable 800F4078 0001 cn Activate\Cones to Mines 800F3F88 0001 cn Activate\Disable Car 2 Car Control 800F4050 0001 cn Activate\Resurrect in Place 800F4080 0001 cn Activate\Upside Down Mode 800F4061 0001 cn Car D00F40A5 0020 800D9EC1 ???? 800D9F64 ???? 800DA078 ???? 800DA321 ???? 0008:"Taxi",0009:"Hot Rod",000A:"F1 Car" cn Edge Boost cd by pressing R you will get a small speed boost that pushes you ahead. D00F40A5 0010 81101331 FFFF cn Car Type cd It gets you from 0-150 in the the time it takes the F1 racer to. Don't use the F1 racer and only hold until you reach 150 or the game will freeze. 800F40B1 ???? 0000:"Normal Car",0001:"Flat Car",0002:"Fat Car",0003:"Giant Car",000A:"Invisible Car",0044:"Super-Tiny Car #2",0066:"Paper-Thin Cars",006E:"Screen-Talled Cars",00BB:"Super-Sky Car",00CD:"Invisible Car (Can See Wheels)",00DD:"Super-Sky Car #2",00FF:"Super-Tiny Car" cn Press GS For Track Select cd With this code, press GS when on the track selction screen and press A to select that track! 88100050 ???? 0000:"Track 1",0001:"Track 2",0002:"Track 3",0003:"Track 4",0004:"Track 5",0005:"Track 6",0006:"Track 7" cn Gravity 800F3D91 ???? 0000:"A Balloon & 2 Weights",0001:"Normal",0002:"1 Weight",0003:"2 Weights" cn Always Place 1st 80101339 0000 cn Have Two Special Cars cd You receive the Hotrod and Taxi with this code, but you may have to go through the cars from the "Beginning" past the "Extreme" for them to appear. 810CAC82 FFFF 810CAC98 FFFF 810CACAE FFFF 810CACC4 FFFF 810CACDA FFFF 810CACF0 FFFF crc B9A9ECA2-17AAE48E-C:45 gn San Francisco Rush 2049 (U) cn Unlock All Cheats 50000B02 0000 8111648C 0101 cn Speed Activator D0037AA4 0020 8114A298 ???? 4333:"146 mph",4350:"170 mph",4380:"210 mph",4393:"270 mph" cn Always Place 1st 80152906 0000 cn Start On Lap Modifier D014AA38 0000 8014AA38 ???? cn Track Modifier 8014978C ???? 0000:"Track 1",0001:"Track 2",0002:"Track 3",0003:"Track 4" cn Max Score\Stunt Mode 8115204E 7FFF cn Infinate Ammo\All Players In Battle 80152B9D 0050 80152F55 0050 8015330D 0050 801536C5 0050 cn Have All\Gold & Silver Coins\Track 1 8113A110 FFFF cn Have All\Gold & Silver Coins\Track 3 8113A1D0 FFFF cn Have All\Gold & Silver Coins\Track 4 8113A230 FFFF cn Have All\Gold & Silver Coins\Track 5 8113A290 FFFF cn Have All\Gold & Silver Coins\Track 6 8113A2F0 FFFF crc 0C814EC4-58FE5CA8-C:45 gn Scooby-Doo - Classic Creep Capers (U) cn Infinite Health 81086BCA 0038 800BAF97 0007 crc 036897CE-E0D4FA54-C:45 gn ShadowGate 64 - Trials of the Four Towers (U) cn Item Modifier Codes\Position 01 800EC350 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 02 800EC351 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 03 800EC352 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 04 800EC353 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 05 800EC354 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 06 800EC355 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 07 800EC356 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 08 800EC357 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 09 800EC358 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 10 800EC359 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 11 800EC35A ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 12 800EC35B ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 13 800EC35C ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 14 800EC35D ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 15 800EC35E ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 16 800EC35F ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 17 800EC360 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 18 800EC361 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 19 800EC362 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 20 800EC363 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 21 800EC364 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 22 800EC365 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 23 800EC366 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 24 800EC367 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 25 800EC368 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 26 800EC369 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 27 800EC36A ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 28 800EC36B ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 29 800EC36C ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 30 800EC36D ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 31 800EC36E ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 32 800EC36F ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 33 800EC370 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 34 800EC371 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 35 800EC372 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 36 800EC373 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 37 800EC374 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 38 800EC375 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 39 800EC376 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 40 800EC377 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 41 800EC378 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 42 800EC379 ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 43 800EC37A ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 44 800EC37B ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 45 800EC37C ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 46 800EC37D ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 47 800EC37E ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn Item Modifier Codes\Position 48 800EC37F ???? 0001:"Crest Key",0002:"Bottle of Oil",0003:"Fragments of A Crest",0004:"Dragon Tears",0005:"Pixie Flute",0006:"Treasure",0007:"Rusty Key",0008:"Ornate Key",0009:"The Ring of The Kingdom",000A:"Orb",000B:"Golden Key",000C:"Liquid Sunset",000D:"Night Elixir",000E:"Forest Nectar",000F:"Primitive Man Statue",0010:"Apeman Sculpture",0011:"Fairy Sculpture",0012:"Elf Statue",0013:"Ancient Coin",0014:"Pick Axe",0015:"The Ring of The Dead",0016:"The Blue Ring",0017:"The Green Ring",0018:"Lever",0019:"Slipper",001A:"Dirty Slipper",001B:"Pair of Slippers",001C:"Jezibel's Pendant",001D:"The Staff of Ages",001E:"Rope",001F:"Cemetery Key",0020:"Flower",0021:"Flint",0022:"Fang",0023:"Dragon Eye",0024:"Dragon Flute",0025:"Burning Candle",0026:"Chipped Violin",0027:"String-Less Violin",0028:"Broken Violin",0029:"Dungeon Key",002A:"Map",002B:"Bone",002C:"Starcrest",002D:"Iron Bar",002E:"Crow Bar",002F:"Hair of Giant",0030:"Mug",0031:"Water",0032:"Water W/Dragon Tears",0033:"Stone of Thirst",0034:"Coin",0035:"Coin",0036:"Coin",0037:"Coin",0038:"Coin",0039:"Nail",003A:"Brooch",003B:"Jewelry Box",003C:"Fruit",003D:"Gauntlet",003E:"Cup",003F:"Artwork",0040:"Poisonous Herb",0041:"Bracelet",0042:"Precious Stone",0043:"Broken Sword",0044:"Quill",0045:"Plate",0046:"Broken Lance" cn All Items 50002402 0202 810EC350 0001 50004601 0000 800EC3D1 0003 crc 3A4760B5-2D74D410-C:45 gn Shadowman (U) cn Infinite\Air 81075B1C 0000 81075B1E 2710 cn Infinite\Health 81075B18 0000 81075B1A 2710 81075B14 0000 81075B16 2710 cn All Cheats Book of Shadows 81030690 0004 81030692 030B cn Max Shadow Charge & Level 81075B20 0000 81075B22 2710 81075B24 0000 81075B26 2710 cn Max Dark Souls Collected 81075F48 0078 cn Health Meter Displayed On Screen 81075B10 0000 81075B12 00FF cn Have All\Items 81030630 0000 81030632 100B 81030650 0016 81030652 130B 81030670 0018 81030672 150B 81030690 0004 81030692 030B 810306B0 001D 810306B2 180B 810306D0 0001 810306D2 000B 810306F0 000A 810306F2 080B 81030710 0002 81030712 010B 81030730 000C 81030732 0E0B 81030750 000E 81030752 0A0B 81030770 0009 81030772 070B 81030790 000B 81030792 090B 810307B0 0007 810307B2 060B 810307D0 001A 810307D2 160B 810307F0 0015 810307F2 120B 81030810 001E 81030812 190B 810308B0 0017 810308B2 140B 81030830 0012 81030832 0F0B 81030850 0003 81030852 020B 81030870 000D 81030872 0B0B 810308F0 0006 810308F2 050B 81030950 0014 81030952 110B 810309D0 0005 810309D2 040B 80030E57 000F cn Have All\Ammo 81075B28 0000 81075B2A 2710 81075B2E 0063 81075B36 03E7 81075B32 03E7 81075B3A 03E7 810306D6 7FFF 81030736 7FFF 810307D6 7FFF 81030816 7FFF 81030876 7FFF 81030816 7FFF 810306D6 FFFF 81030736 FFFF 810307D6 FFFF 81030816 FFFF 81030876 FFFF 81030816 FFFF cn Have All\Warp Levals 800309F2 0001 80030A0E 0001 80030A2A 0001 80030A46 0001 80030A62 0001 80030A7E 0001 80030A9A 0001 80030AB6 0001 80030AD2 0001 80030AEE 0001 80030B0A 0001 80030B26 0001 80030B42 0001 80030B5E 0001 80030B7A 0001 80030B96 0001 80030BB2 0001 cn Always Play As Deadwing Character 80075F52 0001 cn Have L-Eclipser\La Lune cd If you put all Three of these Options on together, you skip straight to being Shadow Man. 80030971 0010 80030973 0D0B cn Have L-Eclipser\La Soleil cd If you put all Three of these Options on together, you skip straight to being Shadow Man. 80030991 001C 80030993 170B cn Have L-Eclipser\La Lame cd If you put all Three of these Options on together, you skip straight to being Shadow Man. 800309B1 0011 800309B3 0C0B crc DBF4EA9D-333E82C0-C:45 gn Snowboard Kids (U) cn Infinite\Tools Options 80122295 ???? 0001:"Fan",0002:"Ghost",0003:"Pan",0004:"Rock",0005:"Mouse",0006:"Board" cn Infinite\Lucky Dip cd "Lucky Dip is Infinite Usage Of What Ever You Get From Each Red Box" 80122294 0003 cn 999 Trick Game Pts 81122040 03E7 cn 1 Lap Race D0122288 0000 80122288 0009 cn Infinite\Cash 801222EA C350 cn Enable Sinobin 8110AE5E 0100 cn Access Gold Medals 50000602 0000 810ECA22 0101 crc 930C29EA-939245BF-C:45 gn Snowboard Kids 2 (U) cn All Gold Medals 50000502 0000 81259130 0101 cn Max Coins 8125A5BE 270F 8025A5BF 00C8 cn Infinite\Trick Game 300 Points 8125A7F2 012C cn Infinite\Tools Options 8025A624 ???? 0001:"Frying Pan",0002:"Ghost",0003:"Super Ghost",0004:"Fan",0005:"Rocket",0006:"Invisible",0007:"Rock",0008:"Rat Face",0009:"Super Rat Face",000A:"Wings" cn Infinite\Weapons Options 8025A622 ???? 0001:"Slap Stick",0002:"Parachute",0003:"Freeze Shot",0004:"Snowman",0005:"Bomb",0006:"Whirlwind" 8025A623 0009 cn Open Extra Characters & Snowboards cd Battle Mode Only 8125916E 0101 80259170 0001 8025915C 0001 8125915E 0101 81259160 0101 crc 7ECBE939-3C331795-C:45 gn South Park (U) cn Have all Cheats cd Go into the Cheats From the main Menu & put on the Ones you want 810CD226 01FF crc C00CA948-8E60D34B-C:45 gn South Park - Chef's Luv Shack (U) cn Max Or No Score\Player 1 81104772 ???? FFFF:"Max Score",0000:"No Score" cn Max Or No Score\Player 2 81104776 ???? FFFF:"Max Score",0000:"No Score" cn Max Or No Score\Player 3 8110477A ???? FFFF:"Max Score",0000:"No Score" cn Max Or No Score\Player 4 8110477E ???? FFFF:"Max Score",0000:"No Score" crc 07F3B276-EC8F3D39-C:45 gn South Park Rally (U) cn Unlock All Characters & Extra Cheats 81088750 FFFF 81088752 FFFF cn Have All\Races 81088756 FFFF cn Have All\Tracks 8108875A FFFF cn Infinite Credits 8008D659 0063 crc BFE23884-EF48EAAF-C:45 gn Silicon Valley (U) cn Infinite\Ability\Sheep 811DE9A0 0400 cn Infinite\Ability\Mouse 811DFCC8 0400 cn Infinite\Boost\Mouse 811DFCC4 0400 cn Infinite\Ability\Penguin 811E009C 0400 cn Infinite\Ability\Husky 811DED78 0400 cn Infinite\Ability\Rabbit 811DE5D0 0400 cn Infinite\Ability\Heli-Rabbit 811DF14C 0400 cn Infinite\Boost\Walrus 811DED74 0400 cn Infinite\Ability\Walrus 811DE5D0 0400 cn Infinite\Ability\Racing Dog 811DF14C 0400 cn Infinite\Boost\Racing Dog 811DF148 0400 cn Infinite\Ability\Ram 811DE5D0 0400 cn Infinite\Ability\Racing Fox 811DF8F4 0082 cn Infinite\Boost\Racing Fox 811DF8F0 0400 cn Infinite\Ability\Springy Thing 811DF14C 0400 cn Infinite\Ability\Fox 811DF8F4 0400 cn Infinite\Boost\Fox 811DF8F0 0400 cn Infinite\Energy\EVO (Chip) 801DE065 0082 cn Infinite\Energy\Evo\in Bonus Level 1 & Final Level 801DE439 0082 cn Infinite\Energy\Evo\In Bonus Level 4 801DEFB5 0082 cn Infinite Health\Ship\in Asteroids Level 803E4CDB 0003 cn Infinite\Energy\Mouse,Hyena 801DFB31 0082 cn Infinite\Energy\Snow Husky 811DFF04 0082 cn Infinite\Energy\Normal Rabbit 811DE438 0082 cn Infinite\Energy\Heli-Rabbit 811DEFB4 0082 cn Infinite\Energy\Sheep 811DEBE0 0082 cn Infinite\Energy\Normal Penguin 811DFF04 0082 cn Infinite\Energy\Dog 811DFF04 0082 cn Infinite\Energy\Racing Dog 811DEFB4 0082 cn Infinite\Energy\Ram 811DE438 0082 cn Infinite\Energy\Racing Fox 811DF7FC 0082 cn Infinite\Energy\Springy Thing 811DEFB4 0082 cn Infinite\Energy\Fox 811DF75C 0082 cn Have All\Secret Mini Game 803F643D 0001 cn Always\Raining 803F2D6F 0005 cn Always\Snowing 803F2D6D 0005 cn Have All\Power Cells 803F2D3D 000F cn Debug Mode 803F642F 0001 cn All Levels Open 50002001 0000 803F7DE0 0001 cn High Score 813F2D30 007F 813F2D32 FFFF crc EBFE2397-FF74DA34-C:45 gn Space Invaders (U) cn Infinite\Lives 800B51DD 0063 cn Infinite\Points 810B51E2 FFFF cn Always Have\Vertical Burst 810B51DE 0104 cn Always Have\Horizontal Right 810B51DE 0204 cn Always Have\Horizontal Left 810B51DE 0304 cn Always Have\Diagonal Burst 810B51DE 0404 cn Infinite\Shield 810B51B6 0001 crc A60ED171-3D85D06E-C:45 gn Spider-Man (U) cn Unlocked\All Costumes 810ECD7E FFFF cn Unlocked\All Levels 810ECD74 0105 810ECDB0 FFFF cn Have All Characters In Viewer 810ECD80 FFFF 810ECD82 FFFF cn Infinite\Health 800F5F26 0001 cn Infinite\Webbing 800F5F53 0001 crc 0684FBFB-5D3EA8A5-C:45 gn StarCraft 64 (U) cn Infinite\& Max Minerals 50000C04 0000 810B1D46 FFFF 50000C04 0000 810B1D44 3B9A 50000C04 0000 810B1D46 C9FF cn Infinite\& Max Vespene Gas 50000C04 0000 810B1D76 FFFF 50000D04 0000 810B1D74 3B9A 50000D04 0000 810B1D76 C9FF cn All levels complete 800D13C4 000C 800D13C5 000A 800D13C6 000A 800D13C7 000A 800D13C8 000A 800D13C9 000A crc A7D015F8-2289AA43-C:45 gn Star Fox 64 (U) cn Unlimited\Boost 81137C9C 0000 81137C9E 0000 8113AB7C 0000 8113AB7E 0000 cn Have All Medals cd For Expert & Normal Modes 50000802 0000 8116E6E0 7777 cn Infinite\Hyper Laser 8015791B 0002 cn Loads O' Hits 8015790B 00FF cn Infinite\Armor\Slippy 8016D72B 00FF cn Infinite\Energy 8013AB27 00FF 80137C47 00FF cn Infinite\Lives 80157911 0009 cn Unlimited\Smart Bombs 8016DC13 0004 cn Infinite\Armor\Falco 8016D727 00FF cn Infinite\Armor\Peppy 8016D72F 00FF cn Infinite\Dual Blue Lasers 8015791B 0002 cn Level Select D016E0A7 0000 8016E0A7 ???? 0000:"Corneria",0001:"Meteo",0002:"Sector X",0003:"Area 6",0004:"Glitch",0005:"Sector Y",0006:"Venom 1",0007:"Solar",0008:"Zoness",0009:"Venom 2",000A:"Training Mode Level",000B:"Macbeth",000C:"Titania",000D:"Aquas",000E:"Fortuna",0010:"Katina",0011:"Bolse",0012:"Sector Z",0013:"Venom With Starwolf",0014:"Corneria (Multi)" crc BA780BA0-0F21DB34-C:45 gn Star Fox 64 (U) (V1.1) cn Unlimited\Boost 8113C68C 0000 8113C68E 0000 8113F56C 0000 8113F56E 0000 cn Have All Medals cd For Expert & Normal Modes 50000802 0000 81178870 7777 cn Infinite\Dual Blue Lasers 80161AAB 0002 cn Loads O' Hits 80161A9B 00FF cn Infinite\Armor\Slippy 801778BB 00FF cn Infinite\Energy\Player 1 cd For Solo & Multi Player 8013C637 00FF 8013F517 00FF cn Infinite\Lives 80161AA1 0009 cn Unlimited\Smart Bombs 80177DA3 0004 cn Infinite\Armor\Falco 801778B7 00FF cn Infinite\Armor\Peppy 801778BF 00FF cn Level Select 80178237 ???? 0000:"Corneria",0001:"Meteo",0002:"Sector X",0003:"Area 6",0004:"Glitch",0005:"Sector Y",0006:"Venom 1",0007:"Solar",0008:"Zoness",0009:"Venom 2",000A:"Training Mode Level",000B:"Macbeth",000C:"Titania",000D:"Aquas",000E:"Fortuna",0010:"Katina",0011:"Bolse",0012:"Sector Z",0013:"Venom With Starwolf",0014:"Corneria (Multi)" cn Infinite Health\Player 2 8013CB17 00FF 8013F9F7 00FF cn Infinite Health\Player 3 8013CFF7 00FF 8013FED7 00FF cn Infinite Health\Player 4 8013D4D7 00FF 801403B7 00FF cn Infinite Smart Bombs\Player 2 80177DA7 0004 cn Infinite Smart Bombs\Player 3 80177DAB 0004 cn Infinite Smart Bombs\Player 4 80177DAF 0004 cn Infinite Dual Blue Lasers\Player 2 80161AAF 0002 cn Infinite Dual Blue Lasers\Player 3 80161AB3 0002 cn Infinite Dual Blue Lasers\Player 4 80161AB7 0002 cn Infinite Boost\Player 2 8113CB6C 0000 8113CB6E 0000 8113FA4C 0000 8113FA4E 0000 cn Infinite Boost\Player 3 8113D04C 0000 8113D04E 0000 8113FF2C 0000 8113FF2E 0000 cn Infinite Boost\Player 4 8113D52C 0000 8113D52E 0000 8114040C 0000 8114040E 0000 crc DDD93C85-DAE381E8-C:45 gn Star Soldier: Vanishing Earth (U) cn Infinite\Lives 800A3648 0003 cn Infinite\Specials 800A3649 0003 cn Extra Armor 800A362F 0001 cn Play As 800A364C ???? 0000:"Character 1",0001:"Character 2",0002:"Character 3" cn Max\Score 810A3624 03E7 cn Max\Upper Level 800A3659 0063 cn Max\Lower Level 800A3658 0003 cn Max\Combo 810A3644 7FFF cn Status Modifier 800A364A ???? 0001:"High",0002:"Mid",0003:"Low" crc 72F70398-6556A98B-C:45 gn Star Wars EP1 Pod Racer (U) cn No Damage cd If when Racing Your Pod Over heats & bursts into flames Press "R" & you will Repair the Damage. 800A52D7 0001 cn Infinite Truguts 81113E7A FFFF 81113E78 7FFF cn Always 1st 81118FEC 0001 cn Enable In-Game cheat Menu & Cheats cd Here you can Activate the IN-Built Cheats Menu. At the Front Screen Just Press C-Button Right.This will open up All Tracks & Characters In Free Play & Time Attack. Also In A Race, Press The Start/Pause button to Access the In-Cheat-Menu Option.You can also choose how many Pod's Racers are in the Race & also how many Laps are in the Race in Free Play & Time Attack 8009B7D7 0001 8109B7DA FFFF cn Unlock All Tracks & Characters cd When using Unlock All Tracks & Characters For can to pick & choose what ever you want to play As & where ;) 80113E68 00FF 80113E69 00FF 80113E6A 00FF 80113E6B 00FF 81113E68 FFFF 81113E6A FFFF 80113E74 007D 81113E76 FFFF cn Have All Tracks Completed 81113E6A FFFF 81113E6C 3FFF 81113E6E 3FFF 81113E70 3FFF 81113E72 00FF crc 264D7E5C-18874622-C:45 gn Star Wars - Shadows of the Empire (U) (V1.0) cn All Levels\Infinite\Lives 800E05CB 0064 cn All Levels\Infinite\Missiles 800E1265 00FF cn All Stages\Invincible 8107A770 2400 cn All Stages\Infinite Health 81072D0C 2400 cn All Stages\Lasers Never Overheat 81073948 2400 cn All Stages\Upper Lasers cd Don't Use With Never Overheat Code 81073944 3C06 81073946 4EFF cn All Stages\Infinite\Pulse Ammo 81074204 2400 cn All Stages\Infinite\Flame Ammo 81073720 2400 cn All Stages\Infinite\Seeker Ammo 81073A94 2400 cn All Stages\Infinite\Stunner Ammo 81073BD4 2400 cn All Stages\Infinite\Disruptor Ammo 81073F04 2400 cn All Stages\Infinite\Jet Pack 81076AAC 2400 81076C58 2400 81076B48 2400 cn All Levels\Time Always 0:00:02 810E04E8 4000 cn All Levels\No Clipping\Off 81111E67 0001 cn All Levels\No Clipping\On 81111E67 0000 cn All Levels\Visibililty\Maximum 800BA62B FFFF cn All Levels\Visibililty\Minimum 800BA66B FFFF cn All Levels\Large Mutant Enemies 800BB62B FFFF cn All Levels\Dash Becomes Shorter & Wider 800BA025 FFFF cn All Levels\See Through\Some Walls 800BC625 FFFF cn All Levels\See Through\Everything Except Specific Things 800BC665 FFFF cn Press GS For Pink Cheat Debug Screen 890D017F 0001 crc 4147B091-63251060-C:45 gn Star Wars - Shadows of the Empire (U) (V1.1) cn Press GS For Pink Cheat Debug Screen 890D01BF 0001 crc 635A2BFF-8B022326-C:45 gn SUPER MARIO 64 cn Press GS For 255 Coins 8933B218 00FF cn Have\Level Select A032D58C 0001 cn Don't Hurt Mario\Monsters A033B197 0001 cn Infinite\Lives 8033B21D 0064 cn Infinite\Energy & Breath 8033B21E 0008 cn Have\Debug Mode A032D598 ???? 0001:"On",0000:"Off" cn Mario's Cap\Off Options cd Here you can Choose Options with Mario without His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 8033B177 ???? 0001:"Mario No Cap",0002:"Invisible Mario",0004:"Metal Mario",0008:"Flying Mario",000A:"Invisible Flying Mario",000D:"Metal Flying Mario",000F:"Invisible Metal Flying Mario" cn Mario's Cap\On Options cd Here you can Choose Options with Mario with His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 8033B177 ???? 0012:"Invisible Mario",0015:"Metal Mario",0016:"Invisible Metal Mario",0019:"Flying Mario" cn Funny Mario Options\Mario's Cap\Off & in His Hand cd Here you can Choose Options with Mario with His Cap off & in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 8033B177 ???? 0020:"Cap In Hand",0022:"Invisible Mario Cap In Hand",0024:"Metal Mario Cap In Hand",0026:"Invisible Metal Mario Cap In Hand",0028:"Flying Mario Cap In Hand" cn Funny Mario Options\Mario's Cap\On & An Extra in His Hand cd Here you can Choose Options with Mario with His Cap on & An Extra in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 8033B177 ???? 0030:"Cap In Hand",0032:"Invisible Mario Cap In Hand",0034:"Metal Mario Cap In Hand",0036:"Invisible Metal Mario Cap In Hand",0038:"Flying Mario Cap In Hand" cn Don't Hurt Mario\Falling 8033B22C 00E8 8133B178 FFFF cn Press L To Levitate cd Press L to levitate & Let go to land D033AFA1 0020 8133B1BC 4220 D033AFA1 0020 8133B17C 0300 D033AFA1 0020 8133B17E 0880 cn [Slot A Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80207723 0001 8020770B 00C7 50001101 0000 8020770C 00FF cn [Slot A Codes]\Have all key doors unlocked (and mote empty) 8020770A 007E cn [Slot A Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80207725 0064 cn [Slot B Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80207793 0001 8020777B 00C7 50001101 0000 8020777C 00FF cn [Slot B Codes]\Have all key doors unlocked (and mote empty) 8020777A 007E cn [Slot B Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80207795 0064 cn [Slot C Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80207803 0001 802077EB 00C7 50001101 0000 802077EC 00FF cn [Slot C Codes]\Have all key doors unlocked (and mote empty) 802077EA 007E cn [Slot C Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80207805 0064 cn [Slot D Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80207873 0001 8020785B 00C7 50001101 0000 8020785C 00FF cn [Slot D Codes]\Have all key doors unlocked (and mote empty) 8020785A 007E cn [Slot D Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80207875 0064 cn Level Select cd Select a Level. Jump Into a Painting. Press A at the Stars Collected Screen. As Stats are fading hold L, and you'll jump to the level you've selected. D033AFA1 0020 A032DDF9 ???? 0001:"Intro",0004:"Big Boo's Haunt",0005:"Cool Cool Mountain",0006:"Mushroom Castle",0007:"Hazy Maze Cave",0008:"Shifting Sand Land",0009:"Bob omb Battlefield",000A:"Snowman's Land",000B:"Wet Dry World",000C:"Jolly Roger Bay",000D:"Tiny Huge World",000E:"Tick tock Clock",000F:"Rainbow Ride",0010:"Mushroom Castle Field",0011:"Bowser In The Dark World",0012:"Vanish Cap Under The Moat",0013:"Bowser In The Fire Sea",0014:"The Secret Aquarium",0015:"Bowser In The Sky",0016:"Lethal Lava Land",0017:"Dire Dire Docks",0018:"Whomp's Fortress",0019:"The End",001A:"Castle Courtyard",001B:"The Princess's Secret Slide",001C:"Cavern Of The Metal Cap",001D:"Tower Of The Wing Cap",001E:"Bowser In The Dark World Boss",001F:"Wing Mario Over The Rainbow",0021:"Bowser In The Fire Sea Boss",0022:"Bowser In The Sky Boss",0024:"Tall Tall Mountain" cn Have\Turbo Running Speed 8033B1C3 00FF crc 916B8B5B-780B85A4-C:45 gn SMASH BROTHERS cn Give Kirby A Wierd Blow-Up 8025E158 000A cn Story Mode\Skip Straight To Master Hand 800A4AE7 000D cn Story Mode\Infinite Time 810A4B2E 43CB cn Story Mode\Player 1\Infinite Lives 800A4B43 0004 cn Story Mode\Player 2\Infinite Lives 800A4BB7 0004 cn Story Mode\Player 3\Infinite Lives 800A4C2B 0004 cn Story Mode\Player 4\Infinite Lives 800A4C9F 0004 cn Story Mode\Player 1\Low % Health 810A4B86 0000 cn Story Mode\Player 2\Low % Health 810A4BFA 0000 cn Story Mode\Player 3\Low % Health 810A4C6E 0000 cn Story Mode\Player 4\Low % Health 810A4CE2 0000 cn Story Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code could also result freezing at the end of the Level. 800A4B3B ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A4BAF ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A4C23 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A4C97 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 1\Kirby B Button Move\Hyrule Castle 80268B0F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Yoshi's Island 80268E4F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Sector Z 802710F7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Peach's Castle 80263D9F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Saffron City 80273A97 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Congo Jungle 80270ACF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Kirby's Dreamland 8026DB3F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Planet Zebes 8026FFA7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Metal Mario Stage 80263597 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Fighting Polygon Team 8026271F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Master Hand Stage 80271C4F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Infinite Time 810A4D1E 43CB cn VS. Mode\Player 1\Low % Health 810A4D76 0000 cn VS. Mode\Player 2\Low % Health 810A4DEA 0000 cn VS. Mode\Player 3\Low % Health 810A4E5E 0000 cn VS. Mode\Player 4\Low % Health 810A4ED2 0000 cn VS. Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A4D2B ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A4D9F ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A4E13 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A4E87 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 1\Kirby B Button Move\Hyrule Castle 802639EF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Yoshi's Island 8026E2B7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Sector Z 8026BF87 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn P1 Press Down On D-Pad To Make Items Appear In Random Spots D109EFA4 0400 8118D0A2 0001 cn Have All Characters 810A4938 0FF0 cn VS. Mode\Have Mushroom Kindom 800A4937 00FF cn Story Mode\Always Get Pacifist (60,000 Points) 810A4B6E 0000 cn Bonus Stage Character Modifier (Training Mode) cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 8018F1D3 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Enable Item Switch Menu (All Modes) cd Go into Vs Mode & then Vs Options & then Press Up On the D-Pad Or Analogue Stick & then click the A Button to enter the Item Switch Menu. This Cheat Works For All Modes 811348E2 0004 cn Story Mode\Player 1\Stage Select D1045188 0010 800A4AE7 ???? 0000:"Stage 1 (Vs Link)",0001:"Stage 2 (Vs Yoshi Team vs 18)",0002:"Stage 3 (Vs Fox McCloud)",0003:"Bonus Stage 1",0004:"Stage 4 (Freezes?)",0005:"Stage 5 (Vs Pikachu)",0006:"Stage 6 (Freezes?)",0007:"Bonus Stage 2",0008:"Stage 7 (Vs Kirby Team vs8)",0009:"Stage 8 (Vs Samus Aran)",000A:"Stage 9 (Vs Metal Mario)",000B:"Bonus Stage 3 (Race To The Finish)",000C:"Stage 10 (Fighting Polygon Team vs30)",000D:"Final Stage (Vs Master Hand)" crc A2E8F35B-C9DC87D9-C:45 gn Superman (U) cn Fly Through 1st & Last Ring Only To Complete Challenge 801442E9 0063 cn Infinite Freezing Breath 8122CDE8 42C8 cn Infinite Health 8122CDD4 42C8 cn Infinite Laser Eye 8122CDE4 42C8 cn Infinite Running Boosts 8122CDDC 42C8 cn Infinite X-Ray Vision 8122CDE0 42C8 crc 3C1FDABE-02A4E0BA-C:45 gn Tetrisphere (U) cn Single & VS Mode\Infinite Misses\Player 1 80112F9F 0003 cn Single & VS Mode\Infinite Misses\Player 2 80116207 0003 cn Single & VS Modes\Secret Cheat Menu 8011265F 00AD cn Single Player Stage Select 810E12DC 0001 crc 63E7391C-E6CCEA33-C:45 gn Tom and Jerry in Fists of Furry (U) cn Unlock All Characters cd This Gives you all Characters to choose from plus fixes A freeze on the Charecter Select Menu by having it on 810E44F2 00FF cn Open All Versus Arenas 810E44F4 03FF cn Infinite Health\Player 1 810E279C 42C8 cn One Hit To Kill\Player 1 810E2A74 3F80 cn One Hit To Kill\Player 2 810E2D4C 3F80 cn Always Have Weapon Options\Player 1 810E2994 ???? 0079:"Anvil",0003:"Club",0004:"Bird bath",0008:"Broom",0009:"NCube knife",000A:"NCube missiles",000B:"Chair",000C:"Champagne",000E:"Chicken",000F:"Crate",0014:"Deck chair",0016:"Egg",001A:"Fish",001D:"Gardeners Fork",001E:"Frying Pan",001F:"Wooden Chair",0029:"Bouy",002A:"Mallet",002B:"Watermelon",002D:"Milk Bottle",0039:"Plank",0041:"Rolling Pin",0046:"Spade",0047:"Stool",0048:"Tennis Racket",004E:"Spanner",0055:"Stick",0063:"Blue Swordfish",0064:"Saucepan",0065:"Wooden Spoon",006B:"Stool",006D:"Bee hive",0078:"Mooses head" cn Always Have Weapon Options\Player 2 810E2C6C ???? 0079:"Anvil",0003:"Club",0004:"Bird bath",0008:"Broom",0009:"NCube knife",000A:"NCube missiles",000B:"Chair",000C:"Champagne",000E:"Chicken",000F:"Crate",0014:"Deck chair",0016:"Egg",001A:"Fish",001D:"Gardeners Fork",001E:"Frying Pan",001F:"Wooden Chair",0029:"Bouy",002A:"Mallet",002B:"Watermelon",002D:"Milk Bottle",0039:"Plank",0041:"Rolling Pin",0046:"Spade",0047:"Stool",0048:"Tennis Racket",004E:"Spanner",0055:"Stick",0063:"Blue Swordfish",0064:"Saucepan",0065:"Wooden Spoon",006B:"Stool",006D:"Bee hive",0078:"Mooses head" cn Infinite Health\Player 2 810E2A74 42C8 cn Infinite Time 810FED4C 42F0 crc 392A0C42-B790E77D-C:45 gn RAINBOW SIX cn All Missions Unlocked 810C1F10 000B cn Infinite Health 8105518A 2400 cn Infinite Ammo 8103A180 2400 crc 204EC022-B119D185-C:45 gn Tony Hawk's Pro Skater (U) cn Officer Dick\Have All\Tapes 50000901 0000 800DDE08 00FF cn Officer Dick\Have All\Gold Medal\Burnside 800DDE0E 00FF cn Officer Dick\Have All\Gold Medal\Skate Park 800DDE0B 00FF cn Officer Dick\Have All\Gold Medal\Roswell 800DDE10 00FF cn Tony Hawk\Have All\Tapes 50000901 0000 800DDD40 00FF cn Player 1\Super Max\Balance 800D561F FFFF cn Tony Hawk\Have All\Gold Medal\Skate Park Chicago 800DDD43 00FF cn Tony Hawk\Have All\Gold Medal\Roswell 800DDD48 00FF cn Bob Burnquist\Have All\Tapes 50000901 0000 800DDD54 00FF cn Bob Burnquist\Have All\Gold Medal\Burnside Portland 800DDD5A 00FF cn Bob Burnquist\Have All\Gold Medal\Skate Park Chicago 800DDD57 00FF cn Bob Burnquist\Have All\Gold Medal\Roswell 800DDD5C 00FF cn Geoff Rowley\Have All\Tapes 50000901 0000 800DDD68 00FF cn Geoff Rowley\Have All\Gold Medal\Burnside Portland 800DDD6E 00FF cn Geoff Rowley\Have All\Gold Medal\Skate Park Chicago 800DDD6B 00FF cn Geoff Rowley\Have All\Gold Medal\Roswell 800DDD70 00FF cn Bucky Lasek\Have All\Tapes 50000901 0000 800DDD7C 00FF cn Bucky Lasek\Have All\Gold Medal\Burnside Portland 800DDD82 00FF cn Bucky Lasek\Have All\Gold Medal\Skate Park Chicago 800DDD7F 00FF cn Bucky Lasek\Have All\Gold Medal\Roswell 800DDD84 00FF cn Chad Muska\Have All\Tapes 50000901 0000 800DDD90 00FF cn Chad Muska\Have All\Gold Medal\Burnside Portland 800DDD96 00FF cn Chad Muska\Have All\Gold Medal\Skate Park Chicago 800DDD93 00FF cn Chad Muska\Have All\Gold Medal\Roswell 800DDD98 00FF cn Kareem Campbell\Have All\Tapes 50000901 0000 800DDDA4 00FF cn Kareem Campbell\Have All\Gold Medal\Burnside Portland 800DDDAA 00FF cn Kareem Campbell\Have All\Gold Medal\Skate Park Chicago 800DDDA7 00FF cn Kareem Campbell\Have All\Gold Medal\Roswell 800DDDAC 00FF cn Andrew Reynolds\Have All\Tapes 50000901 0000 800DDDB8 00FF cn Andrew Reynolds\Have All\Gold Medal\Burnside Portland 800DDDBE 00FF cn Andrew Reynolds\Have All\Gold Medal\Skate Park Chicago 800DDDBB 00FF cn Andrew Reynolds\Have All\Gold Medal\Roswell 800DDDC0 00FF cn Rune Glifberg\Have All\Tapes 50000901 0000 800DDDCC 00FF cn Rune Glifberg\Have All\Gold Medal\Burnside Portland 800DDDD2 00FF cn Rune Glifberg\Have All\Gold Medal\Skate Park Chicago 800DDDCF 00FF cn Rune Glifberg\Have All\Gold Medal\Roswell 800DDDD4 00FF cn Jamie Thomas\Have All\Tapes 50000901 0000 800DDDE0 00FF cn Jamie Thomas\Have All\Gold Medal\Burnside Portland 800DDDE6 00FF cn Jamie Thomas\Have All\Gold Medal\Skate Park Chicago 800DDDE3 00FF cn Jamie Thomas\Have All\Gold Medal\Roswell 800DDDE8 00FF cn Elissa Steamer\Have All\Tapes 50000901 0000 800DDDF4 00FF cn Elissa Steamer\Have All\Gold Medal\Burnside Portland 800DDDFA 00FF cn Elissa Steamer\Have All\Gold Medal\Skate Park Chicago 800DDDF7 00FF cn Elissa Steamer\Have All\Gold Medal\Roswell 800DDDFC 00FF cn Have All Tracks 813D6E42 FFFF 813D4FFA FFFF 813D5D62 FFFF 813D84E2 FFFF 813D4FCA FFFF 813D5F2A FFFF 813D8C52 FFFF 813D5602 FFFF 813D6D3A FFFF cn Player 1\Tony Hawk\Full Special All Levels D00C0223 0000 813D6576 02EE D00C0223 0001 813D4728 02EE D00C0223 0002 813D5496 02EE D00C0223 0003 813D7C16 02EE D00C0223 0004 813D467E 02EE D00C0223 0005 813D565E 02EE D00C0223 0006 813D8386 02EE D00C0223 0007 813D4D36 02EE D00C0223 0008 813D646E 02EE cn Player 1\Max Points\The Warehouse 813D6E42 FFFF cn Player 1\Max Points\The School 813D4FFA FFFF cn Player 1\Max Points\The Mall 813D5D62 FFFF cn Player 1\Max Points\The Skate Park 813D84E2 FFFF cn Player 1\Max Points\Downtown Chicago 813D4FCA FFFF cn Player 1\Super Max\Turning 800D5620 FFFF cn Player 2\Super Max\Ollie 800D5621 FFFF cn Player 2\Super Max\Speed 800D5622 FFFF cn Player 2\Super Max\Air 800D5623 FFFF cn Player 2\Super Max\Balance 800D5624 FFFF cn Player 2\Super Max\Turning 800D5625 FFFF cn Player 1\Play As 800D03D4 ???? 0000:"Tony Hawk",0001:"Bob Burnquist",0002:"Geoff Rowley",0003:"Bucky Lasek",0004:"Chad Muska",0005:"Kareem Campbell",0006:"Andrew Reynolds",0007:"Rune Glifberg",0008:"Jamie Thomas",0009:"Elissa Steamer",000A:"Officer Dick" cn Player 2\Play As 800D03D5 ???? 0000:"Tony Hawk",0001:"Bob Burnquist",0002:"Geoff Rowley",0003:"Bucky Lasek",0004:"Chad Muska",0005:"Kareem Campbell",0006:"Andrew Reynolds",0007:"Rune Glifberg",0008:"Jamie Thomas",0009:"Elissa Steamer",000A:"Officer Dick" cn Player 1\Have Perfect Balance 800DDB83 0001 cn Player 1\Max Trick Score\The Warehouse 813D6E42 FFFF cn Player 1\Max Trick Score\The School 813D4FFA FFFF cn Player 1\Max Trick Score\The Mall 813D5D62 FFFF cn Player 1\Max Trick Score\The Skate Park Course 813D84E2 FFFF cn Player 1\Max Trick Score\Downtown 813D4FCA FFFF cn Player 1\Max Trick Score\Downhill Jam 813D5F2A FFFF cn Player 1\Max Trick Score\Burnside 813D8C52 FFFF cn Player 1\Max Trick Score\The Streets 813D5602 FFFF cn Player 1\Max Trick Score\Roswell 813D6D3A FFFF crc 99150E18-1266E6A5-C:45 gn Tony Hawk's Pro Skater 2 (U) cn Infinte Time 810E87AA 0000 cn Unlock\Spider Man 800E9DD8 0001 800F0B9B 0001 cn Unlock\Officer Dick 800E9DDC 0001 800F087B 0001 cn 1 Million Points 8119054C 000F 8119054E 4240 cn All Gaps\Hanger 800E9CC5 00FF 810E9CC6 FFFF cn All Gaps\Marseille 810E9CDC FFFF 810E9CDE FFFF 800E9CE3 000F cn All Gaps\Philadelphia 810E9D0C FFFF 810E9D0E FFFF 810E9D12 0FFF cn All Gaps\School II 810E9CD0 FFFF 810E9CD2 FFFF 810E9CD6 0FFF cn All Gaps\Skatestreet 810E9D00 FFFF 810E9D02 FFFF 800E9D07 000F cn All Gaps\Venice Beach 810E9CF4 FFFF 810E9CF6 FFFF 810E9CFA 0FFF cn All Tricks Available\Custom Player 1 810E9454 FFFF 810E9456 FFFF 810E9458 FFFF 810E945A FFFF 810E945C FFFF 810E945E FFFF cn All Tricks Available\Custom Player 2 810E9538 FFFF 810E953A FFFF 810E953C FFFF 810E953E FFFF 810E9540 FFFF 810E9542 FFFF cn All Tricks Available\Custom Player 3 810E961C FFFF 810E961E FFFF 810E9620 FFFF 810E9622 FFFF 810E9624 FFFF 810E9626 FFFF cn All Tricks Available\Custom Player 4 810E9700 FFFF 810E9702 FFFF 810E9704 FFFF 810E9706 FFFF 810E9708 FFFF 810E970A FFFF cn Tricks Available\Bob Burnquist 810E89A4 FFFF 810E89A6 FFFF 810E89A8 FFFF 810E89AA FFFF 810E89AC FFFF 810E89AE FFFF cn Tricks Available\Chad Muska 810E8FE0 FFFF 810E8FE2 FFFF 810E8FE4 FFFF 810E8FE6 FFFF 810E8FE8 FFFF 810E8FEA FFFF cn Tricks Available\Eric Koston 810E8D34 FFFF 810E8D36 FFFF 810E8D38 FFFF 810E8D3A FFFF 810E8D3C FFFF 810E8D3E FFFF cn Tricks Available\Elissa Steamer 810E928C FFFF 810E928E FFFF 810E9290 FFFF 810E9292 FFFF 810E9294 FFFF 810E9296 FFFF cn Tricks Available\Geoff Rowley 810E91A8 FFFF 810E91AA FFFF 810E91AC FFFF 810E91AE FFFF 810E91B0 FFFF 810E91B2 FFFF cn Tricks Available\Jamie Thomas 810E9370 FFFF 810E9372 FFFF 810E9374 FFFF 810E9376 FFFF 810E9378 FFFF 810E937A FFFF cn Tricks Available\Kareem Campbell 810E8B6C FFFF 810E8B6E FFFF 810E8B70 FFFF 810E8B72 FFFF 810E8B74 FFFF 810E8B76 FFFF cn Tricks Available\Officer Dick 810E97E4 FFFF 810E97E6 FFFF 810E97E8 FFFF 810E97EA FFFF 810E97EC FFFF 810E97EE FFFF cn Tricks Available\Rune Glifberg 810E8C50 FFFF 810E8C52 FFFF 810E8C54 FFFF 810E8C56 FFFF 810E8C58 FFFF 810E8C5A FFFF cn Tricks Available\Rodney Mullen 810E8EFC FFFF 810E8EFE FFFF 810E8F00 FFFF 810E8F02 FFFF 810E8F04 FFFF 810E8F06 FFFF cn Tricks Available\Steve Caballero 810E8A88 FFFF 810E8A8A FFFF 810E8A8C FFFF 810E8A8E FFFF 810E8A90 FFFF 810E8A92 FFFF cn Tricks Available\Spider Man 810E99AC FFFF 810E99AE FFFF 810E99B0 FFFF 810E99B2 FFFF 810E99B4 FFFF 810E99B6 FFFF cn Tricks Available\Tony Hawk 810E88C0 FFFF 810E88C2 FFFF 810E88C4 FFFF 810E88C6 FFFF 810E88C8 FFFF 810E88CA FFFF cn Tricks Available\Andrew Reynolds 810E90C4 FFFF 810E90C6 FFFF 810E90C8 FFFF 810E90CA FFFF 810E90CC FFFF 810E90CE FFFF cn Max Cash\Officer Dick 810E975C 000F 810E975E 423F 810E9760 000F 810E9762 423F cn Max Cash\Andrew Reynolds 810E903C 000F 810E903E 423F 810E9040 000F 810E9042 423F cn Max Cash\Bob Burnquist 810E891C 000F 810E891E 423F 810E8920 000F 810E8922 423F cn Max Cash\Bucky Lasek 810E8D90 000F 810E8D92 423F 810E8D94 000F 810E8D96 423F cn Max Cash\Chad Muska 810E8F58 000F 810E8F5A 423F 810E8F5C 000F 810E8F5E 423F cn Max Cash\Eric Koston 810E8CAC 000F 810E8CAE 423F 810E8CB0 000F 810E8CB2 423F cn Max Cash\Elissa Steamer 810E9204 000F 810E9206 423F 810E9208 000F 810E920A 423F cn Max Cash\Geoff Rowley 810E9120 000F 810E9122 423F 810E9124 000F 810E9126 423F cn Max Cash\Jamie Thomas 810E92E8 000F 810E92EA 423F 810E92EC 000F 810E92EE 423F cn Max Cash\Kareem Campbell 810E8AE4 000F 810E8AE6 423F 810E8AE8 000F 810E8AEA 423F cn Max Cash\Rune Glifberg 810E8BC8 000F 810E8BCA 423F 810E8BCC 000F 810E8BCE 423F cn Max Cash\Rodney Mullen 810E8E74 000F 810E8E76 423F 810E8E78 000F 810E8E7A 423F cn Max Cash\Steve Caballero 810E8A00 000F 810E8A02 423F 810E8A04 000F 810E8A06 423F cn Max Cash\Custom Player 1 810E93CC 000F 810E93CE 423F 810E93D0 000F 810E93D2 423F cn Max Cash\Custom Player 2 810E94B0 000F 810E94B2 423F 810E94B4 000F 810E94B6 423F cn Max Cash\Custom Player 3 810E9594 000F 810E9596 423F 810E9598 000F 810E959A 423F cn Max Cash\Custom Player 4 810E9678 000F 810E967A 423F 810E967C 000F 810E967E 423F cn All Complete\Bob Burnquist 810E8924 FFFF 810E8926 FFFF 810E8928 FFFF 810E892A FFFF 810E892C FFFF 810E892E FFFF 810E8930 FFFF 810E8932 FFFF cn All Complete\Tony Hawk 810E8840 FFFF 810E8842 FFFF 810E8844 FFFF 810E8846 FFFF 810E8848 FFFF 810E884A FFFF 810E884C FFFF 810E884E FFFF cn Always Special On Cheat 800E9DEC 0001 cn Perfect Balance Cheat 800E9DE8 0001 cn Unlock Hoffman Factory & Skate Heaven 800EA0CB 003F cn Access In-Game Cheat Menu 50001104 0000 800E9DD8 0001 crc 1A7F70B5-00B7B9FD-C:45 gn Tony Hawk's Pro Skater 3 (U) cn Tony Hawk\All Levels Open,Gold Medals & Goals Compleated 800ED8F8 00FF 50001001 0000 800ED908 00FF cn Tony Hawk\Have all 5of5 Stat Points & All Decks 50000F04 0000 800ED934 00FF cn Steve Caballero\All Levels Open,Gold Medals & Goals Compleated 800ED9D4 00FF 50001001 0000 800ED9E4 00FF cn Steve Caballero\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EDA10 00FF cn Kareem Campbell\All Levels Open,Gold Medals & Goals Compleated 800EDAB0 00FF 50001001 0000 800EDAC0 00FF cn Kareem Campbell\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EDAEC 00FF cn Rune Glifberg\All Levels Open,Gold Medals & Goals Compleated 800EDB8C 00FF 50001001 0000 800EDB9C 00FF cn Rune Glifberg\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EDBC8 00FF cn Eric Koston\All Levels Open,Gold Medals & Goals Compleated 800EDC68 00FF 50001001 0000 800EDC78 00FF cn Eric Koston\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EDCA4 00FF cn Bucky Lasek\All Levels Open,Gold Medals & Goals Compleated 800EDD44 00FF 50001001 0000 800EDD54 00FF cn Bucky Lasek\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EDD80 00FF cn Rodney Mullen\All Levels Open,Gold Medals & Goals Compleated 800EDE20 00FF 50001001 0000 800EDE30 00FF cn Rodney Mullen\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EDE5C 00FF cn Chad Muska\All Levels Open,Gold Medals & Goals Compleated 800EDEFC 00FF 50001001 0000 800EDF0C 00FF cn Chad Muska\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EDF38 00FF cn Andrew Rynolds\All Levels Open,Gold Medals & Goals Compleated 800EDFD8 00FF 50001001 0000 800EDFE8 00FF cn Andrew Rynolds\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE014 00FF cn Geoff Rowley\All Levels Open,Gold Medals & Goals Compleated 800EE0B4 00FF 50001001 0000 800EE0C4 00FF cn Geoff Rowley\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE0F0 00FF cn Elissa Steamer\All Levels Open,Gold Medals & Goals Compleated 800EE190 00FF 50001001 0000 800EE1A0 00FF cn Elissa Steamer\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE1CC 00FF cn Jamie Thomas\All Levels Open,Gold Medals & Goals Compleated 800EE26C 00FF 50001001 0000 800EE27C 00FF cn Jamie Thomas\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE2A8 00FF cn Bam Margera\All Levels Open,Gold Medals & Goals Compleated 800EE348 00FF 50001001 0000 800EE358 00FF cn Bam Margera\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE384 00FF cn Skater A\All Levels Open,Gold Medals & Goals Compleated 800EE424 00FF 50001001 0000 800EE434 00FF cn Skater A\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE460 00FF cn Skater B\All Levels Open,Gold Medals & Goals Compleated 800EE500 00FF 50001001 0000 800EE510 00FF cn Skater B\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE53C 00FF cn Skater C\All Levels Open,Gold Medals & Goals Compleated 800EE5DC 00FF 50001001 0000 800EE5EC 00FF cn Skater C\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE618 00FF cn Officer Dick\All Levels Open,Gold Medals & Goals Compleated 800EE6B8 00FF 50001001 0000 800EE6C8 00FF cn Officer Dick\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE6F4 00FF cn Wolverine\All Levels Open,Gold Medals & Goals Compleated 800EE794 00FF 50001001 0000 800EE7A4 00FF cn Wolverine\Have all 5of5 Stat Points & All Decks 50000F04 0000 800EE7D0 00FF cn Infinite Stat Upgrades & Deck Boards to Buy cd This allows you to ugrade you stats in Upgrades to the Max & Also to open the Boards in Decks For All Characters. 800ED8F9 00FF 800ED905 00FF 800EDD45 00FF 800EDD51 00FF 800EDFE5 00FF 800EDFD9 00FF 800ED9D5 00FF 800ED9E1 00FF 800EDAB1 00FF 800EDABD 00FF 800EDB8D 00FF 800EDB99 00FF 800EDC69 00FF 800EDC75 00FF 800EDE21 00FF 800EDE2D 00FF 800EDEFD 00FF 800EDF09 00FF 800EE0B5 00FF 800EE0C1 00FF 800EE191 00FF 800EE19D 00FF 800EE26D 00FF 800EE279 00FF 800EE349 00FF 800EE355 00FF 800EE425 00FF 800EE431 00FF 800EE501 00FF 800EE50D 00FF 800EE5DD 00FF 800EE5E9 00FF 800EE6B9 00FF 800EE6C5 00FF 800EE795 00FF 800EE7A1 00FF cn Play As 800E9D69 ???? 0000:"Tony Hawk",0001:"Steve Caballero",0002:"Kareem Campbell",0003:"Rune Glifberg",0004:"Eric Koston",0005:"Bucky Lasek",0006:"Rodney Mullen",0007:"Chad Muska",0008:"Andrew Rynolds",0009:"Geoff Rowley",000A:"Elissa Steamer",000B:"Jamie Thomas",000C:"Bam Margera",000D:"Skater A",000E:"Skater B",000F:"Skater C",0010:"Officer Dick",0011:"Wolverine" cn Timer Starts Off At 20 Mins 800E9D64 FFFF cn Play On Level cd This allows you to play on a level even if it isnt already open just choose & tick choose foundary or what ever level & play the one you selected 800ED58F ???? 0000:"Foundary",0001:"Los Angeles",0002:"Rio De Janeiro",0003:"Suburbia",0004:"Airport",0005:"Skater Island",0006:"Canada",0007:"Tokyo",0008:"Downhill",0009:"Custom" crc 8ECC02F0-7F8BDE81-C:45 gn Top Gear Hyper-Bike (U) cn Access All\Bikes 810FBCBE FFFF cn Access All\Tracks 810FBCC2 FFFF cn Infinite\Nitro 810B8E4C 42C8 cn Infinite\Nitro Always On 810BB5A4 8004 cn Laps 2 Race 8016FC88 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" crc D741CD80-ACA9B912-C:45 gn Top Gear Overdrive (U) cn Extra Cars & Tracks 801022F0 0001 5000020A 0000 801022F1 000E 811022E8 0501 50000302 0000 811022EA 0101 cn Infinite Money 810F50C4 270F cn Infinite Nitro 810F50CE 0009 cn Laps 2 Race 801185E0 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Level Modifier (Championship & Vs Mode) 8011D0B0 ???? 0000:"Frigid Peaks - Snowy/Daytime",0001:"Fertile Canyon - Day/Lightning",0002:"Swampy Depot - Day/Rainbow",0003:"Downtown - Clear/Rainbow",0004:"Sandy Beaches - Day/Lightning",0005:"Fertile Canyon - Night" crc 62269B3D-FE11B1E8-C:45 gn Top Gear Rally (U) cn Have 1-6 Level Points 50000602 0000 8032685F 0064 cn Extra Cars & Tracks 50000201 0000 8032690C 00FF 8032690F 00FF 813243CC FFFF cn Only Race 1 Lap Championship Mode 8031EBDB 0002 cn Always Place 1st 8131C70E 0000 crc BE5973E0-89B0EDB8-C:45 gn Top Gear Rally 2 (U) cn Always 1st 810318E2 0001 cn No Damage Or Failures 81030D76 0001 cn 100.000 Sponsor Credits & 950 Championship Points In Support Van cd You Also Have Access To All Cars, Tracks & Extra Features 80030D82 00F3 cn No Cones Hit cd In ARSG Rally School 81031CEA 0000 cn No Navigator 80032677 0000 cn Max Sponsor Credits 81033816 270F cn Infinite Time & Always Place 1st cd Championship Mode Only. 810318EE 0001 cn Max Sponsor Points & Extra Cars & Tracks cd This code gives you all tracks and cars. once you activate this code, You must make an internal save (Native) in options & then load that internal save, & go to Drivers Board to pick your car, Then to Race to pick your track 81033816 270F crc A150743E-CF2522CD-C:45 gn Toy Story 2 (U) cn Have 99 coins 810BB10E 0063 cn Have all 5 collectables 801C7A72 0005 cn Infinite Lives 800BB10A 0009 cn Infinite Battery Power 810BB106 000E cn Hold jump to fly 810BB0FC 0002 crc 2F70F10D-5C4187FF-C:45 gn Turok: Dinosaur Hunter (U) (v1.0) cn Infinite\Body Armor 81128CE6 5B23 80128D27 0001 cn Infinite\Air 81129030 AAE1 811E85EA F1FF cn Have\All Level Keys 50000604 0000 80128D33 0007 80128D4B 001F 80128D6B 00FF cn Have\All Weapons 50000B04 0000 80128CF7 0001 80128D23 0001 cn Infinite\Ammo 50000404 0000 80128CB3 00FF 80128CC3 00FF 80128CCF 00FF 50000504 0000 80128CD3 00FF 80128E5B 00FF 80128E57 00FF cn Diffuculty Modifier 801195DF ???? 0000:"Easy",0001:"Normal",0002:"Hard" cn Infinite\Health 812C1584 1E61 812A24F4 1E61 cn Have\Backpack 80128CEB 0001 80128D2B 0001 cn Open All Portals cd Press L to Access Map 8114F8CA F803 50000604 0000 81128D4E 0003 81128D66 0005 cn Infinite\Lives 8005E689 0098 8105E6A0 2400 8005E6AD 0083 cn Have\Cheat Menu 81119540 FFFF 81119542 FFFF crc 2F700DCD-176CC5C9-C:45 gn Turok: Dinosaur Hunter (U) (v1.1) cn Infinite\Body Armor 81128E36 5B23 80128E77 0001 cn Infinite\Air 81129180 AAE1 811E873A F1FF cn Have\All Level Keys 50000604 0000 80128E83 0007 80128E9B 001F 80128EBB 00FF cn Have\All Weapons 50000B04 0000 80128E47 0001 80128E73 0001 cn Infinite\Ammo 50000404 0000 80128E03 00FF 80128E13 00FF 80128E1F 00FF 50000504 0000 80128E23 00FF 80128FAB 00FF 80128FA7 00FF cn Diffuculty Modifier 8011972F ???? 0000:"Easy",0001:"Normal",0002:"Hard" cn Infinite\Health 812C16D4 1E61 812A2644 1E61 cn Have\Backpack 80128E3B 0001 80128E7B 0001 cn Open All Portals cd Press L to Access Map 8114FA1A F803 81128E9E 0003 81128EA2 0003 81128EA6 0003 81128EAA 0003 81128EAE 0003 81128EB2 0003 81128EB6 0005 cn Infinite\Lives 8005E7D9 0098 8105E7F0 2400 8005E7FD 0083 cn Have\Cheat Menu 81119690 FFFF 81119692 FFFF crc ADB9498B-DAF28F55-C:45 gn Turok: Rage Wars (U) cn Player 1\Have All\Mini Game Icons 800FCB17 0024 cn Player 1\Infinite\Proximity Mines 8033653D 00FF cn Player 1\Infinite\Metal Claws 80336541 00FF cn Player 1\Infinite\Sentry Guns 8033653F 00FF cn Player 1\Infinite\Cerebral Bores 8033653B 00FF cn Player 1\Infinite\Health 81336526 6400 80692B86 0064 cn Player 1\Infinite Ammo 80336535 0063 80336537 0063 80336539 0063 80692B95 0063 80692B97 0063 80692B99 0063 80692B9B 0063 80692B9D 0063 80692B9F 0063 80692BA1 0063 cn Player 1\Play As 80140358 ???? 0000:"Turok",0001:"Mantid",0002:"Drone",0003:"Fireborn",0004:"Soldier",0005:"Adon",0006:"Lord Of The Dead",0007:"Elite Guard",0008:"Blind One",0009:"Juggernaut",000A:"Death Guard",000B:"Bastile",000C:"Syra",000D:"Symbiont",000E:"Tail Set",000F:"Pur-Lin",0010:"Symbiont",0011:"Raptor",0012:"Mites",0013:"Monkey" cn Level Select\Proving Ground-Tightrope cd Do Not use this with Level Select The Pit-Starlight. Only use One Level Select Option At A Time 8014BD9F ???? 0000:"Proving Grounds",0001:"Basic Training",0002:"Crossroads",0003:"Grim Retreat",0004:"Cathedral",0005:"Fall Out",0006:"Boxed Set",0007:"Dire Straight",0008:"Prey",0009:"Warehouse",000A:"Water Temple",000B:"Bomb Shelter",000C:"Tempered",000D:"Earth Temple",000E:"Fire Temple",000F:"Mystic",0010:"Bottleneck",0011:"Tightrope" cn Level Select\The Pit-Starlight cd Do Not use this with Level Select Proving Ground-Tightrope. Only use One Level Select Option At A Time 8014BD9F ???? 0012:"The Pit",0013:"Leap Of Faith",0014:"Wicked Dance",0015:"Bunker",0016:"Ampatheater",0017:"Fire Walker",0018:"Crypts",0019:"Breakdown",001A:"Retaliation",001B:"Hopeless",001C:"Matrix",001D:"Fathom",001E:"The Pedestal",001F:"Defcon 5",0020:"Spirit Temple",0021:"Stronghold",0022:"Courtyard",0023:"Starlight" cn Player 1\Infinite\Time 811407F4 47AF 811407F6 C4B1 cn Player 1\Have All\Medals 810FCB4A FFFF 810FCB4C FFFF 810FCB4E FFFF 800FCB50 0003 cn Player 1\Start With Weapon 803366B0 ???? 0000:"Warhammer",0001:"Boomerang",0002:"Tek Crossbow",0003:"Mag 60",0004:"Shotgun",0005:"Assault Rifle",0006:"Mini Gun",0007:"Plasma Rifle",0008:"Freeze Gun",0009:"Flaregun",000A:"Grenade Launcher",000B:"Scorpion Launcher",000C:"Napalm Gel",000D:"Emaciator",000E:"Inflator",000F:"Chest Burster",0010:"Raptor Claw",0011:"Mite Bite",0012:"Cerebral Bore",0013:"PFM Mine",0014:"Iron Claw",0015:"Sentry Turret" crc E8C95AFC-35D121DA-C:45 gn Turok 2: Seeds of Evil (U) (Kiosk) cn Infinite\Health 80305446 0064 80648FA6 0064 cn 99 Gems 80305449 0063 80648FA9 0063 cn Infinite\Ammo 50000302 0000 81305868 0063 50000304 0000 81305872 0063 5000020E 0000 81305882 0063 50000302 0000 816493C8 0063 50000304 0000 816493D2 0063 5000020E 0000 816493E2 0063 crc 49088A11-6494957E-C:45 gn Turok 2: Seeds of Evil (U) cn Player 1\Have All\Weapons D12FC912 0000 812FC912 0101 D12FC914 0000 812FC914 0101 D12FC916 0000 812FC916 0101 D12FC918 0000 812FC918 0101 D12FC91A 0000 812FC91A 0101 D12FC91C 0000 812FC91C 0101 D12FC91E 0000 812FC91E 0101 D12FC920 0000 812FC920 0101 D12FC922 0000 812FC922 0101 D12FC924 0000 812FC924 0101 D12FC926 0000 812FC926 0101 D12FC928 0000 812FC928 0101 D12FC92A 0000 812FC92A 0101 D12FC92C 0000 812FC92C 0101 D12FC92E 0000 812FC92E 0101 D12FC930 0000 812FC930 0101 D12FC932 0000 812FC932 0101 806FE742 0001 806FE743 0001 806FE744 0001 806FE745 0001 806FE746 0001 806FE747 0001 806FE748 0001 806FE749 0001 806FE74A 0001 806FE74B 0001 806FE74C 0001 806FE74D 0001 806FE74E 0001 806FE74F 0001 806FE750 0001 806FE751 0001 806FE752 0001 806FE753 0001 806FE754 0001 806FE756 0001 806FE757 0001 806FE758 0001 806FE759 0001 806FE75A 0001 806FE75B 0001 806FE75C 0001 806FE75E 0001 806FE75F 0001 806FE760 0001 806FE761 0001 806FE762 0001 806FE763 0001 806FE764 0001 cn Player 1\Infinite\Health 812FC4C6 0064 816FE2F6 6400 cn Player 1\99 Gems 812FC4C8 0063 806FE2F8 0063 cn Player 1\Infinite\Ammo 802FC499 0000 50000302 0000 812FC8D4 0063 812FC8DE 0063 812FC8E2 0063 50000A02 0000 812FC8E6 0063 50000302 0000 816FE704 0063 816FE70E 0063 816FE712 0063 50000802 0000 816FE716 0063 816FE72C 0063 816FE730 0063 cn Player 1\Have All\Keys,Nuke,Evrything 802FC602 0030 802FC60C 0030 802FC616 0030 802FC620 0030 50000601 0000 802FC634 0030 50000501 0000 802FC648 0030 50000401 0000 802FC65C 0030 50000601 0000 802FC99C 0030 802FC4E0 0033 802FC4E5 0033 802FC4EA 0033 802FC594 0033 802FC530 0033 802FC53A 0033 802FC53B 0033 802FC5B0 0033 802FC5B1 0033 802FC5B2 0033 802FC5B3 0033 806FE432 0030 806FE43C 0030 806FE446 0030 806FE450 0030 50000601 0000 806FE464 0030 50000501 0000 806FE478 0030 50000501 0000 806FE48C 0030 50000601 0000 806FE4CC 0030 806FE310 0033 806FE315 0033 806FE31A 0033 806FE360 0033 806FE36A 0033 806FE36B 0033 806FE3C4 0033 50000401 0000 806FE3E0 0033 50000601 0000 8059D61A 0001 50000D01 0000 8059D620 0001 50000401 0000 8059D62E 0001 cn Player 2\Infinite\Health 812F723E 0064 8059D1CE 0064 cn Player 2\Infinite\Ammo 50000602 0000 812F767C 0063 812F764C 013C 812F764E 013C 50000302 0000 812F7654 013C 812F7660 013C 812F7664 013C 812F766A 013C 812F766C 013C 812F7674 013C 812F7678 013C 8159D5DC 013C 8159D5DE 013C 8159D5E4 013C 8159D5E8 013C 8159D5EA 013C 8159D5F0 013C 8159D5F4 013C 8159D5FA 013C 8159D5FC 013C 8159D604 013C 8159D608 013C 50000602 0000 8159D60C 013C cn Player 2\99 Gems 812F7240 0063 crc 89A579F1-667E97EF-C:45 gn Turok 3: Shadow of Oblivion (U) cn Have PSG 8033343A 0001 cn Have Cerebral Bore 80333437 0001 cn Have All Secrets 811659C6 FFFF 811659C4 FFFF cn Have Grenade Launcher 80333434 0001 cn Infinite Life Force 813334FC 0063 cn Infinite Health 81332FDA 6400 cn Infinite Arrows 81333408 0064 cn Infinite Pistol Ammo 8133340E 0063 cn Infinite Shotgun Ammo 81333412 0064 cn Infinite Grenade Gun Ammo 8133340A 0064 cn Infinite Firestorm Cannon Ammo 81333410 0064 cn Have Pistol 8033342A 0001 cn Have Shotgun 80333430 0001 crc 033F4C13-319EE7A7-C:45 gn World is Not Enough, The (U) cn Have All\Levels Unlocked cd For Single Player Mode Only 81102EE6 0021 cn Invincibility On All levels 81112F68 0101 cn Skip Intro, D03B0E5F 0004 803B0E5F 0009 cn Level select 803B0E5F 0009 cn Infinite\Ammo On All Levels 810648DC 2400 cn Have All\Guns On All Levels cd Once you pick up a Gun You will have all weapons 8105F224 0810 8105F226 0000 8105F228 2442 8105F22A 0001 81400000 3C02 81400002 0100 81400004 2442 81400006 0063 81400008 AE82 8140000A 0288 8140000C AE82 8140000E 0298 81400010 AE82 81400012 02A0 81400014 AE82 81400016 02A8 81400018 AE82 8140001A 02B0 8140001C AE82 8140001E 02C0 81400020 AE82 81400022 02C8 81400024 AE82 81400026 02D0 81400028 AE82 8140002A 02D8 8140002C AE82 8140002E 02E8 81400030 AE82 81400032 02F0 81400034 AE82 81400036 02F8 81400038 AE82 8140003A 0300 8140003C AE82 8140003E 0308 81400040 AE82 81400042 0310 81400044 AE82 81400046 0320 81400048 AE82 8140004A 0330 8140004C AE82 8140004E 0338 81400050 AE82 81400052 0350 81400054 AE82 81400056 0358 81400058 AE82 8140005A 0360 8140005C AE82 8140005E 0370 81400060 AE82 81400062 0378 81400064 AE82 81400066 0380 81400068 AE82 8140006A 0388 8140006C AE82 8140006E 0340 81400070 AE82 81400072 0348 81400074 AE82 81400076 0350 81400078 0801 8140007A 7C8C 8140007C A077 8140007E 01FC cn Time Taken Clock At 0:00 80102F02 0000 cn Infinite\Time cd Underground Uprising 8138EE3A 19B8 cn Have All\Skins + Everyone is Evil 50005C0C 0000 800BF687 0081 cn Have All\Gadgets 80112F6D 0001 cn Go Solo In Multiplayer D00E0778 0042 801002B7 0001 cn Stop Bond From Going Downhill on Cold Reception cd Press L to Stop, & R to Go D10E0778 0020 803A8466 0001 D10E0778 0010 803A8466 0000 cn Fail Objectives To Complete Them 810315B8 2402 810315BA 0011 cn Infinite\Ammo On Clip, 810649AC 2400 cn Have Tons Of Nightvision cd For Battery Only 81064C82 1500 cn Play Crate Yard Level 80102EDF 0008 crc BBC99D32-117DAA80-C:45 gn TWISTED EDGE cn Max\50000 Stunt Points 810829B8 C350 cn Low Timer 801495FF 0000 80149601 0000 cn Have\All Characters 810829F8 07FF cn Have\All Difficulties 810829F0 0700 cn Have\All Tracks 810829FC BFFE cn Have\All Boards 81082A04 0003 81082A06 FFFF crc EA71056A-E4214847-C:45 gn Vigilante 8 (U) cn All Characters & Levels 81181572 01C0 cn Have All Cars 50000D01 0000 80191298 001F cn Level Select 80190150 ???? 0000:"Super Dreamland 64",0001:"Secret Base",0002:"Sand Factory",0003:"Oil Fields",0004:"Aircraft Graveyard",0005:"Ghost Town",0006:"Hoover Dam",0007:"Valley Farms",0008:"Casino City",0009:"Canyonlands",000A:"Ski Resorts" cn Play As\Player 1 80186AE0 ???? 0000:"Chassey Blue",0001:"Slick Clyde",0002:"Sheila",0003:"John Torque",0004:"Dave",0005:"Convoy",0006:"Loki",0007:"Houston 3",0008:"Boogie",0009:"Beezwax",000A:"Molo",000B:"Sid Burn",000C:"\"Y\" The Alien" cn Play As\Player 2 80186AE1 ???? 0000:"Chassey Blue",0001:"Slick Clyde",0002:"Sheila",0003:"John Torque",0004:"Dave",0005:"Convoy",0006:"Loki",0007:"Houston 3",0008:"Boogie",0009:"Beezwax",000A:"Molo",000B:"Sid Burn",000C:"\"Y\" The Alien" crc F5C5866D-052713D9-C:45 gn Vigilante 8 - 2nd Offense (U) cn All Quests Complete\Player 1 5000120A 0000 81197FF0 01FF cn All Characters\Have Max\Attributes\Player 1 5000120A 0000 81197FF6 6464 5000120A 0000 81197FF8 6464 cn All Characters\Have Max\Acceleration\Player 1 50000C0A 0000 80197FF6 0064 cn All Characters\Have Max\Speed\Player 1 5000120A 0000 80197FF7 0064 cn All Characters\Have Max\Armor\Player 1 5000120A 0000 80197FF8 0064 cn All Characters\Have Max\Target Avoidance\Player 1 5000120A 0000 80197FF9 0064 cn All Quests Complete\Player 2 5000120A 0000 811980A4 01FF cn All Characters\Have Max\Attributes\Player 2 5000120A 0000 811980AA 6464 5000120A 0000 811980AC 6464 cn All Characters\Have Max\Acceleration\Player 2 5000120A 0000 801980AA 0064 cn All Characters\Have Max\Speed\Player 2 5000120A 0000 801980AB 0064 cn All Characters\Have Max\Armor\Player 2 5000120A 0000 801980AC 0064 cn All Characters\Have Max\Target Avoidance\Player 2 5000120A 0000 801980AD 0064 crc 82B3248B-E73E244D-C:45 gn Virtual Chess 64 (U) cn Debug Mode 810E6290 0001 cn Time Always Counts Down\On Black Players Side 8012C67D 0001 cn Time Always Counts Down\On White Players Side 8012C67D 0000 cn Always Play On\2D Board 800E7257 0001 cn Always Play On\3D Board 800E7257 0000 cn Player 1 Controls\Both Sides In 2-Player cd This is only for Human VS. Human Game 8012C508 0000 crc 4E4A7643-A37439D7-C:45 gn Virtual Pool 64 (U) cn Always Your Turn\Player 1 802EF798 0000 cn Always Your Turn\Player 2 802EF798 0001 cn Ball\Always In Hand 802EF79C 0002 cn Max Ratings\Player 1 81062C6A FFFF cn Max Ratings\Player 2 81062CEE FFFF cn Wins Options\Player 1 812EF780 ???? 0000:"Zero Points",FFFF:"Max Points" cn Wins Options\Player 2 812EF782 ???? 0000:"Zero Points",FFFF:"Max Points" cn Foul Score Options\Player 1 812EF784 ???? 0000:"Zero Fouls",FFFF:"Max Fouls" cn Foul Score Options\Player 2 812EF786 ???? 0000:"Zero Fouls",FFFF:"Max Fouls" cn Aiming Sites Always Available 812F0922 0004 crc 3C059038-C8BF2182-C:45 gn V-Rally Edition 99 (U) cn Enable All\Cars 80140D1F 003F cn Enable All\Tracks 80140D1A 0070 cn Unlock Champ 80140D28 0001 cn Enable All\Expert Times 80140D1C 0031 cn Unlock Cheat Menu D11B1F14 0000 811B1F14 00FF 811D530A 04FF D11B1F14 00FF 811B0270 FF03 crc 8066D58A-C3DECAC1-C:45 gn Waialae Country Club - True Golf Classics (U) cn Max Power 8012A431 FFFF cn Max Technique 8012A433 FFFF cn Max Putt 8012A435 FFFF cn Max Recover 8012A437 FFFF cn Select Club 801DA496 ???? 0000:"1W",0001:"2W",0002:"3W",0003:"4W",0004:"5W",0005:"1I",0006:"2I",0007:"3I",0008:"4I",0009:"5I",000A:"6I",000B:"7I",000C:"8I",000D:"9I",000E:"PW",000F:"AW",0010:"SW",0011:"Putter" cn Always On First Shot 811DA47A 0001 cn Club Type\Woods Mods 8012A472 ???? 0000:"Titan",0001:"Metal Wood",0002:"Persimmon" cn Club Type\Irons Mods 8012A473 ???? 0000:"Cavity",0001:"Conventional" cn Club Type\Sand Wedge Mods 8012A474 ???? 0000:"58 Degrees",0001:"60 Degrees",0002:"62 Degrees" crc F7FE28F6-C3F2ACC3-C:45 gn War Gods (U) cn Cheat Menu 80336593 0001 cn Unlimited Time 8033F31B 0063 cn Infinite Credits 81336582 0005 8133658E 0004 crc 7DE11F53-74872F9D-C:45 gn Wave Race 64 (U) (v1.0) cn Misses Don't Count 801C27CF 0000 cn Infinite Time Stunt Mode 801C295E 00FF cn Super Speed 801C27C7 0005 D0154051 0010 801C27C7 0020 cn 99 Points 801CB0A3 0063 cn Infinite Course Out Time 801C2983 00FF cn Maximum Power\Player 1 801C27C7 0005 cn Maximum Power\Player 2 801C2DEA 0005 801C308A 0005 cn Only Play Glacier Coast 800DA753 0007 cn Open\Difficulty Option 801CAFE0 ???? 0001:"Hard",0002:"Expert",0003:"Hard & Expert",0010:"Dolphin",0011:"Dolphin & Hard",0012:"Dolphin & Expert",0013:"Dolphin Hard & Expert" cn Open\Level Option 800DA753 ???? 0002:"Sunset Bay",0003:"Above & Drake Lake",0004:"All Above & Marine Fortress",0005:"All Above & Port Blue",0006:"All Above & Southern Island",000D:"All Above & Twilight City",0016:"All Above & Glacier Coast" cn Open\Course Option cd This works in all modes except for Championship Mode. 801CAFEB ???? 0000:"Dolphin Park",0001:"Sunny Beach",0002:"Sunset Bay",0003:"Drake Lake",0004:"Marian Fortress",0005:"Port Blue",0006:"Twilight City",0007:"Glacier Coast",0008:"Southern Island" cn Always First Place 801C269F 0000 crc 492F4B61-04E5146A-C:45 gn Wave Race 64 (U) (v1.1) cn Misses Don't Count 801C2A6F 0000 cn Infinite Time Stunt Mode 801C2BFE 00FF cn Super Speed 801C2A67 0005 D01CE659 0010 801C2A67 0020 cn 99 Points 801CB343 0063 cn Infinite Course Out Time 801C2C03 00FF cn Maximum Power\Player 1 801C2A67 0005 8013FC91 0005 cn Maximum Power\Player 2 801C308A 0005 801C392D 0005 cn Only Play Glacier Coast 800DA9D3 0007 cn Open\Difficulty Option 801CB260 ???? 0001:"Hard",0002:"Expert",0003:"Hard & Expert",0010:"Dolphin",0011:"Dolphin & Hard",0012:"Dolphin & Expert",0013:"Dolphin Hard & Expert" cn Open\Level Option 801CB26B ???? 0002:"Sunset Bay",0003:"Above & Drake Lake",0004:"All Above & Marine Fortress",0005:"All Above & Port Blue",0006:"All Above & Southern Island",000D:"All Above & Twilight City",0016:"All Above & Glacier Coast" cn Open\Course Option cd This works in all modes except for Championship Mode. 800DA9D3 ???? 0000:"Dolphin Park",0001:"Sunny Beach",0002:"Sunset Bay",0003:"Drake Lake",0004:"Marian Fortress",0005:"Port Blue",0006:"Twilight City",0007:"Glacier Coast",0008:"Southern Island" cn Always First Place 801C293F 0000 crc 6B45223F-F00E5C56-C:45 gn Wayne Gretzky's 3D Hockey (U) cn Team 1\Score pts 800E6AB1 ???? 0000:"Zero Points",001E:"30 Points",0023:"50 Points",004B:"75 Points",0063:"99 Points" cn Team 2\Score pts 800E9F8D ???? 0000:"ero Points",1E03:"0 Points",2305:"0 Points",4B07:"5 Points",6309:"9 Points" cn Crunched Players 810EA078 3F00 cn Extra Teams 800C7205 0001 cn Get In Fights Constantly 800A442E 0020 cn Players\Height Size 810EA074 ???? 3F00:"Midgets",3F80:"Normal Size",3FC0:"Large",4080:"Giants" cn Players\Head Size 810EA070 ???? 3F00:"Very Small",3F80:"Normal Size",4080:"Very Large" crc 5A9D3859-97AAE710-C:45 gn Wayne Gretzky's 3D Hockey '98 (U) cn Team 1\Score pts 8011C061 ???? 0000:"Zero Points",001E:"30 Points",0023:"50 Points",004B:"75 Points",0063:"99 Points" cn Team 2\Score pts 8011F571 ???? 0000:"ero Points",1E03:"0 Points",2305:"0 Points",4B07:"5 Points",6309:"9 Points" cn Crunched Players 810DBA6C 3F00 cn Extra Teams 80115A0C 0001 cn Get In Fights Constantly 800CF766 0020 cn Players\Height Size 81120688 ???? 3F00:"Midgets",3F80:"Normal Size",3FC0:"Large",4080:"Giants" cn Players\Head Size 81118A2C ???? 3F00:"Very Small",3F80:"Normal Size",4080:"Very Large" crc 33BE8CD6-EC186912-C:45 gn WCW MAYHEM cn Character Creation\Max\Strength 802F16F5 0009 cn Character Creation\Max\Impact 803121B5 0009 cn Character Creation\Max\Speed 803156F5 0009 cn Character Creation\Max\Quickness 803176B5 0009 cn Character Creation\Max\Aerial 80319675 0009 cn Character Creation\Max\Mat Ability 8031B635 0009 cn Character Creation\Max\Submission 8031D5F5 0009 cn Character Creation\Max\Brawling 8031F5B5 0009 cn Character Creation\Max\Dirtiness 80321575 0009 cn Infinite Stamina\Player 1 810E3998 0478 cn Infinite Stamina\Player 2 810E3B34 03ED cn Meter Select\Player 1 800E399D ???? 0060:"Full Meter Bar",0000:"Empty Meter Bar" cn Meter Select\Player 2 800AD80D ???? 0060:"Full Meter Bar",0000:"Empty Meter Bar" cn Enable Cheat 800B115B ???? 0002:"Super Created Wrestlers",0004:"Stamina Meter",0008:"Momentum Meter",0020:"Play As Same Wrestler",0080:"All Wrestlers" cn Freeze Timer 810B3242 D300 crc CEA8B54F-7F21D503-C:45 gn Wetrix (U) cn Infinite Lakes 811BF93E 0009 cn Mega Score 801BF958 00FF 801EED04 00FF cn Always Empty Drain 801BF991 0000 811BF992 0000 811BF994 0000 cn Always Berserk Mode 801BF9AF 00FF cn Stop Level Timer 801BF9B2 00FF cn Practice Lessons Open 810B0BAA 0008 cn Always Drop\Player 1 801BF9BB ???? 0000:"Bar",0001:"T",0002:"Corner",0003:"Square",0004:"Down Square",0005:"Down Bar",0006:"Big Water",0007:"Medium Water",0008:"Small Water",0009:"Smallest Water",000A:"Bomb",000B:"Fireball" cn Always Drop\Player 2 801F013B ???? 0000:"Bar",0001:"T",0002:"Corner",0003:"Square",0004:"Down Square",0005:"Down Bar",0006:"Big Water",0007:"Medium Water",0008:"Small Water",0009:"Smallest Water",000A:"Bomb",000B:"Fireball" cn Infinite Ducks 801BF94B 0009 crc E896092B-DC244D4E-C:45 gn Wheel Of Fortune (U) cn Player 1\Max Cash 810B9990 FFFF cn Player 2\Max Cash 810B9AA4 FFFF cn Player 3\Max Cash 810B9BB8 FFFF cn Player 1\No Cash 810B9992 0000 cn Player 2\No Cash 810B9AA6 0000 cn Player 3\No Cash 810B9BB8 0000 cn Player 1\Infinite Free Spins 800B999B 0001 cn Player 2\Infinite Free Spins 800B9AAF 0001 cn Player 3\Infinite Free Spins 800B9BC3 0001 crc ED98957E-8242DCAC-C:45 gn WinBack - Covert Operations (U) cn Infinite Health 8017AABB 0064 cn Enable\Max Power Mode 8015D417 0001 cn Have All Characters 8115D412 FFFF 8115D410 0003 8015D411 0003 cn Flashlight Mod 80179448 ???? 0001:"On",0000:"Off" cn All Bosses 1 Hit Deaths 811BE482 0000 cn Have All\Weapons,Items & Infinite Ammo\Player 1 8017AA9F 001E 8017AAB3 0008 8017AAB7 0009 801587C4 0009 8015D417 0001 801587C0 000C 801587C1 0060 801587C3 0001 50000601 0000 801587C5 0001 801587CB 0004 801587CD 000C cn Start with Weapon\Player 1 8017AAA8 ???? 0000:"HandGun",0001:"Machinegun",0002:"Shotgun",0003:"Rocket Launcher",0004:"M16 With Infinite Ammo",0005:"New Cooler Handgun",0006:"Invisible Gun 1 With Infinite Ammo",0007:"Invisible Gun 2 With Infinite Ammo",0008:"Odd Inviso ShotGun With Infinite Ammo",0009:"Cool Rocket Launcher With Infinite Ammo",0014:"Silenced Handgun" cn Time is Always 00:00:00 8110DD62 0000 cn Have Trial Mode Unlocked 8110DCEE 0004 crc 132D2732-C70E9118-C:45 gn Wipeout 64 cn Infinite\Check Point Time 810CDE92 0960 cn Always Place First cd For This code doesn't record the win on the Time Trial Gold Challenge or the Weapons Gold Challenge. 8109BC68 0001 81091E06 0003 cn Open\Velocitar 80093249 0001 cn Open\Piranha II 800933C9 0001 cn Open\Super Combo Challenge 8009351D 0000 cn Activate\Infinite Random Weapons Pickup 80091C24 0001 cn Activate\Power-Up Weapons 80091C28 0001 cn Activate\Velocitar 80091C2A 0001 cn Activate\Piranha 80091C29 0001 cn Have Weapon\For Feisar 811BC4F6 ???? 0101:"Rockets",0202:"Missiles",0303:"Mines",0505:"Electro Bolt",0606:"E-Pak",0707:"AutoPilot",0808:"Shield",0909:"Turbo Boost",0C0C:"Quake Disruptor",0D0D:"Secret",0E0E:"Thunder Bomb" cn Have Weapon\For AG System 811BCE3E ???? 0101:"Rockets",0202:"Missiles",0303:"Mines",0505:"Electro Bolt",0606:"E-Pak",0707:"AutoPilot",0808:"Shield",0909:"Turbo Boost",0C0C:"Quake Disruptor",0D0D:"Secret",0E0E:"Thunder Bomb" cn Have Weapon\For Auricom 811BC1DE ???? 0101:"Rockets",0202:"Missiles",0303:"Mines",0505:"Electro Bolt",0606:"E-Pak",0707:"AutoPilot",0808:"Shield",0909:"Turbo Boost",0C0C:"Quake Disruptor",0D0D:"Secret",0E0E:"Thunder Bomb" cn Have Weapon\For Qirex 811BC80E ???? 0101:"Rockets",0202:"Missiles",0303:"Mines",0505:"Electro Bolt",0606:"E-Pak",0707:"AutoPilot",0808:"Shield",0909:"Turbo Boost",0C0C:"Quake Disruptor",0D0D:"Secret",0E0E:"Thunder Bomb" cn Have Weapon\For Piranha II 811BCB2E ???? 0101:"Rockets",0202:"Missiles",0303:"Mines",0505:"Electro Bolt",0606:"E-Pak",0707:"AutoPilot",0808:"Shield",0909:"Turbo Boost",0C0C:"Quake Disruptor",0D0D:"Secret",0E0E:"Thunder Bomb" cn Infinite Eliminations 801BC52B 00FF cn [Infinite Sheild] cd This cheat enabled fixes Av's popping up and spoiling you racing,it also gives you Infinite Sheild on all Cars,Tracks and Modes 5000030C 0000 8109BCE2 0000 8109BD12 0000 crc BD636D6A-5D1F54BA-C:45 gn World Cup 98 (U) cn Home Team scores 800478BF ???? 0000:"0 Goals",0019:"25 Goals",0032:"50 Goals",0063:"99 Goals" cn Away Team scores 800478BB ???? 0000:"0 Goals",0019:"25 Goals",0032:"50 Goals",0063:"99 Goals" cn Open Cup Classic Mode 8003CC6F 0001 crc D2BE2F14-38453788-C:45 gn WWF Attitude (U) cn Enable Everything 8112E21C F000 8112E21E 09FF 8112E220 FFFF 8112E222 FFFF cn 0% in Move List 81135620 0000 cn Infinite Creation Points 80161313 0000 cn Max\Charisma 8014E3EC 000A cn Max\Mat Skills 8014E3ED 000A cn Max\Recovery 8014E3EB 000A cn Max\Speed 8014E3EA 000A cn Max\Strength 8014E3E8 000A cn Max\Toughness 8014E3E9 000A crc 4E4B0640-1B49BCFB-C:45 gn WWF No Mercy (U) cn Infinite\Money\Championship Mode cd For Championship Mode 8109940A FFFF cn Infinite\Money\Smackdown Mall Shop cd For Smackdown Mall Shop 8114FAD6 FFFF cn Have All\Characters,Costumes, & Moves 50000B02 0000 810BEE40 FFFF cn Max Spirit\Player 1 D015A5D1 0015 8015AF5F 00FF cn Max Spirit\Player 2 D015A5D1 0015 8015B2B7 00FF cn Max Spirit\Player 3 D015A5D1 0015 8015B60F 00FF cn Max Spirit\Player 4 D015A5D1 0015 8015B967 00FF cn Always Special\Player 1 D015A5D1 0015 8015AF9E 0004 cn Always Special\Player 2 D015A5D1 0015 8015B2F6 0004 cn Always Special\Player 3 D015A5D1 0015 8015B64E 0004 cn Always Special\Player 4 D015A5D1 0015 8015B9A6 0004 cn Ultimate Code\Player 1 D015A5D1 0015 8015AF5E 0064 cn Ultimate Code\Player 2 D015A5D1 0015 8015B2B6 0064 cn Ultimate Code\Player 3 D015A5D1 0015 8015B60E 0064 cn Ultimate Code\Player 4 D015A5D1 0015 8015B964 0064 cn 2 Player Championship Mode cd This lets player 2 play with you in championship mode so if you have a friend that you want to tag team up with in tag team championship now you can. 810A755E 0002 cn CPU To Human Control\Player 1 8015AF99 ???? 0017:"Human",0018:"CPU" cn CPU To Human Control\Player 2 8015B2F1 ???? 0017:"Human",0018:"CPU" cn CPU To Human Control\Player 3 8015B649 ???? 0017:"Human",0018:"CPU" cn Can't Pin\Player 1 cd Do not use with Auto Pin 8016CE23 0004 cn Can't Pin\Player 2 cd Do not use with Auto Pin 8016CE17 0004 cn Can't Pin\Player 3 cd Do not use with Auto Pin 8016CE2F 0004 cn Can't Pin\Player 4 cd Do not use with Auto Pin 8016CE3B 0004 cn Auto-Pin\Player 1 cd Do not use with Cant Pin 8016CE23 0003 cn Auto-Pin\Player 2 cd Do not use with Cant Pin 8016CE17 0003 cn Auto-Pin\Player 3 cd Do not use with Cant Pin 8016CE2F 0003 cn Auto-Pin\Player 4 cd Do not use with Cant Pin 8016CE3B 0003 cn Play As\Player 1\Option 1 cd Do not use this with anyother Play As Player 1 Option, only use one option at a time 810AAAD0 ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 1\Option 2 cd Do not use this with anyother Play As Player 1 Option, only use one option at a time 810AAAD0 ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 1\Option 3 cd Do not use this with anyother Play As Player 1 Option, only use one option at a time 810AAAD0 ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Play As\Player 2\Option 1 cd Do not use this with anyother Play As Player 2 Option, only use one option at a time 810AAADC ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 2\Option 2 cd Do not use this with anyother Play As Player 2 Option, only use one option at a time 810AAADC ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 2\Option 3 cd Do not use this with anyother Play As Player 2 Option, only use one option at a time 810AAADC ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Play As\Player 3\Option 1 cd Do not use this with anyother Play As Player 3 Option, only use one option at a time 810AAAE8 ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 3\Option 2 cd Do not use this with anyother Play As Player 3 Option, only use one option at a time 810AAAE8 ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 3\Option 3 cd Do not use this with anyother Play As Player 3 Option, only use one option at a time 810AAAE8 ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Play As\Player 4\Option 1 cd Do not use this with anyother Play As Player 4 Option, only use one option at a time 810AAAF4 ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 4\Option 2 cd Do not use this with anyother Play As Player 4 Option, only use one option at a time 810AAAF4 ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 4\Option 3 cd Do not use this with anyother Play As Player 4 Option, only use one option at a time 810AAAF4 ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Cannot Be Grabbed\Player 1 D115AEC6 0052 8115AEC6 0001 D115AEC6 00A1 8115AEC6 00C1 cn Cannot Be Punched\Player 1 D115AEC6 002D 8115AEC6 0001 D115AEC6 0035 8115AEC6 00C1 cn Cannot Be Knocked Down\Player 1 D115AEC6 0031 8115AEC6 0001 cn Wrestler Size & Shape\Player 1\Thin wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B468 3D80 cn Wrestler Size & Shape\Player 1\Wide wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B468 3FFF cn Wrestler Size & Shape\Player 1\Short wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B47C 3E80 cn Wrestler Size & Shape\Player 1\Tall wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B47C 3FFF cn Wrestler Size & Shape\Player 1\Flat wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B490 3D80 cn Wrestler Size & Shape\Player 1\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B490 3FFF cn Wrestler Size & Shape\Player 1\Giant wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B4A4 3E80 cn Wrestler Size & Shape\Player 1\Small wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8106B4A4 3FFF cn Wrestler Size & Shape\Player 2\Thin wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B528 3D80 cn Wrestler Size & Shape\Player 2\Wide wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B528 3FFF cn Wrestler Size & Shape\Player 2\Short wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B53C 3E80 cn Wrestler Size & Shape\Player 2\Tall wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B53C 3FFF cn Wrestler Size & Shape\Player 2\Flat wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B510 3DFF cn Wrestler Size & Shape\Player 2\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B510 3FFF cn Wrestler Size & Shape\Player 2\Giant wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B564 3E80 cn Wrestler Size & Shape\Player 2\Small wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B564 3FFF cn Wrestler Size & Shape\Player 3\Thin wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5E8 3D80 cn Wrestler Size & Shape\Player 3\Wide wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5E8 3FFF cn Wrestler Size & Shape\Player 3\Short wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5FC 3E80 cn Wrestler Size & Shape\Player 3\Tall wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5FC 3FFF cn Wrestler Size & Shape\Player 3\Flat wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B610 3D80 cn Wrestler Size & Shape\Player 3\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B610 3FFF cn Wrestler Size & Shape\Player 3\Giant wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B624 3E80 cn Wrestler Size & Shape\Player 3\Small wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B624 3FFF cn Wrestler Size & Shape\Player 4\Thin wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6A8 3D80 cn Wrestler Size & Shape\Player 4\Wide wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6A8 3FFF cn Wrestler Size & Shape\Player 4\Short wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6BC 3E80 cn Wrestler Size & Shape\Player 4\Tall wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6BC 3FFF cn Wrestler Size & Shape\Player 4\Flat wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6D0 3D80 cn Wrestler Size & Shape\Player 4\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6D0 3FFF cn Wrestler Size & Shape\Player 4\Giant wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6E4 3E80 cn Wrestler Size & Shape\Player 4\Small wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8006B6E4 3FFF cn Z LADDER cd Press Z for the ladder to appear, sometimes there is an invisable ladder D1064880 2000 8116C768 0000 D1064880 2000 8116C76A 0019 D1064880 2000 8116C76C 0000 D1064880 2000 8116C76E 0019 D1064880 2000 8116C788 8104 cn Replace Raw War with\TOKYO DOME cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 810528F4 7223 810528F6 0119 81050124 0100 81050126 0100 81050128 0100 8105012A 0100 8105012C 0100 8105012E 0100 81050130 0100 81050132 0100 81050134 0100 81050136 0100 8105010E 0999 81050400 03A5 81050402 0385 81050404 0385 81050406 0385 81050408 0385 8105040A 03A5 8105040C 03A5 8105040E 043F 81050430 043F 8105042C 03A5 81050430 21A5 81050432 0100 81050434 0000 81050436 2CFB 81050438 0899 8105043C 03AF 81050440 03AF 81050442 03A5 810500E8 24C3 81050444 0100 81050190 09EF 81050192 0000 81050194 09EF 81050196 2CFD cn Replace Raw War with\BARBEDWIRE ROPES cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050110 04F3 81050112 04F4 81050114 04F5 81050116 04F3 81050118 04F4 8105011A 04F5 8105011C 04F3 8105011E 04F4 81050120 04F5 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81079D90 3F6C 81079D94 3F48 81079DA4 3D10 81079DB8 3F71 81079E6C 3F6C 81079E80 3D10 81079E90 3F47 81079F48 3F6C 81079F4C BF4C 81079F5C 3D10 81079F70 3F71 8107A024 3F6C 8107A028 3F28 8107A038 3D10 8107A04C 3F71 8107A100 3F6C 8107A114 3D10 8107A124 3F23 8107A1DC 3F6C 8107A1E0 BF2A 8107A1F0 3D10 8107A204 3F71 8107A2B8 3F6C 8107A2BC 3F02 8107A2CC 3D10 8107A2E0 3F71 8107A394 3F6C 8107A3A8 3D10 8107A3B8 3F00 8107A470 3F6C 8107A474 BF02 8107A484 3D10 8107A498 3F71 81050144 0569 81050154 07F7 810528F4 0C01 810528F6 0555 81050140 04F4 81050150 2CFB 8107A628 3F60 8107A63C 3D10 8107A64C 3F52 8107A650 BF80 8107A8BC 3F56 8107A8C4 BA00 8107A8D0 3D10 8107A8DC 3C5A 8107A8E0 3F30 8107A8E4 BF80 8107ADE4 3F56 8107ADEC BA00 8107ADF8 3D10 8107AE04 3C5A 8107AE08 3F0E 8107AE0C BF80 8107AB7C 3F00 D115AF56 2EB2 8115AEC6 0017 D115B2AE 2EB2 8115B21E 0017 D115B606 2EB2 8115B570 0017 D115B95E 2EB2 8115B8CE 0017 81052922 FFFF 81052924 FFFF 81052926 FFFF cn Replace Raw War with\BARBEDWIRE SQUARE\Part 1 cd Both Parts must be on for this Press the C Left Button to make your opponent bleed,These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050110 04F3 81050112 04F4 81050114 04F5 81050116 04F3 81050118 04F4 8105011A 04F5 8105011C 04F3 8105011E 04F4 81050120 04F5 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81079D90 3F6C 81079D94 3F48 81079DA4 3D10 81079DB8 3F71 81079E6C 3F6C 81079E80 3D10 81079E90 3F47 81079F48 3F6C 81079F4C BF4C 81079F5C 3D10 81079F70 3F71 8107A024 3F6C 8107A028 3F28 8107A038 3D10 8107A04C 3F71 8107A100 3F6C 8107A114 3D10 8107A124 3F23 8107A1DC 3F6C 8107A1E0 BF2A 8107A1F0 3D10 8107A204 3F71 8107A2B8 3F6C 8107A2BC 3F02 8107A2CC 3D10 8107A2E0 3F71 8107A394 3F6C 8107A3A8 3D10 8107A3B8 3F00 8107A470 3F6C 8107A474 BF02 8107A484 3D10 8107A498 3F71 81050144 0569 81050154 07F7 810528F4 0C01 810528F6 0555 81050140 04F4 81050150 2CFB 8107A628 3F60 8107A63C 3D10 8107A64C 3F52 8107A650 BF80 8107A8BC 3F56 8107A8C4 BA00 8107A8D0 3D10 8107A8DC 3C5A 8107A8E0 3F30 8107A8E4 BF80 8107ADE4 3F56 8107ADEC BA00 8107ADF8 3D10 8107AE04 3C5A 8107AE08 3F0E 8107AE0C BF80 8107AB7C 3F00 D115AF56 2EB2 8115AEC6 0017 D115B2AE 2EB2 8115B21E 0017 D115B606 2EB2 8115B570 0017 D115B95E 2EB2 8115B8CE 0017 81052922 FFFF 81052924 FFFF 81052926 FFFF 8116C330 0000 8116C332 000A 8116C334 0000 8116C336 000A 8116C378 42B4 cn Replace Raw War with\BARBEDWIRE SQUARE\Part 2 cd Both Parts must be on for this Press the C Left Button to make your opponent bleed,These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8116C382 0000 8116C38C FFFF 81052C9C 0672 81052CA4 2CFB D1064880 0002 8115B21E 002F D1064886 0002 8115AEC6 002F 8116C3E4 0000 8116C3E6 000C 8116C3E8 0000 8116C3EA 000C 8116C428 C3D4 8116C440 FFFF 81052CB2 2CC2 81052CB4 0805 81052CB6 2CFB D1064880 2000 8116C3E6 001F D1064880 2000 8116C3EA 001F D1064880 2000 81005592 3F81 D1005592 3F81 8116C3E6 001F D1064880 2000 81005592 3F81 D1005592 3F81 8116C3EA 001F D1064886 2000 8116C3E6 001F D1064886 2000 8116C3E6 001F D1064886 2000 81005592 3F81 D1005592 3F81 8116C3EA 001F 81052CF8 04F4 81052D00 2CFB 8116C3E4 0000 8116C3E6 0015 8116C3E8 0000 8116C3EA 0015 8116C428 0000 8116C42A 0000 8116C42C 43EB 8116C42E 0000 8116C430 C3A6 8116C432 0000 8116C436 0400 8116C43A 0000 8116C43E 0000 8116C440 FFFF 8116C442 0000 810855A8 3F00 81085684 3F00 81085750 3F00 8108583C 3F00 81050100 2CFB 8105010E 2CFB cn Replace Raw War with\FLAMING TURNBUCKLES cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8116C334 FFFF 8116C336 001F 8116C374 C350 8116C376 FFF3 8116C378 4377 8116C37A 2689 8116C37C C380 8116C37E 0406 8116C382 0D14 8116C386 0FCC 8116C38A 07DC 8116C38C FFFF 8116C38E FDE3 8116C3E8 FFFF 8116C3EA 001F 8116C428 C360 8116C42C 4370 8116C430 4376 8116C436 0D14 8116C43A 0FCC 8116C43E 07DC 8116C442 F9C4 8116C49C FFFF 8116C49E 001F 8116C4DC 4360 8116C4E0 4370 8116C4E4 4380 8116C4EA 0CD0 8116C4EE 0136 8116C4F2 04EE 8116C4F6 F601 8116C550 FFFF 8116C552 001F 8116C590 434F 8116C594 4370 8116C598 C36C 8116C59E 0E70 8116C5A2 0F58 8116C5A6 0814 8116C5AA F1E6 cn Replace Raw War with\REMOVE RING cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050150 0000 81050152 0000 81050154 0000 810500E8 0000 810855A8 3F00 81085684 3F00 81085750 3F00 8108583C 3F00 81079C08 3F00 81079C14 3F00 81079B10 3F00 cn Replace Raw War with\BACKYARD ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105010E 0F76 8105010C 0F76 810482E8 002F 81050150 2CFD 810528F4 33FF 810528F6 33FF 81050152 2DC7 81050114 04F4 81050116 04F5 8105011E 04F3 81050128 07FF 8105012A 07FF 81050132 07FF 81079F48 400C 81079F5C 3F00 81079F70 3FFF 8107A024 4010 8107A038 3F00 8107A04C 4020 8107A060 3F84 8107A394 4012 8107A3A8 3F00 8107A3BC 4030 8107A3D0 3F84 8105042C 0949 81050436 07FF 81050438 07FF 8105043A 07FF 8105043C 0000 8105043E 07FF 81050440 0949 81050442 0949 81050430 0F76 81050128 07FF 8105012A 07FF 8105012C 0000 8105012E 07FF 81050130 07FF 81050132 07FF 81050134 0000 81050136 08F9 81050196 2CFD 81050194 09EF 81050192 0000 81050190 09EF 8116C49E 0019 8116C4B8 0004 8116C4DC C2E1 8116C4E0 42B4 810500FE 2D2D 81050100 2D2D 81050102 2D2D 81050400 2DC7 81050402 2DC7 81050404 2DC7 81050406 2DC7 81050408 2DC7 8105040A 2DC7 8105040C 2DC7 8105040E 2DC7 50001002 0000 810501B8 0000 50000402 0000 810501E0 0000 50000902 0000 81050262 0000 50001402 0000 81050290 0000 50002C02 0000 810502EC 0000 8107941C 3FE0 81079428 3FFF 810500EC 06FE 810500EE 06FD 810500F8 07FF 810500FA 0997 81050110 06FC 81050112 06FB 8105011A 06FF 8105011C 06FA 81052CF0 2CC9 81052CF4 2D1B 81052CD0 2CD1 81052CD4 0963 81052C84 2CBF 81052C8A 0961 81052CB8 2CC4 81052CBC 2DD7 81052CC8 2CD1 81052CCC 2CFB 81052C78 2CBC 81052C80 2D31 81052CF8 2CC1 81052D00 2DD7 cn Replace Raw War with\BACKYARD WEAK cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 0E88 8105042E 2D0D 81050430 2D0D 81050432 2D0D 81050434 2D0D 81050436 07FD 8105043A 2CFB 8105043C 2D0D 8105043E 2D0D 81050440 2D0D 81050442 2D0D 810500E8 2D0D 8105010E 2D0D 8105010C 2D0D 81050150 2D0D 81050196 2CFB 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81050136 2CFB 81050400 2D0D 81050402 2D0D 81050404 2D0D 81050406 2D0D 81050408 2D0D 8105040A 2D0D 8105040C 2D0D 8105040E 2D0D 810528F4 2D0D 810528F6 2D0D 81052CE8 2CC9 81052CEC 2D2D cn Replace Raw War with\BARBEDWIRE ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 2CFB 8105042E 2CFB 81050430 2CFB 81050432 2CFB 81050434 2CFB 81050436 2CFB 81050438 2CFB 8105043A 2CFB 8105043C 2CFB 8105043E 2CFB 81050440 2CFB 81050442 2CFB 810500E8 2CFB 8105010E 2CFB 8105010C 2CFB 81050150 2CFB 81050196 2CFB 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81050136 2CFB 810528F4 DDDD 810528F6 DDDD 81052CE8 2CCA 81052CEC 2CFB 81050400 2CFB 81050402 2CFB 81050404 2CFB 81050406 2CFB 81050408 2CFB 8105040A 2CFB 8105040C 2CFB 8105040E 2CFB cn Replace Raw War with\DUDLEY ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 21A7 8105042E 2D0D 81050432 2D0D 81050436 21A7 8105043E 2D0D 81050440 0000 81050442 0000 810500E8 2D0D 8105010C 2CFD 8105010E 2CFD 81050150 2D29 81050152 2CFB 81050400 09EF 81050402 09EF 81050404 0000 81050406 0000 81050408 0000 8105040A 0000 8105040C 09EF 8105040E 09EF 81050188 04F6 8105018A 04F7 8105018C 04F8 8105018E 04F9 81050190 09EF 81050192 0000 81050194 09EF 81050196 2D0D 810528F4 6666 810528F6 6666 81052CE8 2CC2 81052CEC 2D0D 81052D1C 2CD3 81052D1E 2CD4 81052D20 2CD5 81052D22 2CD6 81052D24 2CFD 81052D26 2CFD 81052D28 2CFB 81052D2A 2CFB 81050124 2CFD 81050126 2CFD 81050128 2CFD 8105012A 2CFD 8105012C 2CFD 8105012E 2CFD 81050130 2CFD 81050132 2CFD 81050134 2CFD 81050136 2CFD 81050154 2CFB 811533F8 002E cn Replace Raw War with\FLAME ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105010E 0EFE 8105010C 0EFE 810528F4 2508 810528F6 2508 81050430 2401 81050430 2401 81050404 2401 81050406 2401 81050408 2401 81050409 2401 8105040A 2401 8105040C 2401 810500E8 2401 cn Replace Raw War with\GREENWICH STREET ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050430 2DC5 81050436 0000 81050438 0000 8105043A 0000 8105043E 0000 810504E8 0EFE 8105010E 2DC5 8105010C 2DC5 81050196 2CFD 81050136 0FB6 81050134 0FC6 81050132 0FB6 81050130 0FC6 8105012E 0FB6 8105012C 0FC6 8105012A 0FB6 81050128 0FC6 81050126 0FB6 81050124 0FC6 81050440 0000 81050442 0000 50002C02 0000 81050378 0000 50002C02 0000 810502EC 0000 50001402 0000 81050290 0000 50000902 0000 81050262 0000 50000402 0000 810501CE 0000 50001002 0000 810501B8 0000 50000402 0000 810501E0 0000 8105042C 2D0D 81050430 0000 81050150 24F0 cn Replace Raw War with\HHH ARNEA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105040E 24EF 8105040C 24EF 8105040A 24EF 81050408 24EF 81050406 24EF 81050404 24EF 81050402 24EF 81050400 24EF 81050436 24E9 81050440 24E9 81050442 24E9 8105043E 24EF 8105042E 24EF 8105043C 24EF 8105042C 24E9 8105010E 24E9 8105010C 24E9 81050196 24E9 8105042E 24EF 81050432 24EF 810500F8 24EF 810500FA 24EF 810500FC 24EF 810500FC 24EF 81050100 24EF 81050100 24EF 81052CE8 2CCA 81052CEC 24EF 81050150 24E9 81050152 24E9 81050154 24E9 810528F4 24E9 810528F6 24E9 cn Replace Raw War with\HOSPITAL ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 0949 8105042E 283F 81050428 0949 81050430 0949 81050430 0949 81050436 096B 81050438 0993 8105043A 096B 8105043E 283F 81050440 283F 81050442 283F 810504E8 0949 81050150 283F 81050196 283F 81050400 283F 81050402 283F 81050404 283F 81050406 283F 81050408 283F 8105040A 283F 8105040C 283F 8105040E 283F 810500F8 283F 810500FA 283F 810500FC 283F 810500FE 283F 81050100 283F 81050100 283F 81052CE8 2CCA 81052CEC 283F 8105010E 283F 8105010C 283F 81050124 0949 81050126 0949 81050128 0949 8105012A 0949 8105012C 0949 8105012E 0949 81050130 0949 81050132 0949 81050134 0949 81050136 0949 810500E8 0949 810528F4 0000 81052CE0 2CC9 cn Replace Raw War with\KANE ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 0A61 8105042E 0A61 81050428 2B6C 81050430 2B6C 81050430 2B6C 81050436 2B57 81050438 2B57 8105043A 2B57 8105043E 0A61 81050440 2B57 81050442 2B57 810500E8 1B1E 8105010E 2D37 8105010C 209F 81050194 0955 81050196 2B57 81050400 2699 81050402 2699 81050404 2699 81050406 2699 81050408 2699 8105040A 2699 8105040C 2699 8105040E 2699 cn Replace Raw War with\SHIMMER ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 1932 8105042E 1932 81050430 1932 81050434 1932 81050432 1932 81050436 1932 81050438 1932 8105043A 1932 8105043E 1932 81050440 1932 81050442 1932 81050150 1932 81050152 1932 81050154 1932 81050190 1932 81050192 1932 81050194 1932 81050196 1932 81050124 1932 81050126 1932 81050128 1932 8105012A 1932 8105012C 1932 8105012E 1932 81050130 1932 81050132 1932 81050134 1932 81050136 1932 810500E8 1932 8105010E 1932 8105010C 1932 cn Replace Raw War with\SPACE SHIP ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 094D 8105042E 0953 81050430 0953 81050432 0F0E 81050434 0953 81050436 0F0E 81050438 0899 8105043C 0953 8105043E 0899 81050440 0963 81050442 0963 81050400 0953 81050402 0953 81050404 0953 81050406 0953 81050408 0953 8105040A 0953 8105040C 0953 8105040E 0953 810500E8 0A75 810528F4 7223 810528F6 0119 81050150 0963 81050152 0963 81050190 0953 81050192 0953 81050194 0953 81050196 0963 8105010E 0F0E 8105010C 0F0E 81050124 0F10 81050126 0F10 81050128 0F10 8105012A 0F10 8105012C 0F10 8105012E 0F10 81050130 0F10 81050132 0F10 81050134 0F10 81050136 0F10 810500F8 0963 810500FA 0963 810500FC 0963 810500FE 0963 81050100 0963 81050102 0963 81052CE8 2CCA 81052CEC 0963 cn Tables\IN RING TABLE\Part 1 cd To Make the Table look broken Keep the Z Button press down, To make player stand on the Table, Stand next to it & Keep C-Right Pressed Down.Put all Parts on Together for this Cheat to work 81052CF0 06E1 81052CF4 09F1 81052CF8 06E2 81052D00 09F1 81052D0C 06E3 81052D0E 06E4 81052D10 09EF 81052D12 09EF 81052D14 06E5 81052D16 06E6 81052D18 09EF 81052D1A 09EF D1064880 0001 8115AFB0 432C D1064880 0001 8115B308 432C D1064880 2000 8115AFB0 42B4 D1064880 2000 8115B308 42B4 8116C330 0000 8116C332 0014 8116C334 0000 8116C336 0014 8116C374 4210 8116C376 C0B1 8116C378 432F 8116C37A 51DC 8116C37C 4210 8116C37E 92F1 8116C382 0800 8116C386 05A0 8116C38A 0800 8116C38C FFFF 8116C38E F3BC 8116C3E4 0000 8116C3E6 0015 8116C3E8 0000 8116C3EA 0015 8116C428 4210 8116C42A C0B1 8116C42C 432F 8116C42E 51DC 8116C430 4210 8116C432 92F1 8116C436 0800 8116C43A 05A0 8116C43E 0800 8116C440 FFFF 8116C442 F3BC D1064880 2000 8116C378 42E0 cn Tables\IN RING TABLE\Part 2 cd To Make the Table look broken Keep the Z Button press down, To make player stand on the Table, Stand next to it & Keep C-Right Pressed Down.Put all Parts on Together for this Cheat to work D1064880 2000 8116C382 07E0 D1064880 2000 8116C38A 0680 D1064880 2000 8116C42C 42E0 D1064880 2000 8116C436 0820 D1064880 2000 8116C43E 0980 8116C498 0000 8116C49A 0017 8116C49C 0000 8116C49E 0017 8116C4DC 4210 8116C4DE C0B1 8116C4E0 432A 8116C4E2 51DC 8116C4E4 4210 8116C4E6 92F1 8116C4EA 0800 8116C4EE 05A0 8116C4F2 0800 8116C4F4 FFFF 8116C4F6 F3BC 8116C54C 0000 8116C54E 0018 8116C550 0000 8116C552 0018 8116C590 4210 8116C592 C0B1 8116C594 432A 8116C596 51DC 8116C598 4210 8116C59A 92F1 8116C59E 0800 8116C5A2 05A0 8116C5A6 0800 8116C5A8 FFFF 8116C5AA F3BC D1064880 2000 8116C4E0 42E0 D1064880 2000 8116C4EA 07E0 D1064880 2000 8116C4F2 0680 D1064880 2000 8116C594 42E0 D1064880 2000 8116C59E 0820 D1064880 2000 8116C5A6 0980 cn Novalty\Truck In The Crowd 81050110 0747 81050112 0748 81050114 0749 81050116 074A 81050118 074B 81050124 0A4B 81050126 0A43 81050128 0A4B 8105012A 0A43 8105012C 0A43 8105012E 0A43 8105011A 074C 8105011C 074D 81050130 0A43 8105011E 074E 81050132 0A43 81050120 0746 81050134 0A4B 81050122 0743 81050136 0A4B D1064880 2000 8115AFB0 42EE D1064880 2000 8115B308 42EE cn CPU To Human Control\Player 4 8015B9A1 ???? 0017:"Human",0018:"CPU" cn Clock At 00:00 8115AB1E 0000 810A99F2 0000 cn Hacked Moves\Dragon Screw Stunner cd Dragon Screw 02 P1 does a Dragon Screw then picks up P2 (still holding his leg) and spins him around and gives him a Stone Cold Stunner D106B454 3749 D106B456 0094 8106B460 00E9 D106B454 3749 D106B456 0094 8106B462 B9BE D106B514 374A D106B516 0094 8106B520 00E9 D106B514 374A D106B516 0094 cn Hacked Moves\Morality Check to Back of head cd Replaces: Back Clothesline P1 is immediately backed up and does the Morality Check to P2 in the back of the head (misses by a little) D106B454 3892 D106B456 0000 8106B460 00B3 D106B454 3892 D106B456 0000 8106B462 194C cn Hacked Moves\Dragon Screw Suplex cd Replaces: Double Dragon Screw 02 P1 does a Dragon screw then picks then up (still holding their feet) and does a capture suplex. D106B454 3749 D106B456 007C 8106B460 00AD D106B454 3749 D106B456 007C 8106B462 DB2A D106B514 374A D106B516 007C 8106B520 00AD D106B514 374A D106B516 007C 8106B522 EAE0 D106B454 3749 D106B456 00A5 8115AF52 0000 D106B514 374A D106B516 00A5 8115B2AA 0000 cn Hacked Moves\Dominator into HHH Facebuster cd Replaces: Dominator D106B454 3810 D106B456 005C 8106B560 011A D106B454 3810 D106B456 005C 8106B562 A256 D106B514 3811 D106B516 005C 8106B520 011A D106B514 3811 D106B516 005C 8106B522 ACB0 D106B454 3810 D106B456 0075 8115AF52 0000 cn Hacked Moves\Capture Tazzplex cd Replaces: Capture Suplex P1 grabs P2's feet like a capture suplex, then lets go & does a Tazzplex. D106B454 3689 D106B456 0021 8106B460 00BC D106B454 3689 D106B456 0021 8106B462 A5E2 D106B514 368A D106B516 0021 8106B520 00BC D106B514 368A D106B516 0021 8106B522 B6BE cn Hacked Moves\Running Rock Bottom cd Replaces: Farooq Spinebuster P2 runs into P1 and P1 delivers a RockBottom to P2. D106B454 3A80 D106B456 0000 8106B460 00C1 D106B454 3A80 D106B456 0000 8106B462 F7A2 D106B514 3A81 D106B516 0000 8106B520 00C2 D106B514 3A81 D106B516 0000 8106B522 1210 cn Hacked Moves\Running Tazplex cd Replaces: Underhook Belly to Belly P2 runs into P1 and P1 does a Tazplex to P2. D106B454 3A7A D106B456 0000 8106B460 00BC D106B454 3A7A D106B456 0000 8106B462 A51E D106B514 3A7B D106B516 0000 8106B520 00BC D106B514 3A7B D106B516 0000 8106B522 B5FA cn Tables\MOVABLE TABLES\Part 1 cd You must use both parts for this cheat to work 81052C24 06E1 81052C26 06E3 81052C2C 09F1 81052C2E 09EF 81052C30 06E2 81052C32 06E5 81052C38 09F1 81052C3A 09EF 81052C48 06E4 81052C4A 06E6 81052C50 09EF 81052C52 09EF 8116C3E4 0000 8116C3E6 0001 8116C3E8 0000 8116C3EA 0001 8116C498 0000 8116C49A 0003 8116C49C 0000 8116C49E 0003 8116C330 0000 8116C332 0000 8116C334 0000 8116C336 0000 D116C556 0000 8116C33A 0000 D116C33A 0000 8116C3EE 0000 D116C3EE 0000 8116C4A2 0000 D116C556 0001 8116C33A 0001 D116C33A 0001 8116C3EE 0001 D116C3EE 0001 8116C4A2 0001 D116C556 0002 8116C33A 0002 D116C33A 0002 8116C3EE 0002 D116C3EE 0002 8116C4A2 0002 D116C556 0003 8116C33A 0003 D116C33A 0003 8116C3EE 0003 D116C3EE 0003 8116C4A2 0003 D116C556 FFFF 8116C33A FFFF D116C33A FFFF 8116C3EE FFFF D116C3EE FFFF 8116C4A2 FFFF D216C556 FFFF 81079B10 3F80 D1064886 2000 81079B10 3F81 D106488C 2000 81079B10 3F81 D1064892 2000 81079B10 3F81 cn Tables\MOVABLE TABLES\Part 2 cd You must use both parts for this cheat to work D116C33A FFFF 8116C382 0000 D116C382 0000 8116C386 0000 D116C386 0000 8116C38A 0000 D116C38A 0000 8116C38E 0000 D116C38E 0000 8116C436 0000 D116C436 0000 8116C43A 0000 D116C43A 0000 8116C43E 0000 D116C43E 0000 8116C442 0000 D116C442 0000 8116C4EA 0000 D116C4EA 0000 8116C4EE 0000 D116C4EE 0000 8116C4F2 0000 D116C4F2 0000 8116C4F6 0000 D116C594 42B4 D116C556 FFFF 8116C378 4335 D116C378 4335 8116C42C 4335 D116C42C 4335 8116C4E0 4335 D116C594 3DC7 D116C556 FFFF 8116C378 42B0 D116C378 42B0 8116C42C 42B0 D116C42C 42B0 8116C4E0 42B0 D1064880 2000 81079B10 3F81 D1079B10 3F81 D116C594 42B4 D116C556 FFFF 8116C378 42F0 D116C378 42F0 8116C42C 42F0 D116C42C 42F0 8116C4E0 42F0 D1079B10 3F81 8116C38A 0F00 D116C38A 0F00 8116C43E 0100 D116C594 3C93 8116C378 42B0 81052D18 0000 81052D1A 0000 D116C54C 0000 8116C54E 0018 D116C550 0000 8116C552 0018 cn Tables\Sabu Table cd Breakable/Fixable/Rebreakable/Refixable press Z to break, C-right + Cdown to fix 8116C49A 000C 8116C49E 000C 8116C4DC 43CC 8116C4E0 42E6 8116C4E4 C2C5 8116C4EE 0800 8116C602 000C 8116C606 000C 8116C648 42E6 8116C644 43CC 8116C64C C314 81052C54 06E3 81052C5C 09EF 8116C6F8 43CC 8116C6FC 42F0 8116C700 C2F1 8116C70A 0400 8116C428 43CC 8116C430 C2D0 8116C42C 42F0 8116C43A 0C00 8116C6B6 0004 8116C6BA 0004 8116C3E6 0004 8116C3EA 0004 D1064880 2000 81005592 3F81 D1005592 3F81 8116C4EA 0F00 D1005592 3F81 8116C652 0100 D1005592 3F81 8116C4E0 4240 D1005592 3F81 8116C648 4240 D1064880 0005 81005CD4 3F83 D1005CD4 3F83 8116C4EA 0000 D1005CD4 3F83 8116C652 0000 D1005CD4 3F83 8116C4E0 42E6 D1005CD4 3F83 8116C648 42E6 D1005CD4 3F83 D1064880 2000 81005CD4 0000 crc CD5BEC0F-86FD1008-C:45 gn WWF War Zone (U) cn Extra Characters 8113A488 1000 8113A48A 07FF 8113A48C 2000 8113A48E 3FFF cn Infinite Creation Points 80136245 0000 crc 90A59003-31089864-C:45 gn WWF WrestleMania 2000 (U) cn Have All Characters 8109ED5A FFFF cn Infinite Create-A-Wrestler Attribute Points 8011A81B 001E cn Timer Is Always 00:00 8016F0AF 0000 cn Max Attributes 50000502 0000 8011A811 0032 cn Weapon Select\Player 1 81167236 0300 81166D90 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 81166D92 0000 80166E50 0000 cn Weapon Select\Player 2 811676CA 0300 81166DC0 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 80166DC2 0001 80166E51 0001 cn Weapon Select\Player 3 81167B5E 0300 81166DF0 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 80166DF2 0002 80166E52 0002 cn Weapon Select\Player 4 81167FF2 0300 81166E18 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 81166E1A 0003 80166E53 0003 cn Always Special\Player 1 80167235 0004 cn Always Special\Player 2 801676C9 0004 cn Always Special\Player 3 80167B5D 0004 cn Always Special\Player 4 80167FF1 0004 cn Specials Don't Run Out 8112AD94 2400 cn Max Spirit\Player 1 801671F5 00FF cn Always Normal Spirit\Player 1 801671F5 0032 cn No Spirit\Player 1 801671F5 0000 cn Max Spirit\Player 2 80167689 00FF cn Always Normal Spirit\Player 2 80167689 0032 cn No Spirit\Player 2 80167689 0000 cn Max Spirit\Player 3 80167B1D 00FF cn Always Normal Spirit\Player 3 80167B1D 0032 cn No Spirit\Player 3 80167B1D 0000 cn Max Spirit\Player 4 80167FB1 00FF cn Always Normal Spirit\Player 4 80167FB1 0032 cn No Spirit\Player 4 80167FB1 0000 cn Ultimate Codes\Player 1 801671F4 0064 cn Ultimate Codes\Player 2 80167688 0064 cn Ultimate Codes\Player 3 80167B1C 0064 cn Ultimate Codes\Player 4 80167FB0 0064 cn Easy Pins & Longer Submissions\Player 2 80167688 0064 cn Easy Pins & Longer Submissions\Player 3 80167B1C 0064 cn Easy Pins & Longer Submissions\Player 4 80167FB0 0064 cn Easy Pins & Longer Submissions\Player 1 801671F4 0064 crc 0553AE9D-EAD8E0C1-C:45 gn Xena Warrior Princess: The Talisman of Fate (U) cn 1 Hit to Kill Opponent\Player 1 D10B6354 42C8 810B6354 4080 cn Opponent Has No Energy\Player 1 810B6354 C080 cn Player 2 Never Wins 800C0C05 0000 cn Infinite Health\Player 1 810B6170 42C8 cn Infinite Health\Player 2 810B6354 42C8 cn 1 Hit to Kill Opponent\Player 2 D10B6170 42C8 810B6170 4080 cn Opponent Has No Energy\Player 2 810B6170 C080 cn Player 1 Never Wins 800C0C03 0000 cn Unlock Titan Difficulty Level 810BF752 0001 crc 2337D8E8-6B8E7CEC-C:45 gn Yoshi's Story (U) cn Infinite\Health cd This is for All Yoshis All levels 8102B780 2400 cn Infinite\Eggs Once You Get One cd This is for All Yoshis All levels 8103E89C 2400 cn Infinite\Lives cd This is for All Yoshis All levels 800F8DF7 00FF crc 1D4136F3-AF63EEA9-C:45 gn Legend of Zelda, The - Ocarina of Time - Master Quest (E) [f1] (NTSC) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 81119D04 0001 cn Max\Double Defense Power cd This gives you White Border Hearts 80118A07 0014 cn Use Any Item In Any House cd do not use under or in water 81119B5A 0000 81119B5C 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811189D4 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811189DC 30FF 811189DE FFFF cn Max\Heart Containers 81118966 0140 cn Max\Gold Skulltulas Killed 80118A09 0064 cn Time of Day Modifier 81118944 ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 81118968 0140 cn Infinite\Magic D0118971 0008 80118972 0001 80118974 0001 8011896B 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 801189A8 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 801189C4 0009 cn Infinite\Deku Nuts 801189C5 0009 cn Infinite\Bombs 801189C6 0009 cn Infinite\Arrows 801189C7 0009 cn Infinite\Deku Seeds 801189CA 0009 cn Infinite\Bombchu's 801189CC 0009 cn Infinite\Magic Beans 801189D2 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 801189E0 0007 801189E1 0007 801189E2 0007 801189E3 0007 801189E4 0007 801189E5 0007 801189E6 0007 801189E7 0007 801189E8 0007 801189E9 0007 801189EA 0007 801189F7 0009 801189F8 0009 801189F9 0009 801189FA 0009 801189FB 0009 80118A01 0009 80118A04 0009 801189FF 0009 cn Have\Ocarina 801189B3 ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 801189B8 000E cn Have\Lens of Truth 801189B9 000F cn Have\Megaton Hammer 801189BB 0011 cn Have\Deku Stick 801189AC 0000 cn Have\Deku Nut 801189AD 0001 cn Have\Bombs 801189AE 0002 cn Have\Fairy Bow 801189AF 0003 cn Have\Fairy Slingshot 801189B2 0006 cn Have\Bombchu 801189B4 0009 cn Have\Arrows\Fire Arrow 801189B0 0004 cn Have\Arrows\Ice Arrow 801189B6 000C cn Have\Arrows\Light Arrow 801189BC 0012 cn Have\Hookshot 801189B5 ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 801189BA 0010 cn Have\Magic\Fairie's Wind 801189B7 000D cn Have\Magic\Nayru's Love 801189BD 0013 cn Have\Magic\Din's Fire 801189B1 0005 cn Bottles\Bottle 1 Modifier 801189BE ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 801189BF ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 801189C0 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 801189C1 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 801189C2 ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 801189C3 ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 80118976 0001 cn Have Quiver (Holds 30) 801189D9 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 801189DA ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 801189DB ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0005:"Lake Hylia",0008:"Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 81119D00 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 8011B9A1 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F1A68 0005 801EE508 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 80119D0D 00B4 cn Beta\Play Beta Quest Worlds cd Put on the code on load up,& then press reset (F1) you will be in Beta Mode,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D011BB71 0000 80119D4B ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Level Select D01C6E35 0000 8111893A ???? 0000:"Inside the Deku Tree",0004:"Dodongo's Cavern",0008:"Gerudo Training Ground",000C:"Below The Phantom Gannon Boss",0010:"Water Temple",0027:"Inside Jabu-Jabu's Belly",002C:"Royal Family's Tomb",0036:"Shoadow Temple",0042:"Lakeside Laboratory",0052:"Temple Of Time",006C:"?" cn Language Select 80119D41 ???? 0000:"English",0001:"German",0002:"French" cn Press L\To Levitate cd Press L To Levitate & Let go to land D011BB11 0020 811D93D0 40CB cn Press L\For Infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D011BB11 0020 811D9BF2 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D011BB11 0020 811D93D0 40CB D011BB11 0000 811D9BF2 000D 801189A8 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 8002397C 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C681D 0010 81119C9E 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 80119821 00FF 80119C97 ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 801189DA ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" crc 27A3831D-B505A533-C:45 gn Legend of Zelda, The - Ocarina of Time - Master Quest (E) [f2] //--------------- PAL (E) Region Cheat Codes cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 81119D04 0001 cn Max\Double Defense Power cd This gives you White Border Hearts 80118A07 0014 cn Use Any Item In Any House cd do not use under or in water 81119B5A 0000 81119B5C 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811189D4 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811189DC 30FF 811189DE FFFF cn Max\Heart Containers 81118966 0140 cn Max\Gold Skulltulas Killed 80118A09 0064 cn Time of Day Modifier 81118944 ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 81118968 0140 cn Infinite\Magic D0118971 0008 80118972 0001 80118974 0001 8011896B 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 801189A8 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 801189C4 0009 cn Infinite\Deku Nuts 801189C5 0009 cn Infinite\Bombs 801189C6 0009 cn Infinite\Arrows 801189C7 0009 cn Infinite\Deku Seeds 801189CA 0009 cn Infinite\Bombchu's 801189CC 0009 cn Infinite\Magic Beans 801189D2 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 801189E0 0007 801189E1 0007 801189E2 0007 801189E3 0007 801189E4 0007 801189E5 0007 801189E6 0007 801189E7 0007 801189E8 0007 801189E9 0007 801189EA 0007 801189F7 0009 801189F8 0009 801189F9 0009 801189FA 0009 801189FB 0009 80118A01 0009 80118A04 0009 801189FF 0009 cn Have\Ocarina 801189B3 ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 801189B8 000E cn Have\Lens of Truth 801189B9 000F cn Have\Megaton Hammer 801189BB 0011 cn Have\Deku Stick 801189AC 0000 cn Have\Deku Nut 801189AD 0001 cn Have\Bombs 801189AE 0002 cn Have\Fairy Bow 801189AF 0003 cn Have\Fairy Slingshot 801189B2 0006 cn Have\Bombchu 801189B4 0009 cn Have\Arrows\Fire Arrow 801189B0 0004 cn Have\Arrows\Ice Arrow 801189B6 000C cn Have\Arrows\Light Arrow 801189BC 0012 cn Have\Hookshot 801189B5 ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 801189BA 0010 cn Have\Magic\Fairie's Wind 801189B7 000D cn Have\Magic\Nayru's Love 801189BD 0013 cn Have\Magic\Din's Fire 801189B1 0005 cn Bottles\Bottle 1 Modifier 801189BE ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 801189BF ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 801189C0 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 801189C1 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 801189C2 ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 801189C3 ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 80118976 0001 cn Have Quiver (Holds 30) 801189D9 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 801189DA ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 801189DB ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0005:"Lake Hylia",0008:"Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 81119D00 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 8011B9A1 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F1A68 0005 801EE508 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 80119D0D 00B4 cn Beta\Play Beta Quest Worlds cd Put on the code on load up,& then press reset (F1) you will be in Beta Mode,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D011BB71 0000 80119D4B ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Level Select D01C6E35 0000 8111893A ???? 0000:"Inside the Deku Tree",0004:"Dodongo's Cavern",0008:"Gerudo Training Ground",000C:"Below The Phantom Gannon Boss",0010:"Water Temple",0027:"Inside Jabu-Jabu's Belly",002C:"Royal Family's Tomb",0036:"Shoadow Temple",0042:"Lakeside Laboratory",0052:"Temple Of Time",006C:"?" cn Language Select 80119D41 ???? 0000:"English",0001:"German",0002:"French" cn Press L\To Levitate cd Press L To Levitate & Let go to land D011BB11 0020 811D93D0 40CB cn Press L\For Infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D011BB11 0020 811D9BF2 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D011BB11 0020 811D93D0 40CB D011BB11 0000 811D9BF2 000D 801189A8 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 8002397C 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C681D 0010 81119C9E 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 80119821 00FF 80119C97 ???? 0000:"Off",0001:"On" cn Always Have Wallet Size 801189DA ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" crc 0414CA61-2E57B8AA-C:50 gn GOLDENEYE cn Enemies Do Nothing 80027E54 00FF cn Enemy Options cd "These Codes Are very very cool but in most places pointless ! But great fun, try then. But remember to deactivate them before coming to the end of the level, otherwise, there will be nothing/no one, to meet or do (:" 80032142 ???? 0001:"Enemies Come After You",0097:"Enemies Move Around & Check",00FF:"Enemies Check Around Themselves" cn Enable All Levels & In-Built Cheat Menu cd This code gives you all of the levels, all of the in-game cheats, and the special 007 mode!Hit the "A" button until you come to the place where you choose your level. EVERY SINGLE ONE SHOULD BE THERE. Hit "B" again and check out the Cheats. ALL 23 SHOULD BE THERE. When you pick your stage, you will see another difficulty level, "007". This is the level editor, where you can change all kinds of stuff! 8105886E FFFF 80058870 00FF 800588A5 00FF 800588A7 00FF 800588AA 00FF 800588AC 00FF 800588AF 00FF 800588B1 00FF 800588BB 00FF 800588B6 00FF 800588B9 00FF 800588BB 00FF cn All Objectives Complete 80064C9B 0001 80064C9F 0001 80064CA3 0001 80064CA7 0001 80064CAB 0001 cn Freeze Unfreeze enemies cd Press C-Up To Freeze & C-Down To Unfreeze. D00572D1 0008 80027E5C 000F D00572D1 0004 80027E5C 0000 cn Cradle in multiplayer cd Puts the cradle graphic in the levels screen where the facility normally is in the multiplayer levels screen.Warning it doesn't allow you to enter the multiplayer levels screen,it should automatically have selected cradle, which cannot be changed from the multiplayer menus 8002666D 0092 8002666F 0093 80026677 0029 80026673 0008 803230C5 0052 803230C6 0041 803230C7 0044 803230C8 004C 803230C9 0045 cn Facility Back Zone In Multiplayer\Part 1\2 players cd All parts must be on for this code to work.this cheat allows you to play the Facility Back Zone In Multiplayer 811E6554 45E4 811E6558 43D5 811E655C C5A7 811E657C 801C 811E657E 6774 811E5164 45E4 811E5168 C383 811E516C 4492 811E518C 801C 811E518E D574 811E78C0 45AD 811E78C4 C383 811E78C8 4440 811E78E8 801C 811E78EA E464 811E4D18 45D0 811E4D1C 4307 811E4D20 C4FB 811E4D40 801C 811E4D42 75EC 811E6738 45CD 811E673C C383 811E6740 43F4 811E6760 801C 811E6762 A0DC 811E5450 45C2 811E5454 4356 811E5458 C598 811E5478 801C 811E547A 6A74 811E5240 4608 811E5244 4307 811E5248 43DC 811E5268 801C 811E526A 962C 811E691C 4606 811E6920 4321 811E6924 449D 811E6944 801C 811E6946 CBEC 801ED447 008A 801ED4DB 008B 801ED56F 008C 801ED603 008D 801ED697 008E 801ED72B 008F 801ED7BF 007D 801ED853 007E 801ED443 002A 801ED4D7 002A 801ED56B 002A 801ED5FF 002A 801ED693 002A 801ED727 002A 801ED7BB 002A 801ED84F 002A 801ED449 0000 801ED4DD 0000 801ED571 0000 801ED605 0000 801ED699 0000 801ED72D 0000 801ED7C1 0000 801ED855 0000 801ED44D 0000 801ED4E1 0000 801ED575 0000 801ED609 0000 801ED69D 0000 801ED731 0000 801ED7C5 0000 801ED859 0000 801EB743 002A 801EB745 0068 811EB746 277F 811EB748 1000 811EB74A 0262 811EB7C2 0190 801EB7C5 0000 811EB7C6 0258 cn Facility Back Zone In Multiplayer\Part 2\2 players cd All parts must be on for this code to work.this cheat allows you to play the Facility Back Zone In Multiplayer 811EB7C8 0000 811EB7CC FFFF 811EB7CE FFFF 811EB7D2 0000 801EB7D5 0000 801EB7DB 0000 811EB7E2 0000 801EB7E7 0000 801EB843 002A 801EB845 0068 811EB846 2780 811EB848 1000 811EB84A 0262 811EB8C2 0190 801EB8C5 0000 811EB8C6 0258 811EB8C8 0000 811EB8CC FFFF 811EB8CE FFFF 811EB8D2 0000 801EB8D5 0000 801EB8DB 0000 811EB8E2 0000 801EB8E7 0000 801EB943 002A 801EB945 0068 811EB946 2791 811EB948 1000 811EB94A 0262 811EB9C2 0190 801EB9C5 0000 811EB9C6 0258 811EB9C8 0000 811EB9CC FFFF 811EB9CE FFFF 811EB9D2 0000 801EB9D5 0000 801EB9DB 0000 811EB9E2 0000 801EB9E7 0000 801EBA43 002A 801EBA45 0068 811EBA46 2792 811EBA48 1000 811EBA4A 0262 811EBAC2 0190 801EBAC5 0000 811EBAC6 0258 811EBAC8 0000 811EBACC FFFF 811EBACE FFFF 811EBAD2 0000 801EBAD5 0000 801EBADB 0000 811EBAE2 0000 801EBAE7 0000 801EBB45 00A0 801EBC45 00A0 801EBD45 00A0 801EBE45 00A0 801EBB47 0075 801EBC47 0076 801EBD47 0077 801EBE47 0078 801EBBE7 0001 801EBCE7 0001 801EBDE7 0001 801EBEE7 0001 801EC247 0071 801ECD47 0072 801ECE47 0074 801ECF47 006C 801ED047 0079 801ED147 0083 D01EBFC5 005A 801EBFC5 0000 D11EBFC6 0000 811EBFC6 F333 D11EBFC8 03E8 811EBFC8 0000 cn Facility Back Zone In Multiplayer\Part 3\2 players cd All parts must be on for this code to work.this cheat allows you to play the Facility Back Zone In Multiplayer D11EBFCA 0000 811EBFCA F0C4 D11EBFCE 4CCC 811EBFCE 000A D11EBFD2 4CCC 811EBFD2 000A D11EBFD4 0003 811EBFD4 0000 D11EBFD6 0000 811EBFD6 02C4 801EBFD9 0004 801EBFDB 0000 811EBFE2 0384 801EBFE7 0004 801EBF45 009E 801EBF47 0084 801EBF48 0010 801EC2D9 0000 801EC447 0085 801EC547 0086 811EA6B6 2743 811EA73E 0114 811EA7F2 0115 811EA8A6 00A3 811EA92E 009D 811EA9E2 00A4 811EAA96 00DA 811EAB1E 00DB 811EABD2 00DF 811EAC86 0130 811EAD0E 008D 811EADC2 012E 811EAE76 0111 811EAEFE 2740 811EAFB2 2741 811EB066 00A0 811EB0EE 009E 811EB1A2 009F 811EB256 274F 811EB2DE 2750 811EB392 0117 811EB446 0131 811EB4CE 008E 811EB582 0132 811EB636 00A1 811EB6BE 0119 811EA62E 00FA 801ED3DF 0000 801ED2DF 0001 D0024337 0007 80024337 001F cn All 64 Characters In Multi Player 800266E7 0040 cn Replace Cradle with Citadell hidden level 80025E47 0029 8103DB6A D9B4 8103DB70 3F44 8103DB72 BDEA 8103DB74 3F80 8103DB76 0000 8103DB78 4219 8103DB7A D89D 81058EC0 C470 cn Secret Island on Dam Level cd For the above code to work,Get to the 2nd guard tower & go down the ladder on the left hand side & to the end of the Dock, Press L & GS and you will be transfered in the water. Just keep walking straight & you will get to it. Obviously you can't actually climb ladders or anything, you will simply walkthrough anything on that Part, if you want to walk back to the Dock, when you come near it click the cheat back on & keep pressing L & GS untill you are back on it. D004C2D1 0020 800BA78D 0050 880BA78D 0000 crc 3B941695-F90A5EEB-C:50 gn 007 The World is Not Enough (E) cn Invincible 811147D8 0101 cn Access Levels & Difficulties 81103B66 0021 50000D01 0000 80118F38 0001 cn Infinite Time 81103B82 0000 cn Infinite Oxygen 800E25E4 0004 cn Multi Player\Access All Arenas 801147EB 0001 811147EC 0101 801147EE 0001 cn Multi Player\Access All Scenarios 801147EF 0001 811147F0 0101 cn Multi Player\Access All Weapon Modes 811147F2 0101 801147F4 0001 cn Multi Player\Access All Evil Skins 50005C0C 0000 800C0167 0081 cn Multi Player\Access Good Q 800C06EF 0001 cn Multi Player\Access Evil Q 800C06EF 0081 cn Multi Player\Invincible 811147D8 0101 crc 58FD3F25-D92EAA8D-C:50 gn 1080 SNOWBOARDING cn Infinite Damage All Players and Levels 803F4C01 0000 cn Prees L For Infinite Lives & Continues cd Whenever you've lost a life, Press L.Do not press L when on the main menu or during the intro Only use this feature in Match Race D00556A9 0020 8026B14B 0003 cn Enable All Levels & Boarders 80250AB9 00FF 80250ABB 0005 81250AC6 FCFF 80250AC8 0007 cn Stop Timer\Time Attack\Air Make 8031AA4A 0000 cn Stop Timer\Time Attack\Half Pipe 802F638A 0000 cn Stop Timer\Time Attack\Crystal Lake 802A582A 0000 cn Stop Timer\Time Attack\Crystal Peak 802B2BCA 0000 cn Stop Timer\Time Attack\Golden Forrest 802B135A 0000 cn Stop Timer\Time Attack\Mountain Village 802CB95A 0000 cn Stop Timer\Time Attack\Dragon Cave 802C137A 0000 cn Stop Timer\Time Attack\Deadly Fall 802CF56A 0000 cn Stop Timer\Trick Attack\Air Make 8031AABA 00C5 cn Stop Timer\Trick Attack\Half Pipe 802F63FA 00C5 cn Stop Timer\Trick Attack\Crystal Lake 8029F66A 00C5 cn Stop Timer\Trick Attack\Crystal Peak 802AC8EA 00C5 cn Stop Timer\Trick Attack\Golden Forrest 802AAF5A 00C5 cn Stop Timer\Trick Attack\Mountain Village 802C50DA 00C5 cn Stop Timer\Trick Attack\Dragon Cave 802BAD3A 00C5 cn Stop Timer\Trick Attack\Deadly Fall 802C8E0A 00C5 cn Stop Timer\Contest\Crystal Lake 8029C0DA 00C5 cn Stop Timer\Contest\Crystal Peak 802A889A 00C5 cn Stop Timer\Contest\Golden Forest 802A6D3A 00C5 cn Stop Timer\Contest\Air Make 80319BBA 00C5 cn Stop Timer\Contest\Half Pipe 802F51FA 00C5 cn Play As 8001A0E7 ???? 0000:"Dion Blaster",0001:"Kensuke Kimachi",0002:"Akari Hayami",0003:"Ricky Winterborn",0004:"Rob Haywood",0005:"Silver Boarder",0006:"Gold Boarder",0007:"Panda Boarder" crc 8F12C096-45DC17E1-C:50 gn A Bug's Life cn Infinite\Lives 801E2460 0009 cn Infinite\Health 801E2455 0004 cn Always Have\Super Jump 811E2450 0020 cn Always Have\50 pieces of corn 801E2461 0032 cn Have F-L-I-K 801E2462 000F cn Levitate cd "Press R To Levitate & Let go to land (:" D008FCE1 0010 801E23C6 0001 D008FCE1 0010 801E23D6 0001 cn Unlock All Levels 81099B70 000F cn Have All Goldberry Tokens D01E244E 0000 801E244E 0000 cn Start with Berry Weapon 801E2457 ???? 0001:"Blueberry",0002:"Homing Berry",0003:"Goldberry",0004:"Super Berry ?" cn All enemies killed 801E244E 0000 801E244F 0000 crc 62F6BE95-F102D6D6-C:50 gn AERO FIGHTERS ASSAUL cn Extra Planes 8127D69C FFFF cn Infinite\99 Lives 80355748 0063 cn 99 Bonus 80131537 0063 cn 99 Accuracy 80131530 0063 cn Gun Select 8027E9D3 ???? 0000:"Chaff",0001:"Jammings",0002:"Air Mines",0003:"Mahibishi",000A:"22mm BB Shot",000B:"22mm",000C:"Hunai Shot",000D:"Fireball",000E:"Sabre",0014:"Fire",0015:"Tomahawk",0016:"Ninja Glitch",0017:"Fire Wave",001E:"Rocket",001F:"Phoenix",0020:"Star",0021:"Fire Arrow",0028:"Ninjabeam" cn Infinite\Chaffs 8027E9C7 000A cn Infinite\Gun 8027EAC0 0001 cn Infinite\Special Weapons 8027EE82 0002 cn Infinite\Armor 8127D9A4 44A0 8127D9A8 44A0 cn Infinite\Health 8027D9A5 00C8 8027D9A9 00C8 cn Always Have\F-15J Eagle 8027D69C 0010 cn Always Have\X-29A A.T.D. 8027D69D 0020 cn Stage Select screen unlocked cd Hold L + R at the Game Mode screen and it will unlock every single level in the game; from Tokyo to Space. Do not hold L + R on any other screen, as this may cause game to freeze D0281691 0030 8027D5C0 000A D0281691 0030 8027D5DA 000A cn All Boss Attack levels unlocked cd Unlocks all planes in death match 80355701 003F cn F-15J Eagle & X-29A A.T.D. planes unlocked 8035575C ???? 0010:"F-15J Eagle",0020:"X-29A A.T.D.",003F:"Both of the above planes" crc D83045C8-F29D3A36-C:50 gn AEROGAUGE cn No Damage\Player 1 50000402 0000 8113F338 0000 cn No Damage\Player 2 50000402 0000 811413D8 0000 cn Unlock Hidden Tracks & Cars cd All of the Freeze All Lap Timers must be on. These codes will Stop the others from racing against you in Grand Prix mode. To win a race in Grand Prix you must finish at least one lap in the qualify round, then complete all laps in race for first. 8009127C 0001 cn Freeze All Timers 8013F001 0000 8013F005 0000 8013F00A 0000 cn Freeze Overall Timer cd All of the Freeze All Lap Timers must be on. These codes will Stop the others from racing against you in Grand Prix mode. To win a race in Grand Prix you must finish at least one lap in the qualify round, then complete all laps in race for first. 8013EFF5 0001 cn Laps Of Race 8013EFEF ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"Never Ending Laps" cn Play As\Player 1 8013F2F5 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Play As\Player 2 8013F2F6 ???? 0000:"N64 Control Pad",0001:"Interceptor",0002:"Hornet",0003:"Avenger",0004:"Shredder",0005:"Black Lightning",0006:"Vengeance",0007:"Prowler",0008:"Reaper",0009:"Dominator" cn Level Select cd For this cheat to work,as soon as you put the cheat on you must turn it back off,if not you wont beable to quit a Race or even finish one. 8013F2FB ???? 0000:"Canyon Rush",0001:"Bikini Island",0002:"China Town",0003:"Neo Arena",0004:"China Town Jam",0005:"Neo Speed Way" cn Always 1st 8013F040 0001 cn Music Modifier 800F715F ???? 00FF:"Music On",0000:"Music Off" cn Language Select 8008CF93 ???? 0000:"English",0001:"French",0002:"German" crc 2DC4FFCC-C8FF5A21-C:50 gn Aidyn Chronicles - The First Mage (E) cn Infinite\Max Health 80279308 001E cn Infinite\99 Health Potions cd Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game. 8027876B 0063 cn Have\Max Gold 50000401 0000 80277AA5 00FF cn Have\Max Total XP 50000401 0000 8027931D 00FF cn Have\Max Total XP Remaning to Start cd This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats 50000401 0000 80279321 00FF crc 27C425D0-8C2D99C1-C:50 gn Airboarder 64 (E) cn Infinite Turbo\Player 1 80166019 0009 cn Infinite Turbo\Player2 80167991 0009 cn Infinite Time\Street Work & Coin 8010FA09 0028 cn Infinite Time\Attack Time Time 000000 8110FA0A 0000 cn Infinite Time\Time Attack 8010FA0B 0000 cn Access All Boards & Characters 80050071 000C cn Maxed Out Turbo Bar 811656E8 429F 80166017 0051 cn Class Score Select 8016609E ???? 0020:"Class C",0040:"Class B",0064:"Class A",00FF:"Class S" cn Coin Perfect Select cd this is for Coin Mode to get Perfect Coin Collection Score straight away when you enter the level 801660B3 ???? 0014:"Green Park Level 1",001A:"Green park Level 2",002B:"Green park Level 3",004A:"Lost Forest Level 1",0059:"Lost Forest Level 2",0080:"Lost Forest Level 3",007D:"Snow Festival 64 Levels 1 2 & 3",006F:"Sunset Island Level 1",0074:"Sunset Island Level 2",0081:"Sunset Island Level 3",006E:"Giant House Level 1",0077:"Giant House Level 2",0072:"Giant House Level 3" cn Options\Music Modifier 80050059 ???? 00FF:"BGM On",0000:"BGM Off" cn Options\Sound Effects Modifier 8105005A ???? 00FF:"SE On",0000:"SE Off" cn Options\Camera Type Modifier 81050056 ???? 0000:"Roll On Near",0001:"Roll On Mid",0002:"Roll On Far",0003:"Roll Off Near",0004:"Roll Off Mid",0005:"Roll Off Far" cn Options\DJ Function Modifier 8105005C ???? 0001:"DJ Function On",0000:"DJ Function Off" cn All Street Work Levels Unlocked 50007801 0000 80050120 ???? 0001:"Courses unlocked",0003:"Courses unlocked with C rank",0004:"Courses unlocked with B rank",0005:"Courses unlocked with A rank",0006:"Courses unlocked with S rank" crc 3CC77150-21CDB987-C:50 gn Armorines - Project S.W.A.R.M. (E) cn Enable In-Game Cheat Menu & Level Select 81115936 014F cn Infinite Ammo (All Guns) 810496D0 2400 cn Don't Take Any Damage 8104A260 2400 crc D9EDD54D-6BB8E274-C:50 gn All Star Baseball '99 (E) cn The Home Team Has Max Score 8107972A FFFF cn The Away Team Has Max Score 81080082 FFFF crc DFD784AD-AE426603-C:50 gn All Star Tennis '99 (E) cn Game Win Select\Player 1 801BAEB1 ???? 0000:"0 Games Won",0001:"1 Game Won",0002:"2 Games Won",0003:"3 Games Won",0004:"4 Games Won",0005:"5 Games Won",0006:"For Game Set & Match" cn Game Win Select\Player 2 801BAEB2 ???? 0000:"0 Games Won",0001:"1 Game Won",0002:"2 Games Won",0003:"3 Games Won",0004:"4 Games Won",0005:"5 Games Won",0006:"For Game Set & Match" cn Points Select\Player 1 801C6160 ???? 0000:"0 Points",0015:"15 Points",0030:"30 Points",0040:"40 Points" cn Points Select\Player 2 801C6161 ???? 0000:"0 Points",0015:"15 Points",0030:"30 Points",0040:"40 Points" crc B210DF19-98B58D1A-C:50 gn Army Men Sarge cn Infinite Health 8016471F 0001 cn Access\All Guns 8015E0CF 0001 cn Access\Max Ammo 801646EF 0001 cn Have Small Mode cd Do not use with Have Big Mode only use one at a time 8015E0C9 0001 cn Play As Tin Soldier cd Do not use this with any other play as option. 8015E0D3 0001 cn Invisible to most enemies 8015E0B3 0001 cn Play As cd Here you can choose who you would like to play as. But Do not use this with any other play as option.. 811653D2 ???? 0007:"The Big Green One",0008:"Vikki",0009:"Plastro" cn Have Big Mode cd Do not use with Have Small Mode only use one at a time 8016470F 0001 cn Have Debug Mode cd When this code is activated, a display of numbers will show on the screen as the players move around 8015E417 0001 crc FC7797BF-4A95E83C-C:50 gn LAMBORGHINI cn Access All Bonus Cars 50000302 0000 80098583 0001 50000302 0000 8009858B 0001 cn Max Points 810CE702 010A cn Infinite Lap Time 8109872C 0000 8109872E 0000 cn Always 1st Place 810A5F30 0001 cn Start On Lap Modifier D00A5F35 0000 810A5F34 ???? 0000:"Normal",0001:"Lap 1",0002:"Lap 2",0003:"Lap 3",0004:"Lap 4",0006:"Lap 5",0006:"Lap 6",0007:"Last Lap from Start" cn Track Direction Unlocked (All Levels) 800A4131 0003 crc 733FCCB1-444892F9-C:50 gn Banjo-Kazooie (E) cn Infinite\Lives 8038696B 0009 cn Have\Running Shoes 8137CA88 5019 cn Have\Zero Time all Levels 50000B04 0000 813869E4 3000 cn Have\Blubbers Gold 80386973 00FF cn Have\Present Option\Green 8038698F 00FF cn Have\Present Option\Blue 80386993 00FF cn Have\Present Option\Red 80386997 00FF cn Have\Nabnuts Acorns 8038699F 00FF cn Have\Eyries Caterpillars 8038699B 00FF cn Have\Chimpys Oranges 80386977 00FF cn Have\All Jinjos 8038695B 00FF cn Yumblies Counter\Mr Vile 8038697C 00FF cn Yumblies Counter\Banjo 8038697B 00FF cn Press L To Levitate cd Press L To Levitate & Let go to land D0285735 0020 8137CE8C 43E0 cn Do Anywhere Option\Take off anywhere cd Press A D0285734 0080 8037CBA1 0001 cn Infinite\Health 80386963 0008 80386965 0001 cn Infinite\8 Skulls 803869A7 0008 cn Infinite\255 Jigsaws 803869AB 00FF cn Infinite\Air 8038696E 000B cn Infinite\255 Notes 80386943 00FF cn Infinite\255 Eggs 80386947 00FF cn Infinite\255 Gold Feathers 80386953 00FF cn Infinite\255 Red Feathers 8038694F 00FF cn Access All Moves 8037CD70 0001 8037CD71 007F 8037CD72 00FF 8037CD73 00FF crc C9176D39-EA4779D1-C:50 gn BANJO TOOIE cn Infinite\Energy\Banjo and Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0A0A 81120794 0A0A cn Infinite\Energy\Snowball cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 80120797 0005 cn Infinite\Energy\Bee cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 801207A3 000A 801207A4 000A cn Infinite\Energy\Washing Machine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 811207A6 0A0A cn Infinite\Energy\Stony cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 801207A9 000A 8011B65A 000A cn Infinite\Energy\Banjo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 801207AF 000A 801207B0 000A cn Infinite\Energy\Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 811207B2 0A0A cn Infinite\Energy\Submarine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 801207B5 000A 801207B6 000A cn Infinite\Energy\Mumbo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 811207B8 0A0A cn Infinite\Energy\Detonator cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 811207BE 0A0A cn Infinite\Energy\T-Rex Baby cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 801201B9 0063 801207CF 000A 801207D0 000A cn Infinite\Air 8112FFD2 42C8 cn Play As cd To use this cheat, put the cheat on, then press L as you walk through a door to become that chosen character D008B494 0020 8012BFAC ???? 0001:"Banjo and Kazooie",0002:"Snowball",0006:"Bee",0007:"Washing machine",0008:"Stony",000A:"Banjo",000B:"Kazooie",000C:"Submarine",000D:"Mumbo",000E:"Golden Goliath",000F:"Detonator",0010:"Truck",0012:"T-rex baby",0013:"T-rex daddy" cn Instant Warp\Options\Not sure cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 00FC:"Lord woo fak fak",00F9:"Mr Patch",0121:"Inside Chuffy's wagon",0134:"Mumbo's Skull",0135:"Humba Wumba's wigwam 1",0157:"Humba Wumba's wigwam 2",019B:"Jingalings Zombified Palace",01A6:"Smuggler cavern",0141:"Inside the digger tunnel",0143:"Bottles house",0169:"Bottles house still",018A:"HAG Inside",019A:"HAG1 Final Boss" 8012C5A3 0001 cn Instant Warp\Options\Spiral Mountain cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 00AD:"Grunty's Old Lair",00AE:"Behind The Waterfall",00AF:"Top Of Castle",0173:"Banjo's house" 8012C5A3 0001 cn Instant Warp\Options\Jinjo Village cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 0142:"Jinjo Village",0144:"King Jingalings throne room",0143:"Bottles house",0145:"Green Jinjo's House",0146:"Black Jinjo's House",0147:"Yellow Jinjo's House",0148:"Blue Jinjo's House",014A:"Brown Jinjo's House",014B:"Orange Jinjo's House",014C:"Purple Jinjo's House",014D:"Red Jinjo's House",014E:"White Jinjo's House" 8012C5A3 0001 cn Instant Warp\Options\Mayahem Temple cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 00B6:"Humba's Wigwam",00B7:"Mumbo's skull",00B8:"The Temple",00B9:"Prison Compound",00BC:"Code chamber",00C4:"Jade Snake Grove",00C5:"Treasure Chamber",00C6:"Kickball Arena",0177:"Targitzan's Slighty Sacred Temple",0178:"Inside Targitzans Temple",0179:"Targitzan Temple Lobby",017A:"Targitzan's Temple Boss",017F:"Mayan Kickball Arena",0166:"Multi",0167:"Still",00C8:"Kickball Arena",00C9:"Kickball Arena" 8012C5A3 0001 cn Instant Warp\Options\Glitter Gulch Mine cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 00C7:"Mine",00CA:"Fuel depot",00CB:"Crushing shed",00CC:"Flooded caves",00CD:"Water storage",00CE:"Waterfall cavern",00CF:"Power hut basement",00D0:"Chuffy's cab",00D1:"Inside chuffy's boiler boss",00D2:"Gloomy caverns",00D3:"Generator caverns",00D4:"Power hut",00D5:"Wumba's wigwam",00D7:"Train station",00D8:"Prospectors hut",00D9:"Mumbo's hut",00DA:"Toxic gas cave",00DB:"Canary cave",00DC:"Ordnance storage",00E9:"Humba",0126:"Water supply pipe",0163:"Ordnance Storage entrance",0164:"Ordnance Storage game",0165:"Ordnance Storage game Multi",016F:"Testing",0170:"Testing",0171:"Mumbo's skull" 8012C5A3 0001 cn Instant Warp\Options\Witchy World cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 00D6:"Witcy World",00DD:"Dodgem dome lobby",00DE:"Dodgem challenge \"1 vs 1\"",00DF:"Dodgem challenge \"2 vs 1\"",00E0:"Dodgem challenge \"3 vs 1\"",00E1:"Crazy castle stockade",00E2:"Crazy castle lobby",00E3:"Crazy castle pump room",00E4:"Balloon burst game",00E5:"Hoop hurry game",00E6:"Star spinner",00E7:"The inferno",00EA:"Cave of horrors",00EB:"Haunted cavern",00EC:"Train station",0124:"Saucer of Peril",013B:"Crazy castle stockade \"sop\"",013C:"Star spinner \"sop\"",0176:"Mumbo's skull" 8012C5A3 0001 cn Instant Warp\Options\Jolly Roger's Lagoon cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 00ED:"Jolly's",00EE:"Pawno's emporium",00EF:"mumbo's skull",00F4:"Ancient Swimming Baths",00F6:"Electric Eels lair",00F7:"Seaweed Sanctum",00F8:"Inside the big fish",00FA:"temple of the fishes",01A8:"Atlantis",01A9:"Seabottom",0181:"sea bottom cavern",0182:"submarine multi",01A7:"Jolly Roger's Lagoon",00FF:"Blubber's wave race hire" 8012C5A3 0001 cn Instant Warp\Options\Terrydacty Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 0112:"Terrydacty Land",0113:"Terry's nest",0114:"Train station",0115:"Oogle boogles cave",0116:"Inside the mountain",0117:"River passage",0118:"Styracosaurus family cave",0119:"Unga bunga's cave",011A:"Stomping plains",011B:"Bonfire caverns",011E:"Humba's Wigwam",0123:"Inside chompa's belly",0183:"Chompa's belly multi" 8012C5A3 0001 cn Instant Warp\Options\Grunty Industries cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 0100:"Outside",0101:"Inside",0102:"Train station",0103:"Workers quarters",0104:"Trash compactor",0105:"Elevator shaft",0106:"Floor 2",0107:"Floor 2 \"electromagnet chamber\"",0108:"Floor 3",0109:"Floor 3 \"boiler plant\"",010A:"Floor 3 \"packing room\"",010B:"Floor 4",010C:"Floor 4 \"cable room\"",010D:"Floor 4 \"quality control\"",010E:"Floor 5",010F:"Basement",0110:"Basement \"repair depot",0111:"Basement \"waste disposal\"",0125:"Water supply pipe",0172:"Mumbo's skull",0162:"Floor 4 \"clinkers cavern\"",0187:"Sewer entrance" 8012C5A3 0001 cn Instant Warp\Options\Hailfire Peaks cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 0127:"Lava side",0128:"Icy side",0129:"Lava train station",012A:"Ice train station",012B:"Chilli billi",012C:"Chilly willy",012D:"Colosseum kickball stadium lobby",0131:"Boggy's igloo",0132:"Icicle grotto",0133:"Inside the volcano",0168:"Icy side still" 8012C5A3 0001 cn Instant Warp\Options\Cloud Cuckoo Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 0136:"Cloud Cuckoo Land 1",0137:"Inside the trashcan",0138:"Inside the cheesewedge",0139:"Zubba's nest",013A:"Central cavern",013D:"Inside the pot o gold",013E:"Mumbo's skull",013F:"Mingy jongo's skull",0140:"Humba wumba's wigwam",0161:"Cloud Cuckoo Land 2",0188:"Zubba's nest multi",0185:"Trash can mini" 8012C5A3 0001 cn Instant Warp\Options\Isle O Hags cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 014F:"Wooded Hollow",0150:"Heggy's egg shed",0151:"Jiggywiggy's temple",0152:"Plateau",0153:"Plateau \"Honey B's Hive\"",0154:"Pine Grove",0155:"Cliff top",0156:"Cliff top Mumbo's skull",015A:"wasteland",015B:"inside another digger tunnel",015C:"Quagmire" 8012C5A3 0001 cn Instant Warp\Options\Cauldron Keep cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B494 0000 8112C5A0 ???? 015D:"Cauldron Keep",015E:"The gatehouse",015F:"Tower of Tragedy Quiz",0160:"Gun chamber",016A:"Gun room still",017B:"Crazy Castle Stockade balloon burst multi",017C:"Crazy Castle Stockade Jump the hoops multi",017D:"Grunty Industries packing game",0180:"Colosseum kickball arena",0186:"Dodgems" 8012C5A3 0001 cn Beta Bottles Revenge Mode cd Bottles Revenge is a Beta mode from Banjo Tooie that the RWP team recently uncovered after an extraordinary amount of effort. Bottles the Spirit transforms into Bottles the Devil and posses enemies nearby and allows a second player hooked up to Pad 2 to play as that Posses character to try to foil Banjos Plans. As player one goes about its business, player two uses every enemy nearby to try to nab Banjo and take away some life. This mode is incredible, and you can control almost every enemy in the game: slot machines, flying creatures, uggers, zubbas...and this is just the beginning. (Congrats Rare Witch Project) 80130402 0001 8008B4D1 0002 crc B088FBB4-441E4B1D-C:50 gn Bass Hunter 64 (E) cn All Lakes Available 80119800 0001 cn Unbreakable Line 80119805 0001 cn Large Fish 80119806 0001 cn Fish Are More Active 80119807 0001 cn No Penalties During Tournamet 80119808 0001 cn No Snags While Fishing 80119809 0001 cn Extra $300 8011980B 0001 cn More fish in Lakes 8011980D 0001 cn Super Lure 8011980E 0001 cn Easy Win Current Tournament 8011980F 0001 cn Access\All Lures cd Codes To Be Used With Save Slot 1 8019A1A9 0003 8119A1AA FFFF cn Access\All Poles 2 cd Codes To Be Used With Slot 1 8019A1AC 0007 cn Access\Extra Boat 2 cd Codes To Be Used With Slot 1 8019A1AD 0001 crc 259F7F84-7C9EED26-C:50 gn Batman Beyond - Return of the Joker (E) cn Infinite\Health 801D7F3C 0064 cn Infinite\99 Lives 801D7F3D 0063 cn Infinite\Infinite 99 Dark Night Discus's 801D7F4A 0063 cn Infinite\Max Charge & Magnetic Nun Chaku 801D7F05 0064 crc 0CAD17E6-71A5B797-C:50 gn BattleTanx - Global Assault (E) cn Infinite Tank Credits 8124AB3E 02F4 cn Score Aid 8124A152 FC9A cn Inincibility 81121420 0100 cn All Weapons & Invulnerable 81121420 0101 cn Level Select 811150B8 0001 cn All Tanx & All Campaigns 50001370 0000 81120546 FFFF 50001370 0000 8112054A FFFF cn Infinite Edge Power 811A8D20 000A 8111AD08 000A 811AC1E4 000A 811ACB7E 000A 811AAEB4 000A 811AE378 000A 811AD514 000A 811AA51C 000A crc A1B64A61-D014940B-C:50 gn Beetle Adventure Racing (E) cn Access All\Cars 8002CFF7 000B cn Access All\Tracks 8002CFF3 0006 cn Access All\Difficulties 8002CFFB 0003 cn Access All\Multiplayer Levels 50000901 0000 8002D000 0001 cn Access In-Game Cheats 50001301 0000 8002D008 0001 cn Display On 81025EC6 0100 cn Map Full 81025E6A 0102 cn Speed units\Kph or Mph cd Here you can choose what you would like to be Displayed on your Speed Ometer, As in Kilometres Per Hour, Or Miles Per Hour. 81025E68 ???? 0100:"Kph",0001:"Mph" cn Max Race Points 8102CBC0 03E7 cn Flat Shading 81025CF6 0000 crc 7C64E6DB-55B924DB-C:50 gn Blast Corps (E) cn Infinite Hydraulics Sidesweeper 803EDB51 0063 cn Infinite Missiles Motor Bike 803F8AC3 0063 cn Infinite Boosts Buggy Vehicle 803EE301 0064 cn Ballista Can Drive Through Anything 803F8A68 0001 cn Found All RDUS 8036E9CC C350 cn Found All Survivors 8036E9C9 00FF cn Found All Scientists 80364AD0 003F crc AB7C101D-EC58C8B0-C:50 gn Bio F.R.E.A.K.S. (E) cn Infinite Health\Player One 811507FA 6400 cn Infinite Shields\Player One 811507FE 6400 cn Shields Always Active\Player One 8015080A 0022 cn Infinite Jet Pack\Player One 81150802 3200 cn Smoke Trail\Player One 80150804 0001 cn Player 2 Easily Defeated\Player One 81152E76 0100 81152E7A 0100 cn Infinite Health\Player Two 81152E76 6400 cn Infinite Shields\Player Two 81152E7A 6400 cn Shields Always Active\Player Two 80152E86 0022 cn Infinite Jet Pack\Player Two 81152E7E 3200 cn Smoke Trail\Player Two 80152E80 0001 cn Player 1 Easily Defeated\Player Two 811507FA 0100 811507FE 0100 crc D571C883-822D3FCF-C:50 gn Blues Brothers 2000 (E) cn Have All\Keys cd This will give you the Grey & Red,Green & Gold Keys 800BE268 00FF 800BE26D 00FF 800BE26E 00FF cn Have All\Music Notes cd This will give you all 10 Music Notes 50000A01 0000 800BE3A0 0001 cn Infinite\Lives 800BE293 0009 cn Infinite\Health 800BE2A7 0002 cn Press L to Levitate cd Press L to levitate & let go to come back down D017E975 0020 810DBD88 44CB cn Max Money 810BE296 03E7 crc 0B58B8CD-B7B291D2-C:50 gn Body Harvest (E) cn Infinite\Greece 81052B48 0098 81052B4A 967F cn Infinite\Health 8004DD1C 0002 cn No Humans Killed 8104819A 0000 cn Have Alien Artifact 8004DC8F 0001 cn Item Modifier 8004DC7F ???? 0000:"Nothing",0002:"Howitzer Shells",0040:"Crank",0080:"Windmill Cog",0100:"Heirglyph Map Piece",0400:"Hangar Key",FFFF:"All Items" cn Weapon Select\1st Position 80048168 ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\2nd Position 80048169 ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\3rd Position 8004816A ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\4th Position 8004816B ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\5th Position 8004816C ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\6th Position 8004816D ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\7th Position 8004816E ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Weapon Select\8th Position 8004816F ???? 0000:"Nothing",0001:"Fuel",0002:"Pistol",0003:"Shotgun",0004:"Rifle",0005:"Machine Gun",0006:"Rocket Launcher",0007:"TNT",0008:"Sun Shield",0009:"Grenades",000A:"Tri-Spinner",000B:"Vehicle Weapon 1",000C:"Vehicle Weapon 2",000D:"Arme 2",000E:"Waffe 2",0010:"Fragcannon",0011:"Lazer Missiles",0012:"Resonator",0013:"Plasma Bombs" cn Infinite Ammo All Weapons 50001102 0000 81048176 8000 cn Level Select 80047FC3 ???? 0001:"Greece",0002:"Java",0003:"America",0004:"Siberia",0005:"Comet" cn Press L To Wall Over Water, Climb Hills D0047609 0020 8104DD02 0808 cn Infinite\Fuel 8004E46C 0050 crc D85C4E29-88E276AF-C:50 gn Bomberman Hero (E) cn Full\Bomb Power 8016523F 0003 cn Full\Fire Power 80165240 0008 cn Infinite\Health 80165244 0004 cn Infinite\Lives 80165243 0009 cn Extra Gems D0165241 0000 80165241 004B cn Max\Bombs 8016523F 0008 cn Press L to Levitate cd Press L to levitate & let go to come back down D005A465 0020 81154178 41CB D005A465 0020 D0154154 0000 80154154 0040 cn Max\Score 80177608 FFFF cn Max\Explosion 80165240 0008 crc 5A160336-BC7B37B0-C:50 gn Bomberman 64 (E) cn Infinite\Lives 802AC617 0063 cn Infinite\Gems 802AC61F 0063 cn Infinite\Credits 802AC61B 0063 cn Infinite\Time 802AC633 0000 cn Have All Gold Cards 8008E575 00FF 8108E576 FFFF 8108E578 FFFF 8108E57A FFFF 8108E57C FFFF cn All Levels & Stages Unlocked 50001804 0000 8008E5CF 0001 cn Infinite Red Pumped-Up Bombs 802AC643 0004 crc D5B2339C-CABCCAED-C:50 gn Buck Bumble (E) cn Have All\Guns & Infinite Ammo cd Press C Left to receive all Guns 81102C0A 0001 50000B04 0000 810EBF66 03E8 cn Infinite\Health cd If you fall into Water just turn off the Infinite Health & put back on when you restrat. 810EBF58 42D8 cn Infinite\99 Lives 810EC2D2 03E7 cn Level Select Menu 801022CA 0EF0 cn Have All\Keys 810EBF60 0001 800EBF61 0001 810EBF62 0001 cn High Score 810EBF4E FFFF cn Max Bonus 810EC2CA 270F crc CEDCDE1E-513A0502-C:50 gn Bust-A-Move 2 - Arcade Edition (E) cn Infinite Credit 80120171 00FF cn Bubble Pointer Puzzle 801807CD 0001 cn Bubble Pointer 1P V CPU 8017E1FD 0001 cn Access Another World cd This is for Puzzle Mode 8116D100 0001 cn Max Points Aid 81170E4A 25C2 crc E328B4FA-004A28E1-C:50 gn Bust A Move 3 DX cn Always have guide line on 80056CCC 0082 cn Pointer always active D0056FA0 0002 80056FA0 0082 cn Play As Select\Player 1 800E3250 ???? 0000:"Bubbloon",0001:"Twinkie",0002:"Prettio",0003:"Marina",0004:"Musashi",0005:"Luna",0006:"Jack",0007:"SSB",0008:"Dragoon",0009:"Gnome",0010:"Monkey",0011:"furby? (looks like 2 balloons)",0012:"Blue Gnome",0013:"1 of the two Ballons",0014:"Water under ballons" cn Play As Select\Player 2 800E3258 ???? 0000:"Bubbloon",0001:"Twinkie",0002:"Prettio",0003:"Marina",0004:"Musashi",0005:"Luna",0006:"Jack",0007:"SSB",0008:"Dragoon",0009:"Gnome",0010:"Monkey",0011:"furby? (looks like 2 balloons)",0012:"Blue Gnome",0013:"1 of the two Ballons",0014:"Water under ballons" cn Next Bubble Select\Player 1 800ECE19 ???? 0000:"No Bubble",0001:"Red",0002:"Green",0003:"Blue",0004:"Yellow",0005:"Orange",0006:"Purple",0007:"White",0008:"Black" cn Next Bubble Select\Player 2 800ECF09 ???? 0000:"No Bubble",0001:"Red",0002:"Green",0003:"Blue",0004:"Yellow",0005:"Orange",0006:"Purple",0007:"White",0008:"Black" cn Press GS to Reset Player 2 score to 0 8809D9C0 0000 8809D9C2 0000 crc 64F1B7CA-71A23755-C:50 gn CASTLEVANIA cn Infinite\Health 81389C42 0064 cn Infinite\Throwing Weapon 81389C4C 0064 cn Throwing Weapon Modifier 81389C46 ???? 0000:"Nothing",0001:"Knives",0002:"Exploding Potions",0003:"Cross",0004:"Axes" cn Press L To Levitate D0387D7F 0020 81350810 3FCB cn Have\All Items 50000501 0000 80389C4E 0001 50000301 0000 80389C55 0001 80389C5E 0001 80389C5F 0001 80389C61 0001 50000E01 0000 80389C64 0001 cn Have\Invincibility 80342BFE 000B cn Infinite\Red Jewels 80389C4D 0064 cn Status 80389C8C ???? 0001:"Good",0008:"Vamp",0011:"Poison",0022:"Good but depressed",0066:"Sto",001F:"V+P" cn Open All Doors and Gates,No Bosses 50002A02 0000 81389BD0 FFFF cn Infinite\Energy 80389C33 0064 cn Infinite\Funds 80389C49 0001 81389C4A 869F cn Have\Exp Points 80389C4D 0063 cn Max Power Up 80389CF1 0002 cn Never Get Poisoned 81389C8C 0000 cn Level Select cd You must use this code on a saved game, because the intro to the first level will mess up the game. Now select the saved game, and hold down the GS button until the level loads. Some of the boss stages will not let you fight the boss unless you re-enter the area. Also, with the part of stage modifier, the second code modifies the part of the level that you are in, and 0000 is the level's start. 89389C94 ???? 0000:"Forest of Silence",0002:"Castle Wall",0003:"Villa",0004:"Inside Villa",0006:"Garden Maze",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",0010:"Tower of Execution",0011:"- Tower of Sorcery",0012:"- Tower of Science",0013:"- Duel Tower",0014:"- Fight With Death/Actrise",0015:"- Castle Keep",0016:"- Intro (Glitch)",0017:"- Clock Tower",0018:"- Final Dracula",001A:"- Fight With Maze Boss",001B:"- Room of Clocks",001C:"- ??",001D:"- ??" 89389C91 0000 cn Switch From cd This Switch From Cheat lets you switch characters on a saved game For example, if you are Reindhart and you want to be Carrie in the middle of your game save it and then enable this Cheat and press F1. when you start your saved game back up you'll be Carrie instead of Reindhart. 80389C41 ???? 0000:"Carrie to Reindhart",0001:"Reindhart to Carrie" crc A2C54BE7-6719CBB2-C:50 gn Castlevania - Legacy of Darkness (E) cn Keys Option\Have Clocktower Key B 801CC040 0001 cn Keys Option\Have Clocktower Key A 801CC03F 0001 cn Keys Option\Have Clocktower Key E 801CC03E 0001 cn Keys Option\Have Wall key 801CC03D 0001 cn Keys Option\Have Control Room Key 801CC03C 0001 cn Keys Option\Have Art Tower Key 2 801CC03B 0001 cn Keys Option\Have Art Tower Key 1 801CC03A 0001 cn Keys Option\Have Clocktower Key D 801CC039 0001 cn Keys Option\Have Clocktower Key C 801CC038 0001 cn Keys Option\Have Thorn Key 801CC037 0001 cn Keys Option\Have Rose Garden Key 801CC01A 0001 cn Keys Option\Have Deck Key 801CC035 0001 cn Keys Option\Have Execution Key 801CC034 0001 cn Keys Option\Have Chamber Key 801CC033 0001 cn Keys Option\Have Copper Key 801CC032 0001 cn Keys Option\Have Garden Key 801CC031 0001 cn Keys Option\Have Storeroom Key 801CC030 0001 cn Keys Option\Have Left Tower Key 801CC02F 0001 cn Keys Option\Have Archives Key 801CC02E 0001 cn Have Options\Rose Brooch 801CC02D 0001 cn Have Options\Crest Half B 801CC02C 0001 cn Have Options\Crest Half A 801CC02B 0001 cn Have Options\Oldreys Diary 801CC02A 0001 cn Have Options\Winch lever 801CC029 0001 cn Infinite Options\Moon Cards 801CC028 0001 cn Infinite Options\Sun Cards 801CC027 0001 cn Have Options\Mandragora 801CC026 0001 cn Have Options\Magical Nitro 801CC025 0001 cn Have Options\Contract 801CC024 0001 cn Have Options\Powerup 801CC01F 0001 cn Infinite Options\Cure Ampoule 801CC01E 0001 cn Infinite Options\Purifying 801CC01D 0001 cn Infinite Options\Healing kit 801CC01C 0001 cn Infinite Options\beef 801CC01B 0001 cn Infinite Options\chicken 801CC01A 0001 cn Have Options\Special Crystal 3 801CC019 0001 cn Have Options\Special Crystal 2 801CC018 0001 cn Have Options\Special Crystal 1 801CC017 0001 cn Infinite Options\Red Jewels 801CC015 0068 cn Infinite Options\Gold 811CC012 2710 cn Infinite Options\Health 811CC00A 2710 cn Weapon Modifier 801CC00F ???? 0000:"Nothing",0001:"Knife",0002:"Potion",0003:"Cross",0004:"Axe" cn Status Modifier 801CC054 ???? 0000:"Never Get Poisoned or Vamped",0001:"Normal",0004:"Vamp",0008:"Poison",000C:"Vamped & Poisoned",00FF:"Instant Death" cn Level Modifier 801CC349 ???? 0000:"Forest Of Silence",0001:"Left Tower",0002:"Castle Wall",0003:"Villa",0004:"Villa",0005:"Villa",0006:"Villa",001A:"Villa",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",000A:"Castle Center",000B:"Castle Center",000C:"Castle Center",000D:"Castle Center",000E:"Castle Center",000F:"Castle Center",0010:"Foggy Lake",0011:"Foggy Lake",0012:"Foggy Lake",0013:"Cave Of Spiderwomen",0014:"Castle Keep",0015:"Castle Keep",0016:"Falls Into Space(?)",0017:"Clock Tower",0018:"Final Battle Site",0019:"Castle Center",001B:"Room Of Clocks",001C:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",002B:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",001D:"Tower Of Sorcery",001E:"Tower Of Execution",001F:"Tower Of Execution",0020:"Tower Of Execution",0021:"Tower Of Science",0022:"Tower Of Science",0023:"Tower Of Ruins",0024:"Tower Of Ruins",0025:"Art Tower",0026:"Art Tower",0027:"Dual Tower",0028:"Clock Tower",0029:"Clock Tower",002A:"Outer Wall",002C:"Fall From Sky Ouside Of Castlevania Opening",002D:"Another Free Fall. Forest Where Girl Runs In Opening",002E:"Black Room(?)" cn Inter-Level Modifier 801CC34B ???? 0000:"Forest Of Silence",0001:"Left Tower",0002:"Castle Wall",0003:"Villa",0004:"Villa",0005:"Villa",0006:"Villa",001A:"Villa",0007:"Tunnel",0008:"Underground Waterway",0009:"Castle Center",000A:"Castle Center",000B:"Castle Center",000C:"Castle Center",000D:"Castle Center",000E:"Castle Center",000F:"Castle Center",0010:"Foggy Lake",0011:"Foggy Lake",0012:"Foggy Lake",0013:"Cave Of Spiderwomen",0014:"Castle Keep",0015:"Castle Keep",0016:"Falls Into Space(?)",0017:"Clock Tower",0018:"Final Battle Site",0019:"Castle Center",001B:"Room Of Clocks",001C:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",002B:"Countryside Where Carrie's Mom Is Buried.(Fall Through Ground)",001D:"Tower Of Sorcery",001E:"Tower Of Execution",001F:"Tower Of Execution",0020:"Tower Of Execution",0021:"Tower Of Science",0022:"Tower Of Science",0023:"Tower Of Ruins",0024:"Tower Of Ruins",0025:"Art Tower",0026:"Art Tower",0027:"Dual Tower",0028:"Clock Tower",0029:"Clock Tower",002A:"Outer Wall",002C:"Fall From Sky Ouside Of Castlevania Opening",002D:"Another Free Fall. Forest Where Girl Runs In Opening",002E:"Black Room(?)" cn Cut Scene Modifier 801CC363 0009 801CC35B ???? 0003:"Castle Drawbridge Lowers",0004:"Character Enters Castle",0005:"(?)",000A:"(?)",000C:"(?)",0020:"(?)",0021:"(?)",0022:"(?)",0006:"Vampire In Main Entrance Hall Of Villa",0007:"One Of The Working Gears Cut Scenes",0008:"\"I Smell Poison\" From Underground Waterway",0009:"Castle Gate Closes In Villa Upon Entering Villa",000B:"Renon Appears For First Time",000D:"Village Vampire In Upstairs Villa",000E:"Malus Appears For The First Time",000F:"Malus Leaves Garden",0010:"Character In Boat On Foggy Lake",0011:"Seal Removed From Wall In Arena",0012:"Bleeding Statue",0013:"Cosmic Lights",0014:"Explosion At Wall In Arena",0015:"Explosion At Wall In Castle That Leads To Hidden Room",0016:"Malus Appears Again In Upstairs Room Of Castle",0017:"Bull Awakens",0018:"Vincent The Vampire",0019:"One Of The Working Gears Cut Scenes",001A:"Gate Opens In Forest Of Silence",001B:"Meet Renon For The Last Time In Castle Keep.",001C:"This Cut Scene Runs Cut Scene 27 And 2E",001E:"Castle Keep Destructs",001F:"Malus On Flying Horse Outside Castle Keep",0024:"Spider People In Tunnel",0025:"Rosa In Garden",0027:"Castel Destruction",0028:"Space Warp",0029:"Castle Destruction",002A:"Malus Is Saved By Reinhardt",002B:"Malus And Reinhardt On Horse",002E:"Rosa Returns",0030:"Ada Henry And Cornell At Game End",0031:"Scrolling Text About Castle And Henry",0033:"Vampire In Basement",0034:"Vampire In Villa Basement Destroyed Woman Vampire Rises",0035:"Finds Hidden Path In Villa Basement",0037:"Lever & Gear In Castle",0038:"Harpie",0039:"Harpie Destroyed",0044:"Death(Grim Reaper)",0045:"Death Is Destroyed",0046:"Castle Drawbridge Closes And Ortega Appears",0047:"Thirsty Man",0048:"Cornell Meets Henry In Garden",0049:"Cornell And Henry Part In Garden",0051:"Monster Dracula Appears",0052:"Actrise Appears In Castle Center",0054:"Actrise Appears Again With Cousin Fernandes Before Fight With Carrie",0055:"Cousin Fernandes Is Destroyed",0056:"Actrise Appears Again Before Fight With Carrie",0057:"Actrise Defeated By Carrie" crc DCCF2134-9DD63578-C:50 gn Centre Court Tennis (E) cn Infinite Character Creation Points 8017BB17 000A cn Maximum\Serve Smash 8117BB0E 0A0A cn Maximum\Volley Lob 8117BB10 0A0A cn Maximum\Stroke Spin 8117BB12 0A0A cn Maximum\Back,Front,Left & Right Move 8117BB14 000A cn Left vs Right Side 8017BB16 0005 cn Max Score In Mini Games 81116230 05F5 81116232 E0FF cn Practice\Balls Always Zero 8011684F 0000 cn Practice\Time Always Zero 8111684A 0000 cn Scoreboard\Max sets top 80116983 0009 cn Scoreboard\Max games top 8011698B 0009 cn Scoreboard\Max sets bottom 80116987 0009 cn Scoreboard\Max games bottom 8011698F 0009 crc B9AF8CC6-DEC9F19F-C:50 gn Chameleon Twist (E) cn Access All Levels 8020860E 00FF 80208610 00FF cn Extra Crowns 80251857 0015 cn Infinite Health 80174DF3 000A cn Extended Tongue 8133185E FFFF crc 07A69D01-9A7D41A1-C:50 gn Chameleon Twist 2 (E) cn Infinite Health 8018BA7D 000F cn Max Collectable Items 80164501 0014 cn Have 6 Carrots 80164519 007E cn Have All\Levels 80164508 003F cn Have All\Costumes 8016451A 00FE cn Have All\Collectibles\Stage 1 80164510 0014 cn Have All\Collectibles\Stage 2 80164511 0014 cn Have All\Collectibles\Stage 3 80164512 0014 cn Have All\Collectibles\Stage 4 80164513 0014 cn Have All\Collectibles\Stage 5 80164514 0014 cn Have All\Collectibles\Stage 6 80164515 0014 cn Press L To levitate cd Press L To Levitate & Let go to land D018BAB5 0020 8118B9E0 4200 crc FB3C48D0-8D28F69F-C:50 gn Charlie Blast's Territory (E) cn Stop Timer From Counting Down (All Levels) 8101D4E0 2400 crc 2E359339-3FA5EDA6-C:50 gn =Chopper Attack (E) cn Max Score 81129716 FFFF cn Infinite Weapon\1st Position 8012972B 0063 cn Infinite Weapon\2nd Position 8012972F 0063 cn Infinite Weapon\3rd Position 80129733 0063 cn Infinite Weapon\4th Position 80129737 0063 cn Infinite Weapon\5th Position 8012973B 0063 cn Weapon Modifier\Gun Weapon 80129A13 ???? 0000:"No Weapon",0001:"Normal Shot",0002:"2-Way Shot",0003:"3-Way Shot",0004:"4-Way Shot" cn Gun 4-Way Shot 80129A13 0004 cn Infinite Fuel 81129A16 FFFF cn Infinite Shield 811299B8 03E8 cn Opens All 5 Item Slots 8012974B 0005 cn Weapon Modifier\1st Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 80129729 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\2nd Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 8012972D ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\3rd Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 801297E1 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\4th Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 801297E5 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Weapon Modifier\5th Position cd Must to be used with the Infinite Weapon Codes & the open all 5 item slot code. 801297E9 ???? 0000:"Nothing",0001:"AGM",0002:"AAM",0003:"AGAM",0004:"Dummy",0005:"Rocket",0006:"Cluster",0007:"H-Cluster",0008:"H-Plasma" cn Score Attack Mode 81129762 0001 cn Stage Select On 81129766 0001 cn Option On 8112976A 0001 cn Clear Mission Selector 8112976C ???? 0001:"1",0002:"2",0003:"3",0004:"4",0005:"5",0006:"6",0007:"7",0008:"8" cn Texture Mode 81129774 0001 crc 8E9692B3-4264BB2A-C:50 gn Clay Fighter 63 1-3 (E) cn Extra Characters and Secret Options 801A86A1 000F cn Stage Select 801A868B ???? 0000:"Candy Factory",0001:"Claynaveral Hangar",0002:"Camp Claynaveral",0003:"Outhouse",0004:"Mudville Mansion",0005:"Ghastly Graveyard",0006:"Spooky Spire",0007:"Happy Harry's Hut",0008:"Freezing Fortress",0009:"Refuse Room",000A:"Grotto Gulch",000B:"Rubbage Room",000C:"Rubbage Reef",000D:"Kiln's Laboratory",000E:"Kiln's Hideout",000F:"Fiery Furnace",0010:"Research Room",0011:"Clayribbean Cruise",0012:"Santa's Workship",0013:"Kooky Courtyard",0014:"Santa's Toy Factory",0015:"Boogerhenge",0016:"Backwash Bay",0017:"Tureen Toilet",0018:"Tribal Tower",0019:"Aquadome" cn Play As\Player1 801A868F ???? 0000:"Bad Mr. Frosty",0001:"Blob",0002:"Bonker",0003:"Boogerman",0004:"Dr. Kiln",0005:"Earthworm Jim",0008:"Houngan",0009:"Icky Bod Clay",000A:"Kung Pow",000D:"Sumo Santa",000E:"Taffy",000F:"T-Hoppy" cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Can't be Stunned\Player 1 801F766B 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Infinite Energy\Player 1 801F7673 00AA cn Refuse Room, Grotto Gulch, Santa's Workship Stages\No Energy\Player 1 801F7673 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Full Super Bar\Player 1 811F767A 0200 cn Tribal Tower Stage\Can't be Stunned\Player 1 801F770B 0000 cn Tribal Tower Stage\Infinite Energy\Player 1 801F7713 00AA cn Tribal Tower Stage\No Energy\Player 1 801F7713 0000 cn Tribal Tower Stage\Full Super Bar\Player 1 811F771A 0200 cn Aquadome Stage\Can't be Stunned\Player 1 801F799B 0000 cn Aquadome Stage\Infinite Energy\Player 1 801F7993 00AA cn Aquadome Stage\No Energy\Player 1 801F7993 0000 cn Aquadome Stage\Full Super Bar\Player 1 811F799A 0200 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Can't be Stunned\Player 1 801F7E9B 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Infinite Energy\Player 1 801F7EA3 00AA cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\No Energy\Player 1 801F7EA3 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Full Super Bar\Player 1 811F7EAA 0200 cn Freezing Fortress Stage\Can't be Stunned\Player 1 801F7EFB 0000 cn Freezing Fortress Stage\Infinite Energy\Player 1 801F7F03 00AA cn Freezing Fortress Stage\No Energy\Player 1 801F7F03 0000 cn Freezing Fortress Stage\Full Super Bar\Player 1 811F7F0A 0200 cn Rubbage Reef Stage\Can't be Stunned\Player 1 801F7F7B 0000 cn Rubbage Reef Stage\Infinite Energy\Player 1 801F7F83 00AA cn Rubbage Reef Stage\No Energy\Player 1 801F7F83 0000 cn Rubbage Reef Stage\Full Super Bar\Player 1 811F7F8A 0200 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Can't be Stunned\Player 1 801F7FAB 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Infinite Energy\Player 1 801F7FB3 00AA cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\No Energy\Player 1 801F7FB3 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Full Super Bar\Player 1 811F7FBA 0200 cn Clayribbean Cruise Stage\Can't be Stunned\Player 1 801F805B 0000 cn Clayribbean Cruise Stage\Infinite Energy\Player 1 801F8063 00AA cn Clayribbean Cruise Stage\No Energy\Player 1 801F8063 0000 cn Clayribbean Cruise Stage\Full Super Bar\Player 1 811F806A 0200 cn Backwash Bay Stage\Can't be Stunned\Player 1 801F80EB 0000 cn Backwash Bay Stage\Infinite Energy\Player 1 801F80F3 00AA cn Backwash Bay Stage\No Energy\Player 1 801F80F3 0000 cn Backwash Bay Stage\Full Super Bar\Player 1 811F80FA 0200 cn Ghastly Graveyard Stage\Can't be Stunned\Player 1 801F818B 0000 cn Ghastly Graveyard Stage\Infinite Energy\Player 1 801F8193 00AA cn Ghastly Graveyard Stage\No Energy\Player 1 801F8193 0000 cn Ghastly Graveyard Stage\Full Super Bar\Player 1 811F819A 0200 cn Candy Factory Stage\Can't be Stunned\Player 1 801F826B 0000 cn Candy Factory Stage\Infinite Energy\Player 1 801F8273 00AA cn Candy Factory Stage\No Energy\Player 1 801F8273 0000 cn Candy Factory Stage\Full Super Bar\Player 1 811F827A 0200 cn Kooky Courtyard Stage\Can't be Stunned\Player 1 801F836B 0000 cn Kooky Courtyard Stage\Infinite Energy\Player 1 801F8373 00AA cn Kooky Courtyard Stage\No Energy\Player 1 801F8373 0000 cn Kooky Courtyard Stage\Full Super Bar\Player 1 811F837A 0200 cn Santa's Toy Factory Stage\Can't be Stunned\Player 1 801F879B 0000 cn Santa's Toy Factory Stage\Infinite Energy\Player 1 801F87A3 00AA cn Santa's Toy Factory Stage\No Energy\Player 1 801F87A3 0000 cn Santa's Toy Factory Stage\Full Super Bar\Player 1 811F87AA 0200 cn Boogerhenge, Tureen Toilet Stage\Can't be Stunned\Player 1 801F8B3B 0000 cn Boogerhenge, Tureen Toilet Stage\Infinite Energy\Player 1 801F8B43 00AA cn Boogerhenge, Tureen Toilet Stage\No Energy\Player 1 801F8B43 0000 cn Boogerhenge, Tureen Toilet Stage\Full Super Bar\Player 1 811F8B4A 0200 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Can't be Stunned\Player 1 801F971B 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Infinite Energy\Player 1 801F9723 00AA cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\No Energy\Player 1 801F9723 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Full Super Bar\Player 1 811F972A 0200 cn Rubbage Room Stage\Can't be Stunned\Player 1 801FA1AB 0000 cn Rubbage Room Stage\Infinite Energy\Player 1 801FA1B3 00AA cn Rubbage Room Stage\No Energy\Player 1 801FA1B3 0000 cn Rubbage Room Stage\Full Super Bar\Player 1 811FA1BA 0200 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Can't be Stunned\Player 2 801FAB0B 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Infinite Energy\Player 2 801FAB13 00AA cn Refuse Room, Grotto Gulch, Santa's Workship Stages\No Energy\Player 2 801FAB13 0000 cn Refuse Room, Grotto Gulch, Santa's Workship Stages\Full Super Bar\Player 2 811FAB1A 0200 cn Tribal Tower Stage\Can't be Stunned\Player 2 801FABAB 0000 cn Tribal Tower Stage\Infinite Energy\Player 2 801FABB3 00AA cn Tribal Tower Stage\No Energy\Player 2 801FABB3 0000 cn Tribal Tower Stage\Full Super Bar\Player 2 811FABBA 0200 cn Aquadome Stage\Can't be Stunned\Player 2 801FAE2B 0000 cn Aquadome Stage\Infinite Energy\Player 2 801FAE33 00AA cn Aquadome Stage\No Energy\Player 2 801FAE33 0000 cn Aquadome Stage\Full Super Bar\Player 2 811FAE3A 0200 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Can't be Stunned\Player 2 801FB33B 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Infinite Energy\Player 2 801FB343 00AA cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\No Energy\Player 2 801FB343 0000 cn Outhouse, Claynaveral Hanger, Camp Claynaveral Stages\Full Super Bar\Player 2 811FB34A 0200 cn Freezing Fortress Stage\Can't be Stunned\Player 2 801FB39B 0000 cn Freezing Fortress Stage\Infinite Energy\Player 2 801FB3A3 00AA cn Freezing Fortress Stage\No Energy\Player 2 801FB3A3 0000 cn Freezing Fortress Stage\Full Super Bar\Player 2 811FB3AA 0200 cn Rubbage Reef Stage\Can't be Stunned\Player 2 801FB41B 0000 cn Rubbage Reef Stage\Infinite Energy\Player 2 801FB423 00AA cn Rubbage Reef Stage\No Energy\Player 2 801FB423 0000 cn Rubbage Reef Stage\Full Super Bar\Player 2 811FB42A 0200 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Can't be Stunned\Player 2 801FB44B 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Infinite Energy\Player 2 801FB453 00AA cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\No Energy\Player 2 801FB453 0000 cn Happy Harry's Hut, Spooky Spire, Mudville Mansion Stage\Full Super Bar\Player 2 811FB45A 0200 cn Clayribbean Cruise Stage\Can't be Stunned\Player 2 801FB4FB 0000 cn Clayribbean Cruise Stage\Infinite Energy\Player 2 801FB503 00AA cn Clayribbean Cruise Stage\No Energy\Player 2 801FB503 0000 cn Clayribbean Cruise Stage\Full Super Bar\Player 2 811FB50A 0200 cn Backwash Bay Stage\Can't be Stunned\Player 2 801FB58B 0000 cn Backwash Bay Stage\Infinite Energy\Player 2 801FB593 00AA cn Backwash Bay Stage\No Energy\Player 2 801FB593 0000 cn Backwash Bay Stage\Full Super Bar\Player 2 811FB59A 0200 cn Ghastly Graveyard Stage\Can't be Stunned\Player 2 801FB62B 0000 cn Ghastly Graveyard Stage\Infinite Energy\Player 2 801FB633 00AA cn Ghastly Graveyard Stage\No Energy\Player 2 801FB633 0000 cn Ghastly Graveyard Stage\Full Super Bar\Player 2 811FB63A 0200 cn Candy Factory Stage\Can't be Stunned\Player 2 801FB70B 0000 cn Candy Factory Stage\Infinite Energy\Player 2 801FB713 00AA cn Candy Factory Stage\No Energy\Player 2 801FB713 0000 cn Candy Factory Stage\Full Super Bar\Player 2 811FB71A 0200 cn Kooky Courtyard Stage\Can't be Stunned\Player 2 801FB80B 0000 cn Kooky Courtyard Stage\Infinite Energy\Player 2 801FB813 00AA cn Kooky Courtyard Stage\No Energy\Player 2 801FB813 0000 cn Kooky Courtyard Stage\Full Super Bar\Player 2 811FB81A 0200 cn Santa's Toy Factory Stage\Can't be Stunned\Player 2 801FBC3B 0000 cn Santa's Toy Factory Stage\Infinite Energy\Player 2 801FBC43 00AA cn Santa's Toy Factory Stage\No Energy\Player 2 801FBC43 0000 cn Santa's Toy Factory Stage\Full Super Bar\Player 2 811FBC4A 0200 cn Boogerhenge, Tureen Toilet Stage\Can't be Stunned\Player 2 801FBFDB 0000 cn Boogerhenge, Tureen Toilet Stage\Infinite Energy\Player 2 801FBFE3 00AA cn Boogerhenge, Tureen Toilet Stage\No Energy\Player 2 801FBFE3 0000 cn Boogerhenge, Tureen Toilet Stage\Full Super Bar\Player 2 811FBFEA 0200 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Can't be Stunned\Player 2 801FCBBB 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Infinite Energy\Player 2 801FCBC3 00AA cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\No Energy\Player 2 801FCBC3 0000 cn Kiln's Laboratory, Kiln's Hideout, Fiery Furnace, Research Room Stage\Full Super Bar\Player 2 811FCBCA 0200 cn Rubbage Room Stage\Can't be Stunned\Player 2 801FD64B 0000 cn Rubbage Room Stage\Infinite Energy\Player 2 801FD653 00AA cn Rubbage Room Stage\No Energy\Player 2 801FD653 0000 cn Rubbage Room Stage\Full Super Bar\Player 2 811FD65A 0200 crc AE5B9465-C54D6576-C:50 gn Command & Conquer (E) cn Infinite Options\Power GDI 810C55D6 FFFF cn Infinite Options\Power NOD 810C577E FFFF cn Infinite Options\Health Commando 810B5364 0080 cn Infinite Options\Money NOD 810C575E FFFF cn Infinite Options\Money GDI 810C55B6 FFFF cn Level Select cd Select Replay Mission, Press L To Display All Missions,And Press R To Select Your Team You can now press R+L+Up To Win A Battle 810901AA 0001 crc 373F5889-9A6CA80A-C:50 gn CONKER BFD cn Infinite\Health\Player 1 800CC8BA 0006 cn Infinite\Oxygen 800CC7A2 0001 cn Infinite\Pots of cash 810D256A FFFF cn Access All\Chapters, Scenes,& Multi-Player Characters 50002401 0000 800EA120 00FF cn Play as cd Here you can Choose Options who you want to play as,But only one Option at a time. 800D255F ???? 0001:"Wessle",0003:"Tedi",0004:"Combat Squirrel",0005:"Conker",000B:"Uga",000C:"Bald Caveman",000D:"Caveman",000E:"Mohican Caveman",0010:"Neo Conker",001B:"Villager",0021:"Zombie",0023:"Enemy Bat",0024:"Conkers Bat",0025:"Army Captain",0026:"Tedi Boss",0027:"Gregg",0028:"Gregg skeleton" cn Infinite\Lives Player 1 800D2564 0063 cn Infinite\Health\Player 2 800CCBE6 270F cn Infinite\Health\Player 3 800CCF12 270F cn Infinite\Health\Player 4 800CD23E 270F cn Infinite\Time In Multi 8109019A 7500 cn Infinite\Bags In Heist 800E1004 00FF cn Access All\Characters & Weapons In Multi Race 810EA122 ???? 00FF:"All Characters & Baseball bat",00FB:"All Characters & Frying Pan",00F3:"All Characters & Bones" cn Infinite\Bombs 802059EA 0030 cn Infinite\Max Kills Player 1 cd MULTI ONLY. Only put this code on once you are in the game 800E0F67 03E7 cn Infinite\Accuracy Count Player 1 cd MULTI ONLY. Only put this code on once you are in the game,Once you pick up a Gun a shoot once, you will 100%. 800E0F87 0001 cn Infinite\Head Shot Count Player 1 cd MULTI ONLY. Only put this code on once you are in the game 800E0F8B 0064 cn Press L To Levitate\Player 1 cd Press L Button to Levitate & Let go to come back down D0042DA5 0020 810CC710 41CB cn Press L To Levitate\Player 2 cd Press L Button to Levitate & Let go to come back down D0042DAE 0020 810CCA3C 41CB cn Press L To Levitate\Player 3 cd Press L Button to Levitate & Let go to come back down D0042DB5 0020 810CCD68 41CB cn Press L To Levitate\Player 4 cd Press L Button to Levitate & Let go to come back down D0042DBE 0020 810CD094 41CB cn Weapon Select In Multi (On Pick Up) cd Select what Weapon you would like in Multi Player and then on a Weapon Pickup you will have the weapon of your choice.to change for another just Enable the one of your choice to have that instead.(you must have a weapon already to change for the next. 80180C4B ???? 0001:"Sword",0002:"Nothing",0003:"Yellow Chain-Ssaw",0004:"Throwing Knives",0005:"Riffle",0006:"Long Pistol with Sight",0007:"Rocket Launcher",0008:"Buck Shot",000A:"High Powred Riffle With Scope",000C:"Two Automatic Machine Guns",0013:"Gas Mask" crc 503EA760-E1300E96-C:50 gn Cruis'n USA (E) (1.0) cn Always Place 1st 801502CB 0001 cn Unlimited Time 801509ED 0045 cn Access Options\All Tracks 80150602 001F 80150603 00FF cn Access Options\All Car Upgrades 50000704 0000 801505DF 0003 crc 503EA760-E1300E96-C:50 gn Cruis'n USA (E) (1.1) cn Always Place 1st 801501AB 0001 cn Unlimited Time 801508CD 0045 cn Access Options\All Tracks 801504E2 001F 801504E3 00FF cn Access Options\All Car Upgrades 50000704 0000 801504BF 0003 crc 503EA760-E1300E96-C:50 gn Cruis'n USA (E) (1.2) cn Always Place 1st 801501DB 0001 cn Unlimited Time 801508FD 0045 cn Access Options\All Tracks 80150512 001F 80150123 00FF cn Access Options\All Car Upgrades 50000704 0000 801504EF 0003 crc 83F3931E-CB72223D-C:50 gn Cruis'n World (E) cn Infinite Time 813D0C1C 4296 cn Access\Florida & Moon Tracks cd This is for Championship Mode Only 813BF2A4 0101 cn Max Power Level,& Paint Job / Two Tone 813BEDA2 0512 cn Access\All Cars & Upgrades 813BED58 1FFF 803BED22 0005 cn Unlocked Pro & Master difficulty level 803BEDD5 0003 cn Dancing Girl Always On 803BED53 0001 803C20AF 0054 cn Cannot Spin Out 803CDC73 0000 cn Disable\Left Lane Traffic cd This is for Championship Mode Only 8033C83B 0001 cn Disable\Right Lane Traffic cd This is for Championship Mode Only 8033C83F 0001 cn Max\Trick points 803BF21F 0063 cn Max\Championship Points 813BFB4E 270F cn Always 1st\Player 1 803CDF03 0001 cn Unlimited Nitro\Player 1 cd Press C-Button Down For Boost, This Code is for Championship Mode Only 803C74C7 0003 cn Stop Elapsed Time\Player 1 813C7558 3C80 cn Always 1st\Player 2 803CE3DB 0001 cn Unlimited Nitro\Player 2 cd Press C-Button Down For Boost, This Code is for Championship Mode Only 803C7703 0003 cn Stop Elapsed Time\Player 2 813C7794 3C80 cn Always 1st\Player 3 803CDA2B 0001 cn Unlimited Nitro\Player 3 cd Press C-Button Down For Boost, This Code is for Championship Mode Only 803C704F 0064 cn Always 1st\Player 4 803CD553 0001 cn Unlimited Nitro Player 4 cd Press C-Button Down For Boost, This Code is for Championship Mode Only 803C728B 0003 crc D1A78A07-52A3DD3E-C:50 gn CyberTiger (E) cn Infinite & Max Power-Ups 800B4612 00F0 50000801 0000 800B4600 00FF cn Access Secret Characters\Kimmi & Cindy 800B0DAA 0011 cn Access Secret Characters\Twfan & Eagamer 800B0DAE 0011 cn Access Secret Characters\Bengal The Tiger 800B4DB2 0011 cn Access Secret Characters\Mark 800B0DB7 0012 cn Access Secret Characters\Robert & Delvis 800B0DBA 0011 cn Access Secret Characters\Starr & Traci 800B0DBE 0011 cn Access Secret Characters\Festus 800B0DC3 0001 cn Access Secret Characters\Marvin The Alien 800B0DC7 0001 crc 7ED67CD4-B4415E6D-C:50 gn DARK RIFT cn Access Sonork Character 80049AA0 0001 cn Access Demitron Character 80049AA4 0001 cn Infinite Health\All Levels\Player 1 812716E0 0190 8127BDB8 0190 8127E478 0190 81292EE8 0190 81293768 0190 81297538 0190 812ACCC8 0190 812B1CE8 0190 812B7BE8 0190 8138AEE0 0190 cn Infinite Health\All Levels\Player 2 81271FB8 0190 8127B158 0190 8127E820 0190 81293B48 0190 81294390 0190 812980B8 0190 812AD608 0190 812B2D08 0190 812B67D8 0190 8138A898 0190 cn Press GS For 2 Rounds Won\Player 1 880B6491 0002 cn Press GS For 2 Rounds Won\Player 2 880B64A3 0002 cn Music Modifier 80081812 ???? 0000:"Music Off",002A:"Volume Low",0055:"Volume Medium",007F:"Volume Max" crc 630AA37D-896BD7DB-C:50 gn Destruction Derby 64 (E) cn Have All\Tracks 50000802 0000 81099498 0101 cn Have All\Difficulty Levels 8109B7D6 0003 cn Have All\Cars 50000602 0000 8109B7D8 0101 cn Max\Points Aid 8112A3CE 02F4 cn Max\Collisions Points 812E013A 02F4 cn Max\Checkpoint Bonus 812E013E 02F4 crc FD73F775-9724755A-C:50 gn Diddy Kong Racing cn Enable All Cheats cd Go into Options & then Magic Codes. Then Code list to turn off & on what you want. 800DFE2C 001F 50000301 0000 800DFE2D 00FF cn Have All\Trophies cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 80207E6E 0007 80207E6F 00FF cn Have All\Keys cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 80207E69 001F cn Have All\T.T. Amulets cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 80207E77 0004 cn Have All\50 Balloons 8020807D 0032 cn Have All\None-Adventure tracks completed 50001204 0000 80207F87 0007 50000904 0000 80207FDF 0007 80207E68 0007 80207E6A 0007 80207E6B 0007 80207E6C 000F 80207E6D 00FF cn Have All\T.T. time trial races beaten 80207E76 0004 cn Have All\Control Drumstick & Adventure Two mode unlocked 801264DC 0003 801264DF 0003 801264F2 0003 801264F3 0008 cn Have All\Trophy Adventure races unlocked 50000502 0000 8020807E 0007 crc 596E145B-F7D9879F-C:50 gn Diddy Kong Racing cn Enable All Cheats cd Go into Options & then Magic Codes. Then Code list to turn off & on what you want. 800E03AC 001F 50000301 0000 800E03AD 00FF cn Have All\Trophies cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 8020865E 0007 8020865F 00FF cn Have All\Keys cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 80208659 001F cn Have All\T.T. Amulets cd Only put this code on once you are inside the lobby to choose a gate,or it will crash the game. 80208667 0004 cn Have All\50 Balloons 8020807D 0032 cn Have All\None-Adventure tracks completed 50001204 0000 80208777 0007 50000904 0000 802087CF 0007 80208658 0007 8020865A 0007 8020865B 0007 8020865C 000F 8020865D 00FF cn Have All\T.T. time trial races beaten 80208666 0004 cn Have All\Control Drumstick & Adventure Two mode unlocked 80126CCC 0003 80126CCF 0003 80126CE2 0003 80126CE3 0008 cn Have All\Trophy Adventure races unlocked 50000502 0000 8020886E 0007 crc D614E5BF-A76DBCC1-C:50 gn Disney's Tarzan (E) cn Infinite\Health 81192300 0120 cn Have\Coins Collected 100% 800DD4B7 0064 cn Have\Level & Tokens Completed 100% 800DD48F 0000 800DD490 0001 800DD491 0000 cn Access Level Select cd On the main menu Scroll down to make CHEATS visible to go into Level Select.For in-Game Cheats,Pause gameplay. 810DD47C 8001 cn Infinite\Lives 800DD4B2 ???? 0003:"3 Lives",0063:"99 Lives" cn Have\All TARZAN Letters 800DD485 00FF cn Have\Full Portrait 800DD484 00FF cn Infinite\Red Weapon 811921D8 0063 cn Infinite\Green Weapon 811921D6 0063 cn Infinite\Purple Weapon 811921DA 0063 cn Press GS For\Sabor Attacks\Sabor 1 Hit Kill 8924A49E 0001 cn Infinite\Bonus Timer cd This is For All Timers on Bonus Levels 8017373E 0025 crc 3DF17480-193DED5A-C:50 gn Donald Duck Quack At cn Infinite\99 Lives 801D6F2E 0063 cn Infinite\99 Stars 801D6F2F 0063 cn Instant\Rage Attack (Press C-Left) D00CAFD1 0002 801CE23D 0001 cn Instant\Hyperactive State [Invincible] (Press C-Right) D00CAFD1 0001 801CE296 0001 cn Instant\Carrier Box [Moon Walk] (Press L) cd Press and hold the L Button and you will run floating of any ledge slowing drifting down. If you keep pressing the A Button while Holding L it will act as a Moon Jump. D00CAFD1 0020 801C901F 0001 cn Infinite\Time\Gladstones Time Attack 801D6F27 00FF cn Infinite\Time\Nephews Toy Hunting 801D6F23 0063 cn Have All\Levels and Bonus Stages Unlocked cd Press start in Gyro's Lab and then resume game to see all open 801D6F4C 00FF 801D6F4D 00FF 801D6F4E 00FF 801D6F4F 00FF 801D6F53 00FF cn Have All\Time Attack & Toy Hunting Comnpleated (All Levels) cd Press start in Gyro's Lab and then resume game to see all open 801D6F58 00FF 801D6F59 00FF 801D6F5A 00FF 801D6F5B 00FF 801D6F5C 00FF 801D6F5D 00FF 801D6F5E 00FF 801D6F5F 00FF crc 11936D8C-6F2C4B43-C:50 gn DONKEY KONG 64 cn Donkey Kong\Infinite Ammo 807FCB85 0096 cn Infinite\Health 817FCB8C 041F cn Donkey Kong\Infinite Musical Instrument 817FC894 0103 817FC898 00FF cn Diddy\Infinite Musical Instrument 817FC8F6 000A cn Tiny\Infinite Musical Instrument 817FC9B2 000A cn Lanky\Infinite Musical Instrument 817FC954 000A cn Chunky\Infinite Musical Instrument 817FCA10 000A cn Infinite\Camera Film 807FCB89 0005 cn Infinite\Orange Bombs 807FCB81 0096 cn Donkey Kong\Infinite Bananas\Jungle Japes 817FC89A 03E7 cn Donkey Kong\Infinite Bananas\Angry Aztec 817FC89C 03E7 cn Donkey Kong\Infinite Bananas\FactoryLevel 817FC89E 03E7 cn Donkey Kong\Infinite Bananas\Galleon Level 817FC8FE 03E7 cn Donkey Kong\Infinite Bananas\Fungi Forest 817FC8A2 03E7 cn Donkey Kong\Infinite Bananas\Creepy Castle 817FC8A6 03E7 cn Donkey Kong\Infinite Bananas\Crystal Caves 817FC8A4 03E7 cn Donkey Kong\All Golden Bananas\Jungle Japes 817FC8D2 03E7 cn Donkey Kong\All Golden Bananas\Angry Aztecs 817FC8D4 03E7 cn Donkey Kong\All Golden Bananas\Frantic Factory 817FC8D6 03E7 cn Donkey Kong\All Golden Bananas\Gloomy Galleon 817FC8D8 03E7 cn Donkey Kong\All Golden Bananas\Crystal Caves 817FC8DC 03E7 cn Donkey Kong\All Golden Bananas\Creepy Castle 817FC8DE 03E7 cn Donkey Kong\All Golden Bananas\DK Isle 817FC8E0 03E7 cn Diddy\All Golden Bananas\Jungle Japes 817FC930 0064 cn Diddy\All Golden Bananas\Angry Aztecs 817FC932 0064 cn Diddy\All Golden Bananas\Frantic Factory 817FC934 0064 cn Diddy\All Golden Bananas\Gloomy Galleon 817FC936 0064 cn Diddy\All Golden Bananas\Fungi Forest 817FC938 0064 cn Diddy\All Golden Bananas\Crystal Caves 817FC93A 0064 cn Diddy\All Golden Bananas\Creepy Castle 817FC93C 0064 cn Diddy\All Golden Bananas\DK Isle 817FC93E 0064 cn Tiny\All Golden Bananas\Jungle Japes 817FC9EC 0064 cn Tiny\All Golden Bananas\Angry Aztecs 817FC9EE 0064 cn Tiny\All Golden Bananas\Frantic Factory 817FC9F0 0064 cn Tiny\All Golden Bananas\Gloomy Galleon 817FC9F2 0064 cn Tiny\All Golden Bananas\Fungi Forest 817FC9F4 0064 cn Tiny\All Golden Bananas\Crystal Caves 817FC9F6 0064 cn Tiny\All Golden Bananas\Creepy Castle 817FC9E8 0064 cn Tiny\All Golden Bananas\DK Isle 817FC9FA 0064 cn Lanky\All Golden Bananas\Jungle Japes 817FC98E 0064 cn Lanky\All Golden Bananas\Angry Aztecs 817FC990 0064 cn Lanky\All Golden Bananas\Frantic Factory 817FC992 0064 cn Lanky\All Golden Bananas\Gloomy Galleon 817FC994 0064 cn Lanky\All Golden Bananas\Fungi Forest 817FC996 0064 cn Lanky\All Golden Bananas\Crystal Caves 817FC998 0064 cn Lanky\All Golden Bananas\Creepy Castle 817FC99A 0064 cn Lanky\All Golden Bananas\DK Isle 817FC99C 0064 cn Chunky\All Golden Bananas\Jungle Japes 817FCA4A 0064 cn Chunky\All Golden Bananas\Angry Aztecs 817FCA4C 0064 cn Chunky\All Golden Bananas\Frantic Factory 817FCA4E 0064 cn Chunky\All Golden Bananas\Gloomy Galleon 817FCA50 0064 cn Chunky\All Golden Bananas\Fungi Forest 817FCA52 0064 cn Chunky\All Golden Bananas\Crystal Caves 817FCA54 0064 cn Chunky\All Golden Bananas\Creepy Castle 817FCA56 0064 cn Chunky\All Golden Bananas\DK Isle 817FCA58 0064 cn Donkey Kong\Infinite Coins 817FC896 03E7 cn Diddy\Infinite Coins 817FC8F4 03E7 cn Tiny\Infinite Coins 817FC9B0 03E7 cn Lanky\Infinite Coins 817FC952 03E7 cn Chunky\Infinite Coins 817FCA0E 03E7 cn Infinite\Crystal Coconuts 817FCB86 03E7 cn Donkey Kong\Has Moves 817FC890 0103 cn Donkey Kong\Have Weapon 817FC892 0103 cn Free Pass (Access All Areas) cd This is exactly what it says, You can walk through Any Locked Door,Gate, Or Area. Have Fun. 8066D167 0001 8066D262 0001 crc 2C739EAC-9EF77726-C:50 gn Doom 64 (E) cn Always Have\Gun 80063373 0001 cn Always Have\Shotgun 80063377 0001 cn Always Have\Double Shotgun 8006337B 0001 cn Always Have\Chain Gun 8006337F 0001 cn Always Have\Missile Launcher 80063383 0001 cn Always Have\Chainsaw 8006336B 0001 cn Always Have\Plasma Rifle 80063387 0001 cn Always Have\BFG 8006338B 0001 cn Infinite\Armor 800634BF 00FF cn Rapid Fire 810633EA 0B94 cn Invincible 8006355B 0002 cn Turn Map Markers On 800633BB 0004 cn Invincible And Map Markers 800633BB 0006 cn Always Have\Bio Suite 80063333 ???? 00FF:"On",0000:"Off" cn Always Have\Missile Ammo 8006339F 0064 cn Always Have\Have Rocket Launcher 80063381 0001 cn Always Have\Have Laser Weapon 8006338D 0001 cn [Max Brightness] cd Enable this cheat on rom load to have Max Brightness (internal) and then put Jabo d3d8 on 160% Max for a extra brightness Boost. 8005AA18 0064 cn Have All\Keys 50000504 0000 810634DE FFFF cn Have All\Weapons 50000A04 0000 8106350A 0001 cn Infinite\Ammo All Weapons 50000404 0000 81063532 013C cn Enable Cheat Menu 8005AA23 0001 crc B6524461-ED6D04B1-C:50 gn Dual Heroes (E) cn Infinite Health\Player 1 80225E9D 00FA cn Infinite Health\Player 2 80225E9F 00FA cn Win Once To Win\Player 1 80225E95 0001 cn Win Once To Win\Player 2 80225E97 0001 cn Infinite Time 80225EA5 003C crc 57BFF74D-DE747743-C:50 gn Duke Nukem 64 (E) cn Access all In-Game cheats 50000504 0000 80101308 0001 cn Infinite\Ammo & All Guns 50000C02 0000 812A5A34 02F4 cn Access\All Items cd To access simply pause in game play & then unpause. 801012EC 0001 cn Invincibility 802AAA98 0001 cn Access\All Keys 802A5A77 000F cn Infinite\Holoduke 812A5A5C 0640 cn Infinite\Night Vision 812A5A8C 0640 cn Infinite\Scuba Gear 812A5ABC 0640 cn Crosshair On 802A5B24 0001 cn Max auto-aim On 802A5B25 0002 cn Upgraded Plasma Gun 802A5A63 0063 crc DC36626A-3F3770CB-C:50 gn DUKE NUKEM ZERO HOUR cn Cheat Menu\Cheat Menu Enabled 800CF7D8 0001 cn Cheat Menu\Have All Weapons 811CE810 FFFF cn Cheat Menu\Have All Game Type & Other 810E1A3E 0FFF cn Cheat Menu\All Weapons Enabled 801CCC59 0001 801CCCC5 0001 801CDD25 0001 801CDE21 0001 801CDEB5 0001 801CDEB7 0001 801CDEE9 0001 801CE819 0001 801CE821 0001 801CE88D 0001 801CF9D5 0001 cn Infinite Ammo (All Guns) 810A21B4 A65B cn Invincibility 800DF203 0001 cn Time Always 00:00 801A1D06 0000 cn Enable Debug Menu 800DFCD0 0001 crc 492B9DE8-C6CCC81C-C:50 gn Earthworm Jim 3D (E) cn Infinite\Health 800C876F 0064 cn Infinite\Lives 800C8773 0064 cn Infinite\Ammo\Blaster 810C6916 0064 cn Infinite\Ammo\Rocket Launcher 810C6946 0064 cn Infinite\Ammo\Banana Peel Bomb 810C6976 0064 cn Infinite\Ammo\Laser 810C698E 0064 cn Infinite\Ammo\Green Slimer 810C69A6 0064 cn Infinite\Ammo\Chickens 810C69BE 0064 cn Infinite\Ammo\Shotgun 810C69EE 0064 cn Infinite\Ammo\Music Gun 810C6906 0064 cn Infinite\Ammo\Boomerang Knives 810C691E 0064 cn Infinite\Ammo\Mushrooms 810C6936 0064 cn Infinite\Ammo\Lepricon Gun 800C8897 0064 cn Infinite\Ammo\Pistol 800C8777 0064 cn Infinite\Ammo\Sniper Chicken 800C881F 0064 cn Infinite\Ammo\Butcher Knife Gun 800C887F 0064 cn Have\231 Marbles D00EBE53 0000 800EBE53 03E7 cn Have\All Gold Udders 50002802 0000 810C80BA 0101 crc 202A8EE4-83F88B89-C:50 gn EXCITEBIKE64 cn Infinite Time 810F0E36 1770 cn Max Score Stunt Mode\Player One 810E43E8 0098 810E43EA 967F cn Max Score Stunt Mode\Player Two 810E4BC8 0098 810E4BCA 967F cn Unlock Original Excitebike cd Press L+R at track selection to Access Soccer,Hill Climb & Excite 3D D00F6605 0030 810F2420 FF07 cn Start On Lap D00E4681 0000 800E4681 ???? 0001:"Lap 1",0002:"Lap 2",0003:"Lap 3",0004:"Lap 4" cn Always Low Temp\Player Two 810E4E48 0000 810E4E4A 0000 cn Always Low Temp\Player One 810E4668 0000 810E466A 0000 cn In Game Cheat Select\1 800CDA4A ???? 0001:"Transparent riders",0002:"All stunts",0004:"Invincible mode",0008:"Developers team photo",0010:"Beat this",0020:"Small head mode" cn In Game Cheat Select\2 800CDA4B ???? 0001:"Big head mode",0002:"Mirror mode",0004:"Debug mode",0008:"Down hill mode",0010:"Stunt bonus",0020:"Invisible riders",0040:"Night mode",0080:"Odd colour mode" cn In-Game cheat modifer 810CDA4A ???? 0001:"Big head mode",0002:"Mirror mode",0004:"Debug mode",0008:"Down hill mode",0010:"Stunt bonus",0020:"Invisible riders",0040:"Night mode",0080:"Odd colour mode",0100:"Transparent riders",0200:"All stunts",0400:"Invincible mode",0800:"Developers team photo",1000:"Beat this",2000:"Small head mode" crc 8E9D834E-1E8B29A9-C:50 gn Extreme-G (E) cn Infinite Shields\Player 1 801651F5 00C8 cn Infinite Primary Weapon\Player 1 801651FD 00C8 cn Infinite Turbos\Player 1 801651CB 0003 801651CF 0003 cn Bike Modifier\Player 1 8016983F ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Infinite Shields\Player 2 80165965 00C8 cn Infinite Primary Weapon\Player 2 8016596D 00C8 cn Infinite Turbos\Player 2 8016593B 0003 8016593F 0003 cn Bike Modifier\Player 2 8016988B ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Infinite Shields\Player 3 801660D5 00C8 cn Infinite Primary Weapon\Player 3 801660DD 00C8 cn Infinite Turbos\Player 3 801660AB 0003 801660AF 0003 cn Bike Modifier\Player 3 801698D7 ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Infinite Shields\Player 4 80166845 00C8 cn Infinite Primary Weapon\Player 4 8016684D 00C8 cn Infinite Turbos\Player 4 8016681B 0003 8016681F 0003 cn Bike Modifier\Player 4 80169923 ???? 0000:"Raze",0001:"Rana",0002:"Khan",0003:"Grimace",0004:"Mooga",0005:"Jolt",0006:"Main",0007:"Apollyon",0008:"Roach",0009:"Neon" cn Extra Bikes Unlocked 80167C13 0001 80167C17 0003 cn Extra Levels Unlocked 8016980B 0001 8016980F 0001 cn All Tracks Unlocked 80095F6E 0008 50000264 0000 80169347 0001 50000264 0000 80169473 0001 50000564 0000 8016959F 0001 cn Mode Select 80097687 ???? 0001:"Boulder",0002:"Fish Eye Lens",0003:"Boulder & Fish Eye Lens",0004:"Magnify",0008:"Anti-Gravity",000A:"Anti-Gravity & Fish Eye Lens",0010:"Wireframe",0011:"Boulder & Wireframe",0020:"Stealth Mode",0040:"Ghost Mode",0080:"Ugly Mode" crc 1185EC85-4B5A7731-C:50 gn Extreme-G XG2 (E) cn Infinite Nitros\Player 1 80170BA3 0004 80170BA7 0004 cn Infinite Shield\Player 1 80170BCD 00C8 cn Infinite Lasers\Player 1 80170BD9 00C8 cn Infinite Nitros\Player 2 8017120B 0004 8017120F 0004 cn Infinite Shield\Player 2 80171235 00C8 cn Infinite Lasers\Player 2 80171241 00C8 cn Infinite Nitros\Player 3 80171873 0004 80171877 0004 cn Infinite Shield\Player 3 8017189D 00C8 cn Infinite Lasers\Player 3 801718A9 00C8 cn Infinite Nitros\Player 4 80171EDB 0004 80171EDF 0004 cn Infinite Shield\Player 4 80171F05 00C8 cn Infinite Lasers\Player 4 80171F11 00C8 cn Access\All Tracks 50000BD8 0000 80182FC7 0001 50000CD8 0000 80182EF3 0001 50000CD8 0000 80182EF7 0001 50000CD8 0000 80182EFB 0001 50000CD8 0000 80182EFF 0001 50000CD8 0000 80182F03 0001 50000CD8 0000 80182F07 0001 cn Access\All Levels & Superbikes 50000304 0000 80183A0F 0001 cn Access\All Secret Characters cd This code is Fantastic, You have 12 characters to choose from to you race without any bike, just on foot 50000C04 0000 80183A27 0001 cn [Screen Hud Clear] cd If you are using a Plugin other then Jabos 1.5 and can not see through the Thick Hud on the Screen. then Let the game load 1st before Putting this code on,Or it will give an error and Freeze 80092C6B 0004 crc 07C1866E-5775CCDE-C:50 gn F-1 World Grand Prix II (E) cn Max Driver Points 8103A8F6 03E7 cn Max Constructor Points 8103A8F8 03E7 crc 776646F6-06B9AC2B-C:50 gn F-Zero X (E) cn Time Always 00.00.00/1st Place 812C4BC0 0000 812C4BC2 0001 cn Infinite Shield 812C4B48 4326 812C4B4C 4326 cn Infinite Lives 800D8729 0005 cn Boost From Start D02C4DA0 003F 802C4925 0050 cn Unlock Everything 810C01E8 0100 crc 3CECBCB8-6126BF07-C:50 gn F1 Racing Championship (E) cn No Checkpoint time 81164E1C 0001 cn Big Score 81164E58 8181 81164E5A 8181 cn Instant 450kmh Boost cd Press Trigger Button D10A1F50 2000 8119D334 005A crc 0E31EDF0-C37249D5-C:50 gn FIFA - Road to World Cup 98 (E) cn Home Team scores 25 Goals 801AF433 0019 cn Home Team scores 0 Goals 801AF433 0000 cn Away Team scores 25 Goals 801AF437 0019 cn Away Team scores 0 Goals 801AF437 0000 crc 0198A651-FC219D84-C:50 gn FIFA 99 (E) cn Team on the right of score board has 15 goals 800375C3 000F cn Team on the left of score board has 15 goals 800375C7 000F cn Team on the right of score board has 0 goals 800375C3 0000 cn Team on the left of score board has 0 goals 800375C7 0000 crc C3F19159-65D2BC5A-C:50 gn FIFA Soccer 64 (E) cn Number Of Goals Player 1 80119043 ???? 0001:"1 Goal",0002:"2 Goals",0003:"3 Goals",0004:"4 Goals",0005:"5 Goals",0006:"6 Goals",0007:"7 Goals",0008:"8 Goals,09 9 Goals,0A 10 Goals",0014:"20 Goals",001E:"30 Goals",0028:"40 Goals",0032:"50 Goals" cn Number Of Goals Player 2 80119047 ???? 0001:"1 Goal",0002:"2 Goals",0003:"3 Goals",0004:"4 Goals",0005:"5 Goals",0006:"6 Goals",0007:"7 Goals",0008:"8 Goals,09 9 Goals,0A 10 Goals",0014:"20 Goals",001E:"30 Goals",0028:"40 Goals",0032:"50 Goals" crc 36F1C74B-F2029939-C:50 gn Fighter's Destiny (E) cn Start with Stars Modifier\Player 1 D0209757 0000 80209757 ???? 0000:"No Stars",0006:"Max Stars" cn Start with Stars Modifier\Player 2 D020B61F 0000 8020B61F ???? 0000:"No Stars",0006:"Max Stars" cn Have 1 Star\Ryuji 8030734E 0001 cn Have 1 Star\Bob 8030734F 0001 cn Have 1 Star\Pierre 80307350 0001 cn Have 1 Star\Meiling 80307351 0001 cn Have 1 Star\Leon 80307352 0001 cn Have 1 Star\Abdul 80307353 0001 cn Have 1 Star\Ninja 80307354 0001 cn Have 1 Star\Tomahawk 80307355 0001 cn Have 1 Star\Valerie 80307356 0001 cn Infinite Health\Player 1 802098A1 0000 802047C3 0000 cn Infinite Health\Player 2 802047C7 0000 8020B769 0000 cn Start on stage 100 on Survival to get Joker 802EF67B 0063 cn Stop timer for Fastest to get Robot 810ADBDC 3F80 cn Always Win Judge's Decision\Player 1 8020B777 FFFF 802098AF 0000 cn Always Win Judge's Decision\Player 2 802098AF FFFF 8020B777 0000 cn Enable Boro 80307349 0001 cn Level Select 8022A84C ???? 0000:"Fire Mountain",0001:"Desert",0002:"Highlands",0003:"Hong Kong",0004:"Coliseum",0005:"Jungle",0006:"Ninja Room",0007:"Suspension Bridge",0008:"Palace",0009:"Observation",000A:"Pasture",000B:"Joker's Room",000C:"Blue Hell Mountain",000D:"Palace" cn Play As\Player 1 802EF622 ???? 0000:"Ryuji",0001:"Bob",0002:"Pierre",0003:"Meiling",0004:"Leon",0005:"Abdul",0006:"Ninja",0007:"Tomahawk",0008:"Boro",0009:"Valerie",000A:"Ushi",000B:"Joker",000C:"The Master",000D:"No Clue" crc 66CF0FFE-AD697F9C-C:50 gn Fighting Force 64 (E) cn Infinite Lives 810CE462 03E7 cn Infinite health 810C8B0E 03E7 cn Level Select cd Scroll With C-Left & C-Right Level Select Available, At The Player Select Top Screen 810A590E 0001 cn Score Aid 810CD912 29AA crc 142A17AA-13028D96-C:50 gn Forsaken 64 (E) cn Infinite\Primery Weapons 8008EE30 0012 cn Infinite\Secondary Weapons 8008EE31 0012 cn Infinite\Weapon Energy 8008EE32 0012 cn Infinite\Lives 8008EE33 0012 cn Stealth Mode 8008EE34 0012 cn Invulnerability 8008EE35 0012 cn Wireframe Mode 8008EE36 0012 cn Gore Mode 8008EE37 0012 cn Turbo Mode 8008EE38 0012 cn Psychedelic Mode 8008EE39 0012 cn One Shot Enemies 8008EE3A 0012 cn Freeze Enemies 8008EE3B 0012 cn Infinite\Titans cd Titans are included in code 8008EE3C 0012 cn Infinite\Solaris cd Solaris are included in code 8008EE3D 0012 cn Level Select cd Accesses all Missions & Battle mode 8008EE3E 0012 crc D543BCD6-2BA5E256-C:50 gn Gauntlet Legends (E) cn Get All Stuff cd Opens Up New Levels Etc, 50001410 0000 810C5DA6 FFFF cn Infinite Use Of Items cd On Pick-Ups Only 50001310 0000 800C5EC6 FFFF cn Access Skill Level 99 cd And Get A Familiar 800FD38A FFFF cn Access All Window Shards 50000302 0000 810AE6C6 07FF cn Access All Rune Stones 50000302 0000 810AE6D6 07FF cn Always Max Turbo Attack 810FD4AE FF64 cn New Player Name 810FD36C 4249 810FD36E 5443 810FD370 4820 810FD372 3639 cn Start With Small Familiar cd Do not use this with Big Familiar Code 810FD512 0102 cn Start With Big Familiar cd Do not use this with Small Familiar Code 810FD512 0202 crc 68FCF726-49658CBC-C:50 gn G.A.S.P!!Fighters'NE cn Player 1\Character Modifier cd This Allows you to play as any Character you choose in any Mode 80105001 ???? 0000:"Azami",0001:"Serina",0002:"Miki",0003:"Kai",0004:"Sakai",0005:"Kengon",0006:"Kyeya",0007:"Kaoru",0008:"Gouriki",0009:"Reiji",000A:"Yami",000B:"Hikari",000C:"Invisible Fighter" cn Player 1\Infinite Energy 81105026 03E8 cn Player 2\Player 1 Never Wins 8009E3F4 0000 cn Player 1\Need 1 Round to Win D009E334 0000 8009E334 0001 cn Player 2\Character Modifier cd This Allows you to play as any Character you choose in any Mode 8011B399 ???? 0000:"Azami",0001:"Serina",0002:"Miki",0003:"Kai",0004:"Sakai",0005:"Kengon",0006:"Kyeya",0007:"Kaoru",0008:"Gouriki",0009:"Reiji",000A:"Yami",000B:"Hikari",000C:"Invisible Fighter" cn Player 2\Infinite Energy 8111B3BE 03E8 cn Player 1\Player 2 Has No Energy cd Press C-Button Up and Player 2 will lose All Health resulting in a Instant K.O. D0044461 0008 8111B3BE 0000 cn Player 2\Player 1 Has No Energy cd Press C-Button Up and Player 1 will lose All Health resulting in a Instant K.O. D0044467 0008 81105026 0000 cn Player 2\Need 1 Round to Win D009E335 0000 8009E335 0001 cn Player 1\Player 2 Never Wins 8009E3F5 0000 cn Have All Extras Open cd This Code opens all extra stages in VS Battles,Team Battle 1P, Team Battles VS,Tag Battle and Practice Modes. Extra Male and Female Body in Create A Fighter Character and Have Extra Characters (Gouriki & Reiji) 8009E31F 00FF cn Music Modifier 8009E21E ???? 0000:"Stereo",0001:"Monaural",0002:"Music Off" crc 99179359-2FE7EBC3-C:50 gn Gex 3 - Deep Cover Gecko (E) cn Infinite\Health 810A60C8 0005 cn Infinite\Lives 810A60C6 0064 cn Crazy Tail 8110955E 0001 cn Access All\Special Remote Controls 810A60E4 FFFF 810A60E6 FFFF cn Access All\ordinary Remote Controls 50000F01 0000 800A60A8 000F cn Access All\Bonus Coins 50000F02 0000 810A6124 0007 cn Access All\Paw Coins 50000F02 0000 810A60E8 03FF crc E68A000E-639166DD-C:50 gn Gex 64 - Enter the Gecko (E) cn Infinite Health 800C50CB 0063 cn Infinite Lives 810C50C6 0063 cn INFINITE AIR CODES\Umpire Strikes Out D00BED05 0004 8136608E 012B cn INFINITE AIR CODES\Pain In The Asteroids D00BED05 0004 8133CBEE 012B cn ACCESS ALL REMOTE CONTROLS\Red Remotes cd Opens Gate 4 And The Lions Mouth 50000E01 0000 800C513E 0007 cn All Silver & Gold Gold Remotes cd Opens Gate 3,2,1 810C5164 0FFF 810C5166 FFFF 810C5168 01E0 810C516A 007F cn Hover & Fly Mode cd Press And Hold L Button + A Button D10BED04 0020 8114ECA2 0010 D10BED04 0010 cn Fully Charged Gex cd Press L Button Once When On One Of The Specific Levels, For Circuit Central Levels Only D00AAAB9 0020 81163CDE 32FF crc F5237301-99E3EE93-C:50 gn Glover cn Infinite\Energy 8029129F 0003 cn Infinite\99 Lives 8029129B 0063 cn Have Spell\Enlarge Spell 812912B4 03E8 cn 1000 Garibs 80291297 0064 cn Have Spell\Speed Up Spell 812912B8 03E8 cn Have Spell\Death Spell 812912A8 03E8 cn Have Spell\Sticky Fingers Spell 812912B2 03E8 cn All levels unlocked cd At the main menu, where it says: Start, practice, options, & time trial, hold D-pad up, then the glove, playing-with-the-ball icon, will jump down into the lower left corner of the screen, then press the A button, and a level select screen will be available with all ordinary and boss levels, etc. available 80298CFD 00A0 cn Cheat Modifier\1 80298CFE ???? 0001:"Low gravity",0002:"Big ball",0003:"Both of the above" cn Cheat Modifier\2 80298CFF ???? 0001:"Locate caribs",0002:"Call ball",0008:"Unlimited lives",0010:"Power ball",0020:"Control ball",0040:"Infinite energy",007B:"All of the above" cn [100% Complete]\Save Slot 1 cd All green crystals collected and Bonuslevels solved. 801EBA37 0007 50000801 0000 801EBA28 00FF cn [100% Complete]\Save Slot 2 cd All green crystals collected and Bonuslevels solved. 801EBA53 0007 50000801 0000 801EBA44 00FF cn [100% Complete]\Save Slot 3 cd All green crystals collected and Bonuslevels solved. 801EBA6F 0007 50000801 0000 801EBA60 00FF cn [100% Complete]\Save Slot 4 cd All green crystals collected and Bonuslevels solved. 801EBA8B 0007 50000801 0000 801EBA7C 00FF cn [100% Complete]\Save Slot 5 cd All green crystals collected and Bonuslevels solved. 801EBAA7 0007 50000801 0000 801EBA98 00FF cn [100% Complete]\Save Slot 6 cd All green crystals collected and Bonuslevels solved. 801EBAC3 0007 50000801 0000 801EBAB4 00FF cn Super Jump D02AFA14 0080 801EE771 0013 crc EE4A0E33-8FD588C9-C:50 gn GT 64 Championship Edition (E) cn Always first position 80162A80 0001 cn Only race one lap 80161DF5 0001 cn Always have 99 points 80161EC1 0063 crc AE90DBEB-79B89123-C:50 gn Hercules - The Legendary Journeys (E) cn Infinite Health & Max Health 810CFF5E 03E7 810CFF62 03E7 cn Infinite Dinars 800B6663 00E8 800B6662 00E8 cn Infinite Magic 810B6BEA 0063 810B6BD2 0063 810B6C02 0063 810B6C1A 0063 cn Press L to Levitate cd Press L Button to Levitate & Let go to come back down D017D8F5 0020 810CFFB4 44CB crc 95B2B30B-2B6415C1-C:50 gn Hexen (E) cn Access In-Game Cheat Menu cd To Access Pause Game Play. This gives you access to In-game Cheats like God Mode,Level Select,All Items Etc 81137C56 07FF 80137D33 0005 crc 277B129D-DD3879FF-C:50 gn Holy Magic Century (E) cn Set Agility to 999-999 8107C234 03E7 cn Set Defence to 999-999 8107C236 03E7 cn Makes your MP 999-999 8107C230 03E7 8107C232 03E7 cn Makes your HP 999-999 8107C22C 03E7 8107C22E 03E7 cn Have All Elements 8107C24C 3232 8107C24E 3232 cn Earn Spirits Faster 8007C25D 0000 cn No Random Battles 8108CD1C 0000 8108CD1E 0000 crc E7D20193-C1158E93-C:50 gn Hot Wheels Turbo Racing (E) cn Allways 1st 8111B14A 0000 cn Max Tournament Points 811270B6 02F4 cn Infinite Turbos 8111B39C 0800 cn Access All Cars 811270A4 FFFF 811270A6 FFFF cn A Few Extra Cars 811270AA FFFF cn Bonus Tracks 811270AE FFFF cn Race At Night 801270CF 0080 cn Mirror Mode 801270CE 0001 crc 641D3A7F-86820466-C:50 gn HYBRID HEAVEN PAL cn Have All\Keys 50000410 0000 80181B30 0063 50000410 0000 80181B38 0063 cn Infinite\Weapons & Items 50000610 0000 80181AD0 0063 50000610 0000 80181AD8 0063 cn Infinite\Refresh Items 50000E10 0000 801819F8 0063 80181A08 0063 50000D10 0000 80181A00 0063 80181A10 0063 cn Infinite\Max Body Stats 81181638 270F 81181678 0063 50000C02 0000 81181640 270F 50000502 0000 81181670 270F 50000602 0000 81181698 270F 50000602 0000 811816A6 270F cn Infinite\Max Health 81181630 270F 81181632 270F cn Level 999 81181678 270F cn Have All\Moves 50005306 0000 8118C950 0100 50005306 0000 8118C952 00FF cn Difficulty Select Options 811C5C1C ???? 0100:"Normal",0101:"Hard",0102:"Ultimate" cn Play As 811C5CF6 ???? 0001:"The real Mr Diaz Baddie",0002:"President Weller",0003:"Alien" cn Press L To Levitate D00CCE25 0020 812558F0 3FCB cn Editor's Cheat Level and Battle Select 801D74A4 0005 crc B58988E9-B1FC4BE8-C:50 gn Hydro Thunder (E) cn Always 1st 812C4DC6 0001 cn Infinite\Time 812B49C0 42C8 cn Infinite\Boosts\Player 1 812C4DCC 4190 cn Have All\Ships 812B5DD2 0101 812B5DD4 0101 812B5DD6 0101 812B5DD8 0101 812B5DDA 0101 812B5DDC 0101 812B5DDE 0101 cn Have All\Races 812B5DC4 0101 812B5DC6 0101 812B5DC8 0101 812B5DCA 0101 812B5DCC 0101 812B5DCE 0101 812B5DD0 0101 cn Infinite\Boosts\Player 2 812C50FC 4190 crc D692CC5E-EC58D072-C:50 gn Iggy's Reckin' Balls cn Access\Lizzy cd Top Secret Character 810C642C 0001 cn Access\All Characters,Worlds & Level Select cd Pause Gameplay For Level Select 810CD092 0007 cn Infinite\Turbos 810CD090 0008 cn Infinite\Time 810D9088 44E9 cn Infinite\Credits 810BDF5C 02F4 cn Laps To Race 800C8909 ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Difficulty Level Easy 810BDF68 0001 cn Have Max\Points 810D8FE0 02F4 cn Have Max\RB Medals 810D8FF0 02F4 cn Freeze Timer 810CD67C 4000 cn Max Points 800D8FE1 0063 cn Max RB Medals 800D8FF1 0063 crc E2D37CF0-F57E4EAE-C:50 gn International Superstar Soccer 64 (E) cn Home Team Scores 80119F2B ???? 0000:"",0001:"1 Goal",0002:"2 Goals",0003:"3 Goals",0004:"4 Goals",0005:"5 Goals",0006:"6 Goals",0007:"7 Goals",0008:"8 Goals,09 9 Goals,0A 10 Goals",0014:"20 Goals",001E:"30 Goals",0028:"40 Goals",0032:"50 Goals" cn Away Team Scores 8011A9BF ???? 0000:"",0001:"1 Goal",0002:"2 Goals",0003:"3 Goals",0004:"4 Goals",0005:"5 Goals",0006:"6 Goals",0007:"7 Goals",0008:"8 Goals,09 9 Goals,0A 10 Goals",0014:"20 Goals",001E:"30 Goals",0028:"40 Goals",0032:"50 Goals" cn Infinite player creation points 801AC581 003C crc F41B6343-C10661E6-C:50 gn International Superstar Soccer '98 (E) cn Home Team Scores 801A86FD ???? 0000:"",0001:"1 Goal",0002:"2 Goals",0003:"3 Goals",0004:"4 Goals",0005:"5 Goals",0006:"6 Goals",0007:"7 Goals",0008:"8 Goals,09 9 Goals,0A 10 Goals",0014:"20 Goals",001E:"30 Goals",0028:"40 Goals",0032:"50 Goals" cn Away Team Scores 801A9579 ???? 0000:"",0001:"1 Goal",0002:"2 Goals",0003:"3 Goals",0004:"4 Goals",0005:"5 Goals",0006:"6 Goals",0007:"7 Goals",0008:"8 Goals,09 9 Goals,0A 10 Goals",0014:"20 Goals",001E:"30 Goals",0028:"40 Goals",0032:"50 Goals" cn Infinite player creation points D03E0CF2 0001 803E0CF2 0063 crc 68D7A1DE-0079834A-C:50 gn JET FORCE GEMINI cn Access\All Characters 80208910 FFFF cn Infinite Continues 800A34F1 0063 cn Juno\Full & Max Health 80208AB5 000C 80208AB2 0040 cn Juno\Access\All Keys 81208B18 FFF7 cn Juno\Access\All Objects 81208B1A FFFF cn Juno\Infinite\Mizar Tokens 81208AC4 02F4 cn Juno\Max Blue & White Heads 81208ABA 03E7 81208AB8 03E7 cn Juno\Infinite\Max Ammo All Guns 50000302 0000 81208AC6 02F4 50000802 0000 81208ACC 02F4 50000402 0000 81208ADC 02F4 cn Vela\Full & Max Health 80208A3F 000C 80208A3C 0040 cn Vela\Access\All Keys 81208AA2 FF70 cn Vela\Access\All Objects 81208AA4 FFFF cn Vela\Infinite\Mizar Tokens 81208A4E 02F4 cn Vela\Max\Blue & White Heads 81208A44 03E7 81208A42 03E7 cn Vela\Infinite\Max Ammo All Guns 50000302 0000 81208A50 02F4 50000802 0000 81208A56 02F4 50000402 0000 81208A66 02F4 cn Lupus\Full & Max Health 80208B2B 000C 80208B28 0040 cn Lupus\Access\All Keys 81208B8E FF70 cn Lupus\Access\All Objects 81208B90 FFFF cn Lupus\Infinite\Mizar Tokens 81208B3A 02F4 cn Lupus\Max\Blue & White Heads 81208B30 03E7 81208B2E 03E7 cn Lupus\Infinite\Max Ammo All Guns 50000302 0000 81208B3C 02F4 50000802 0000 81208B42 02F4 50000402 0000 81208B52 02F4 cn Access\All Floyd Awards cd only enable One character at a time when using this code 50000501 0000 80208908 0005 cn Juno\Access\All Weapons cd Do not put this code on until you collect one Extra Weapon then you will have all ready to use 80208ABC 00FF 80208ABD 00FF cn Vela\Access\All Weapons cd Do not put this code on until you collect one Extra Weapon then you will have all ready to use 80208A46 00FF 80208A47 00FF cn Lupus\Access\All Weapons cd Do not put this code on until you collect one Extra Weapon then you will have all ready to use 80208B32 00FF 80208B33 00FF cn Tribals\Have All Tribals\Gold Wood 802088E4 000F cn Tribals\No Tribals Killed\Gold Wood 802088E5 0000 cn Tribals\Have No Tribals Remaining\Gold Wood 802088E6 0000 cn [Resolution Fix] 800FE6F2 0003 800FE6DE 0003 800FEDEA 00D0 cn Vela\All Single Player Levels Unlocked 80208AA0 00FF 80208AA1 00FF cn Juno\All Single Player Levels Unlocked 80208B16 00FF 80208B17 00FF cn Lupus\All Single Player Levels Unlocked 80208B8C 00FF 80208B8D 00FF cn All Single Player Levels Unlocked cd All Charcters 80208AA0 00FF 80208AA1 00FF 80208B16 00FF 80208B17 00FF 80208B8C 00FF 80208B8D 00FF crc 0F743195-D8A6DB95-C:50 gn John Romero's Daikatana (E) cn Infinite\Health 81207B24 03E7 cn Max\Experience 81207B26 03E7 cn Infinite\Armour 81207B44 0001 81207B46 03E7 cn Max\Attributes 50000502 0000 81207B28 0007 cn Level Select 811C6B4E 0001 cn Access\All Items cd Press L Button Where Items Are available D0209D85 0020 81207B8C 007F cn Access\All Guns & Infinite Ammo 81207AB4 007F 81207AB6 FFFF 81207B84 03E7 50000A02 0000 81207B70 03E7 crc 979B263E-F8470004-C:50 gn Killer Instinct Gold (E) cn Infinite Health 801D3584 0078 cn Invincible 801D35D4 000A cn Access In-Game Cheats 801283DC 0006 cn Access Gargos Character 80127DC8 0001 cn Fast Kick & Punch 801D357E 0010 cn Max Blood 80127D5D 0003 cn No Time Limit 80127D5B 0001 crc 0D93BA11-683868A6-C:50 gn Kirby64 cn Infinite Max Health 800D718F 0006 800D7151 00C0 cn Kirkby can fly unlimited 8012EADF 00F0 cn Access all enemy info 50005101 0000 800D6F10 0002 cn Access all crystals 50000701 0000 800D6EC0 0001 50001701 0000 800D6EC8 0007 cn Access all difficulty levels cd 100 yard hop, bumper crop bump & checkerboard chase 50000301 0000 800D6E69 0003 cn All Levels completed cd You must still beat boss's to continue onto next level 50002B01 0000 800D6EE0 0002 cn All Save Slots 100% Completed\Save slot 1 800ECD18 0064 cn All Save Slots 100% Completed\Save slot 2 800ECD70 0064 cn All Save Slots 100% Completed\Save slot 3 800ECDC8 0064 cn Infinite Max Lives 800D714F 0064 crc 4A997C74-E2087F99-C:50 gn Knife Edge - Nose Gunner (E) cn Infinite Armour\Player One 8011D65F 0064 cn Infinite Bombs\Player One 8011D667 0003 cn Level 11 Vulcan Cannon\Player One 80123BAB 000A cn Infinite Armour\Player Two 8011D663 0064 cn Infinite Bombs\Player Two 8011D66B 0003 cn Level 11 Vulcan Cannon\Player Two 80123BCB 000A cn Level Select 81123E16 000C cn Extreme Mode 8111D332 0003 cn Max Score 81123B82 FC9A crc E3D6A795-2A1C5D3C-C:50 gn Knockout Kings 2000 (E) cn Infinite Health\Player 1 8106B974 42C8 8106B9DE 0000 cn Infinite Health\Player 2 8106BAE4 42C8 8106BAE6 0000 cn No Health\Player 1 8106B9DC 0000 8106B9DE 0000 cn No Health\Player 2 8106BAE4 0000 8106BAE6 0000 cn Full Punch Meter\Player 1 8106B9E8 0000 8106B9EA 0BB2 cn Full Punch Meter\Player 2 8106B9E8 0000 8106B9EA 0BB2 cn Empty Punch Meter\Player 1 8106B9E8 0000 8106B9EA 0000 cn Empty Punch Meter\Player 2 8016BAF0 0000 8016BAF2 0000 cn Infinite Boxer Creation Points 810637AA 0064 cn Have Full\Power Bar 810637AE 0064 cn Have Full\Speed Bar 810637B2 0064 cn Have Full\Stamina Bar 810637B6 0064 cn Big Options\Big Head Mode 800F407C 0001 cn Big Options\Big Gloves Mode 800F407D 0001 crc E97955C6-BC338D38-C:50 gn Legend of Zelda, The - Majora's Mask (E) (M4) (v1.0) cn Infinite\Rupees 811E6B8A 03E7 cn Infinite\Health 811E6B86 03E7 cn Infinite\Max & Double Magic Meter 801E6B89 0060 811E6B90 0101 cn Infinite\Items cd This is Infinite use of Bombs,Bombchus,Deku Sticks,Deku Nuts,Magic Beans,& Powder Kegs. But you must also put it's Have on to work. 801E6BF1 0063 801E6BF6 0063 801E6BF7 0063 801E6BF8 0063 801E6BF9 0063 801E6BFA 0063 801E6BFC 0063 801E6BFB 0063 801E6BFD 0063 cn Have\All Masks 811E6BD8 3E39 811E6BDA 4745 811E6BDC 4032 811E6BDE 3A46 811E6BE0 3842 811E6BE2 4833 811E6BE4 3C3D 811E6BE6 373F 811E6BE8 3634 811E6BEA 4341 811E6BEC 3B44 811E6BEE 4935 cn Use all C Buttons 811EAA68 0000 811EAA6A 0000 cn Event Item\Modifier 1 801E6BC5 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 2 801E6BCB ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 3 801E6BD1 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Have Item Modifier 801E6BD0 ???? 0005:"Japanese Flute?",000B:"Japanese Item?",0010:"Great Fairy's Sword",0011:"Japanese Hookshot?",0031:"Japanese Scroll?",004A:"Japanese Bow?" cn Bottles\Bottle 1 Modifier 801E6BD2 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 2 Modifier 801E6BD3 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 3 Modifier 801E6BD4 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 4 Modifier 801E6BD5 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 5 Modifier 801E6BD6 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 6 Modifier 801E6BD7 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Great Fairy's Sword 801E6BD0 0010 cn Have\QuestStatus Items 801E6C0D 0005 811E6C0E F7CF cn Have\Have Ocarina of Time 801E6BC0 0000 cn Have\Hero's Bow 801E6BC1 0001 cn Have\Fire Arrow 801E6BC2 0002 cn Have\Ice Arrow 801E6BC3 0003 cn Have\Light Arrow 801E6BC4 0004 cn Have\Bombs 801E6BC6 0006 cn Have\Bombchu 801E6BC7 0007 cn Have\Deku Sticks 801E6BC8 0008 cn Have\Deku Nuts 801E6BC9 0009 cn Have\Magic Beans 801E6BCA 000A cn Have\Powder Kegs 801E6BCC 000C cn Have\Pictograph 801E6BCD 000D cn Have\Lens of Truth 801E6BCE 000E cn Have\Hookshot 801E6BCF 000F cn All Equipment Upgrades 801E6BBD 0023 811E6C0A 201B 801E6B9C 004F cn Replace Sword With cd Only put the Deity Link's Sword on, if using The Play As Fierce Deity Link Code, if not it will turn Fierce Deity Link into a crazed slashing Machine. You have been warned. 801E6B9C ???? 004A:"Fire Arrow w/ Bow",004B:"Ice Arrow w/ Bow",004C:"Light Arrow w/ Bow",004D:"Kokiri Sword",004E:"Razor Sword",004F:"Guilded Sword",0050:"Deity Link's Sword" cn Play As 801E6B70 ???? 0000:"Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Infinite\Hearts Options cd If you need to clear the Infinite Max Hearts from the screen just choose the 6 or 4 Heart Options, take off the cheat & then make a save. 811E6B84 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Press L To Levitate cd Press L To Levitate & Let go to land D03DDFDB 0020 813F72B8 40CB cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D03DDFDB 0000 801E6B52 ???? 0000:"Mama's House",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0003:"Southern Swamp Mr Tingle Entry",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",002E:"Woodfall Temple non Beta",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",0038:"Path to Romani Ranch non Beta",004A:"outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",0074:"Cave Portal to Last Boss Field",007F:"Waterfall Sothern Swamp",008A:"Giant Turtle In the Temple non beta",008B:"Room of Miau & Tijo Zora Great Hall",0094:"Recieving Gorans Mask non Beta",0095:"?",0096:"Hungry Goran in the Snow",00A2:"Statue in Stone Tower",00A6:"Stone Tower non Beta",00B9:"Recieving Deku Mask non Beta",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water",00FF:"Vamps House In Ikana Canyon" cn Warp Modifier cd Put this code on and it will now take where you wanted to go, turn it back off or it will infinite loop entering all the time. 803DDFDA 0000 803F6835 0001 813F683A ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" crc 0A5D8F83-98C5371A-C:50 gn Legend of Zelda, The - Majora's Mask (E) (M4) (v1.1) cn Infinite\Rupees 811E6F2A 03E7 cn Infinite\Health 811E6F26 03E7 cn Infinite\Max & Double Magic Meter 801E6F29 0060 811E6F30 0101 cn Infinite\Items cd This is Infinite use of Bombs,Bombchus,Deku Sticks,Deku Nuts,Magic Beans,& Powder Kegs. But you must also put it's Have on to work. 801E6F91 0063 50000801 0000 801E6F96 0063 cn Have\All Masks 811E6F78 3E39 811E6F7A 4745 811E6F7C 4032 811E6F7E 3A46 811E6F80 3842 811E6F82 4833 811E6F84 3C3D 811E6F86 373F 811E6F88 3634 811E6F8A 4341 811E6F8C 3B44 811E6F8E 4935 cn Use all C Buttons 811EAE08 0000 811EAE0A 0000 cn Event Item\Modifier 1 801E6F65 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 2 801E6F6B ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 3 801E6F71 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Have Item Modifier 801E6F70 ???? 0005:"Japanese Flute?",000B:"Japanese Item?",0010:"Great Fairy's Sword",0011:"Japanese Hookshot?",0031:"Japanese Scroll?",004A:"Japanese Bow?" cn Bottles\Bottle 1 Modifier 801E6F72 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 2 Modifier 801E6F73 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 3 Modifier 801E6F74 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 4 Modifier 801E6F75 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 5 Modifier 801E6F76 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 6 Modifier 801E6F77 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Great Fairy's Sword 801E6F70 0010 cn Have\QuestStatus Items 801E6FAD 0005 811E6FAE F7CF cn Have\Have Ocarina of Time 801E6F60 0000 cn Have\Hero's Bow 801E6F61 0001 cn Have\Fire Arrow 801E6F62 0002 cn Have\Ice Arrow 801E6F63 0003 cn Have\Light Arrow 801E6F64 0004 cn Have\Bombs 801E6F66 0006 cn Have\Bombchu 801E6F67 0007 cn Have\Deku Sticks 801E6F68 0008 cn Have\Deku Nuts 801E6F69 0009 cn Have\Magic Beans 801E6F6A 000A cn Have\Powder Kegs 801E6F6C 000C cn Have\Pictograph 801E6F6D 000D cn Have\Lens of Truth 801E6F6E 000E cn Have\Hookshot 801E6F6F 000F cn All Equipment Upgrades 801E6F5D 0023 811E6FAA 201B 801E6F3C 004F cn Replace Sword With cd Only put the Deity Link's Sword on, if using The Play As Fierce Deity Link Code, if not it will turn Fierce Deity Link into a crazed slashing Machine. You have been warned. 801E6F3C ???? 004A:"Fire Arrow w/ Bow",004B:"Ice Arrow w/ Bow",004C:"Light Arrow w/ Bow",004D:"Kokiri Sword",004E:"Razor Sword",004F:"Guilded Sword",0050:"Deity Link's Sword" cn Play As 801E6F10 ???? 0000:"- Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Infinite\Hearts Options cd If you need to clear the Infinite Max Hearts from the screen just choose the 6 or 4 Heart Options, take off the cheat & then make a save. 811E6F24 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Press L To Levitate cd Press L To Levitate & Let go to land D03DE37B 0020 813F7658 40CB cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D03DE37B 0000 801E6EF2 ???? 0000:"Mama's House",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",004A:"Outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"Inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",007F:"Waterfall Sothern Swamp",008B:"Room of Miau & Tijo Zora Great Hall",00A2:"Statue in Stone Tower",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water" cn Warp Modifier cd Put this code on and it will now take where you wanted to go, turn it back off or it will infinite loop entering all the time. 803DE37A 0000 803F6BD5 0001 813F6BDA ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" crc 6AECEC4F-F0924814-C:50 gn The Legend of Zelda - Majora's Mask - Collector's Edition (E) (GC Version) cn Infinite\Rupees 811E54BA 03E7 cn Infinite\Health 811E54B6 03E7 cn Infinite\Max & Double Magic Meter 801E54B9 0060 811E54C0 0101 cn Infinite\Items cd This is Infinite use of Bombs,Bombchus,Deku Sticks,Deku Nuts,Magic Beans,& Powder Kegs. But you must also put it's Have on to work. 801E5521 0063 50000801 0000 801E5526 0063 cn Have\All Masks 811E5508 3E39 811E550A 4745 811E550C 4032 811E550E 3A46 811E5510 3842 811E5512 4833 811E5514 3C3D 811E5516 373F 811E5518 3634 811E551A 4341 811E551C 3B44 811E551E 4935 cn Use all C Buttons 811E9398 0000 811E939A 0000 cn Event Item\Modifier 1 801E54F5 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 2 801E54FB ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Event Item\Modifier 3 801E5501 ???? 0028:"Moon's Tear",0029:"Land Title Deed",002A:"Swap Title Deed",002B:"Mountain Title Deed",002C:"Ocean Title Deed",002D:"Room Key",002E:"Special Delivery To Mama",002F:"Letter To Kafei",0030:"Pendant Of Memories" cn Have Item Modifier 801E5500 ???? 0005:"Japanese Flute?",000B:"Japanese Item?",0010:"Great Fairy's Sword",0011:"Japanese Hookshot?",0031:"Japanese Scroll?",004A:"Japanese Bow?" cn Bottles\Bottle 1 Modifier 801E5502 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 2 Modifier 801E5503 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 3 Modifier 801E5504 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 4 Modifier 801E5505 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 5 Modifier 801E5506 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Bottles\Bottle 6 Modifier 801E5507 ???? 0012:"Empty Bottle",0013:"Red Potion",0014:"Green Potion",0015:"Blue Potion",0016:"Fairy",0017:"Deku Princess",0018:"Milk",0019:"Milk (1/2)",001A:"Fish",001B:"Bug",001C:"Blue Fire",001D:"Poe",001E:"Big Poe",001F:"Spring Water",0020:"Hot Spring Water",0021:"Zora Egg",0022:"Gold Dust",0023:"Magical Mushroom",0024:"Sea Horse",0025:"Chateau Romani",0026:"Japanese Bottle?",0027:"Empty Japanese Bottle?" cn Have\Great Fairy's Sword 801E5500 0010 cn Have\QuestStatus Items 801E553D 0005 811E553E F7CF cn Have\Have Ocarina of Time 801E54F0 0000 cn Have\Hero's Bow 801E54F1 0001 cn Have\Fire Arrow 801E54F2 0002 cn Have\Ice Arrow 801E54F3 0003 cn Have\Light Arrow 801E54F4 0004 cn Have\Bombs 801E54F6 0006 cn Have\Bombchu 801E54F7 0007 cn Have\Deku Sticks 801E54F8 0008 cn Have\Deku Nuts 801E54F9 0009 cn Have\Magic Beans 801E54FA 000A cn Have\Powder Kegs 801E54FC 000C cn Have\Pictograph 801E54FD 000D cn Have\Lens of Truth 801E54FE 000E cn Have\Hookshot 801E54FF 000F cn All Equipment Upgrades 801E54ED 0023 811E553A 201B 801E54CC 004F cn Replace Sword With cd Only put the Deity Link's Sword on, if using The Play As Fierce Deity Link Code, if not it will turn Fierce Deity Link into a crazed slashing Machine. You have been warned. 801E54CC ???? 004A:"Fire Arrow w/ Bow",004B:"Ice Arrow w/ Bow",004C:"Light Arrow w/ Bow",004D:"Kokiri Sword",004E:"Razor Sword",004F:"Guilded Sword",0050:"Deity Link's Sword" cn Play As 801E54A0 ???? 0000:"Fierce Deity Link",0001:"Goron Link",0002:"Zora Link",0003:"Deku Link",0004:"Normal Link" cn Infinite\Hearts Options cd If you need to clear the Infinite Max Hearts from the screen just choose the 6 or 4 Heart Options, take off the cheat & then make a save. 811E54B4 ???? 0140:"Max Hearts",0063:"6 Hearts",0043:"4 Hearts" cn Press L To Levitate cd Press L To Levitate & Let go to land D0378ECB 0020 813921A8 40CB cn Beta World 1 cd Put on the code on load up,After the Nintendo logo you will be in that place of Choice.you can also choose another place & then press F1 (reset) to go to that place this is for beta interest only it will not assist you in playing the game. D03DC90B 0000 801E5482 ???? 0000:"Mama's House non Beta",0001:"Fearful Spider House",0002:"Beneaf the Graveyard",0003:"Southern Swamp Mr Tingle Entry",0006:"Outside Tourist Information Southern Swamp",0008:"Outside Magic Hag's Potion Shop",000A:"Southern Swamp Woods Of Mystery Entry",0024:"Counter Of The Tresure Chest Shop",002E:"Woodfall Temple non Beta",0032:"Spider Hand",0035:"Statue outside Gorman Track",0036:"Statue outside Lair Of The Temples Boss",0038:"Path to Romani Ranch non Beta",004A:"outside The Royal Palace of the Deku Kingdom",004C:"Ledge in The Royal Palace of the Deku Kingdom",004E:"inside The Royal Palace of the Deku Kingdom 1",0071:"Green Blobs",0074:"Cave Portal to Last Boss Field",007F:"Waterfall Sothern Swamp",008A:"Giant Turtle In the Temple non beta",008B:"Room of Miau & Tijo Zora Great Hall",0094:"Recieving Gorans Mask non Beta",0095:"?",0096:"Hungry Goran in the Snow",00A2:"Statue in Stone Tower",00A6:"Stone Tower non Beta",00B9:"Recieving Deku Mask non Beta",00D9:"Giant Lizards in a Cave",00DA:"Cave with Steaming Water",00FF:"Vamps House In Ikana Canyon" cn Warp Modifier cd Put this code on and it will now take where you wanted to go, turn it back off or it will infinite loop entering all the time. 803DC90A 0000 803F5165 0001 813F516A ???? 0010:"Mayors Residence",0008:"Magic Hags Potion Shop",000A:"Romani Ranch Barn",000B:"Mama's House",000E:"Honey & Darlings Shop",0015:"Final Boss Arena",001F:"Beneath the Graveyard (left entrance)",002F:"Beneath the Graveyard (right entrance)",0030:"Southern Swamp (Reg Entrance)",004F:"Southern Swamp (from tour house)",006E:"Southern Swamp (from Woodfall)",006F:"Southern Swamp (from Deku Palace)",0078:"Path to Ikana Canyon",009E:"Southern Swamp (from Deku Place 2)",009F:"Southern Swamp (From Potion Shop)",00AF:"Boat Cruise (picture taking)",00CD:"Southern Swamp (From Woods of Mystery)",00CE:"Southern Swamp (From Spider House)",00CF:"Southern Swamp (From Ikana Canyon)",00FE:"Southern Swamp (From Owl Warp)",0E00:"Curiosity Shop",0E38:"Ikana Canyon Entrance",1500:"Lens of Truth Cave (get it)",2600:"Stone Tower Temple (Upside down)",2609:"Stone Tower Temple (Boss Room Entrance)",2604:"Treasure Chest Shop",2605:"Treausre Chest Shop (counter)",260E:"Clock Tower (w/ skull kid, silent)",2610:"Stone Tower Temple (endless fall)",6214:"Romani Ranch",9214:"Zora Shop",B214:"Snowhead (Path to temple, warp in)",D214:"East Clock Down" crc B044B569-373C1985-C:50 gn Legend of Zelda, The - Ocarina of Time (E) (V1.0) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 8111979C 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C64F5 0010 801183D7 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 811195F2 0000 811195F4 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 8111846C 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 81118474 30FF 81118476 FFFF cn Max\Heart Containers 811183FE 0140 cn Max\Gold Skulltulas Killed 801184A1 0064 cn Time of Day Modifier 811183DC ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 81118400 0140 cn Infinite\Magic D0118409 0008 8011840A 0001 8011840C 0001 80118403 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 80118440 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011845C 0009 cn Infinite\Deku Nuts 8011845D 0009 cn Infinite\Bombs 8011845E 0009 cn Infinite\Arrows 8011845F 0009 cn Infinite\Deku Seeds 80118462 0009 cn Infinite\Bombchu's 80118464 0009 cn Infinite\Magic Beans 8011846A 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 50000B01 0000 80118478 0007 50000501 0000 8011848F 0009 80118497 0009 80118499 0009 8011849C 0009 cn Have\Ocarina 8011844B ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 80118450 000E cn Have\Lens of Truth 80118451 000F cn Have\Megaton Hammer 80118453 0011 cn Have\Deku Stick 80118444 0000 cn Have\Deku Nut 80118445 0001 cn Have\Bombs 80118446 0002 cn Have\Fairy Bow 80118447 0003 cn Have\Fairy Slingshot 8011844A 0006 cn Have\Bombchu 8011844C 0009 cn Have\Arrows\Fire Arrow 80118448 0004 cn Have\Arrows\Ice Arrow 8011844E 000C cn Have\Arrows\Light Arrow 80118454 0012 cn Have\Hookshot 8011844D ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 80118452 0010 cn Have\Magic\Fairie's Wind 8011844F 000D cn Have\Magic\Nayru's Love 80118455 0013 cn Have\Magic\Din's Fire 80118449 0005 cn Bottles\Bottle 1 Modifier 80118456 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 80118457 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 80118458 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 80118459 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011845A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011845B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011840E 0001 cn Have Quiver (Holds 30) 80118471 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 80118472 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 80118473 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Press L To Levitate & Let go to land D01C64F5 0020 811D8AE0 40CB cn Press L For infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C64F5 0020 811D92F2 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C64F5 0020 811D8AE0 40CB D01C64F5 0000 811D92F2 000D 80118440 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Hyrule Field,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C64F5 0000 801197E3 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119765 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119765 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119765 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119765 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 8011849F 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 801D851B ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 801197A1 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F12C8 0005 801EDD08 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 801197A5 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 80023414 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C64F5 0010 81119736 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 801192B9 00FF 8011972F ???? 0000:"Off",0001:"Off" cn Always Have Wallet Size 80118472 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" cn Language Select 801197D9 ???? 0000:"English",0001:"German",0002:"French" cn Dark Link\Make Dark Link Apear In TOT 8023D6DF 0020 8023D6E5 0033 crc B2055FBD-0BAB4E0C-C:50 gn Legend of Zelda, The - Ocarina of Time (E) (V1.1) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 811197DC 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C6535 0010 80118417 ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 81119632 0000 81119634 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811184AC 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811184B4 30FF 811184B6 FFFF cn Max\Heart Containers 8111843E 0140 cn Max\Gold Skulltulas Killed 801184E1 0064 cn Time of Day Modifier 8111841C ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 81118440 0140 cn Infinite\Magic D0118449 0008 8011844A 0001 8011844C 0001 80118443 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 80118480 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 8011849C 0009 cn Infinite\Deku Nuts 8011849D 0009 cn Infinite\Bombs 8011849E 0009 cn Infinite\Arrows 8011849F 0009 cn Infinite\Deku Seeds 801184A2 0009 cn Infinite\Bombchu's 801184A4 0009 cn Infinite\Magic Beans 801184AA 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 50000B01 0000 801184B8 0007 50000501 0000 801184CF 0009 801184D7 0009 801184D9 0009 801184DC 0009 cn Have\Ocarina 8011848B ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 80118490 000E cn Have\Lens of Truth 80118491 000F cn Have\Megaton Hammer 80118493 0011 cn Have\Deku Stick 80118484 0000 cn Have\Deku Nut 80118485 0001 cn Have\Bombs 80118486 0002 cn Have\Fairy Bow 80118487 0003 cn Have\Fairy Slingshot 8011848A 0006 cn Have\Bombchu 8011848C 0009 cn Have\Arrows\Fire Arrow 80118488 0004 cn Have\Arrows\Ice Arrow 8011848E 000C cn Have\Arrows\Light Arrow 80118494 0012 cn Have\Hookshot 8011848D ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 80118492 0010 cn Have\Magic\Fairie's Wind 8011848F 000D cn Have\Magic\Nayru's Love 80118495 0013 cn Have\Magic\Din's Fire 80118489 0005 cn Bottles\Bottle 1 Modifier 80118496 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 80118497 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 80118498 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 80118499 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 8011849A ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 8011849B ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 8011844E 0001 cn Have Quiver (Holds 30) 801184B1 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 801184B2 ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 801184B3 ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Press L To Levitate & Let go to land D01C6535 0020 811D8B20 40CB cn Press L For infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D01C6535 0020 811D9332 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D01C6535 0020 811D8B20 40CB D01C6535 0000 811D9332 000D 80118480 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Hyrule Field,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C6535 0000 80119823 ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 801184DF 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 811197D8 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 801197E1 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F1308 0005 801EDD48 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 801197E5 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 80023454 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C6535 0010 81119776 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 801192F9 00FF 8011976F ???? 0000:"Off",0001:"Off" cn Always Have Wallet Size 801184B2 ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" cn Language Select 80119819 ???? 0000:"English",0001:"German",0002:"French" cn Dark Link\Make Dark Link Apear In TOT 8023D71F 0020 8023D725 0033 crc 09465AC3-F8CB501B-C:50 gn Legend of Zelda, The - Ocarina of Time (E) (GC Version) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 81119D24 0001 cn Press R\For Old Or Young Link cd To Activate this Cheat Hold The R Button when walking through a Doorway this will change you to the option on the other side, Disable this Cheat straight away after getting to the other side, in some places you might even get Access Violations. Just press ok untill you can carry on. D01C6A7D 0010 8011895F ???? 0001:"Link Young",0000:"Link Old" cn Use Any Item In Any House cd do not use under or in water 81119B7A 0000 81119B7C 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811189F4 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811189FC 30FF 811189FE FFFF cn Max\Heart Containers 81118986 0140 cn Max\Gold Skulltulas Killed 80118A29 0064 cn Time of Day Modifier 81118964 ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 81118988 0140 cn Infinite\Magic D0118991 0008 80118992 0001 80118994 0001 8011898B 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 801189C8 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 801189E4 0009 cn Infinite\Deku Nuts 801189E5 0009 cn Infinite\Bombs 801189E6 0009 cn Infinite\Arrows 801189E7 0009 cn Infinite\Deku Seeds 801189EA 0009 cn Infinite\Bombchu's 801189EC 0009 cn Infinite\Magic Beans 801189F2 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 50000B01 0000 80118A00 0007 50000501 0000 80118A17 0009 80118A1F 0009 80118A21 0009 80118A24 0009 cn Have\Ocarina 801189D3 ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 801189D8 000E cn Have\Lens of Truth 801189D9 000F cn Have\Megaton Hammer 801189DB 0011 cn Have\Deku Stick 801189CC 0000 cn Have\Deku Nut 801189CD 0001 cn Have\Bombs 801189CE 0002 cn Have\Fairy Bow 801189CF 0003 cn Have\Fairy Slingshot 801189D2 0006 cn Have\Bombchu 801189D4 0009 cn Have\Arrows\Fire Arrow 801189D0 0004 cn Have\Arrows\Ice Arrow 801189D6 000C cn Have\Arrows\Light Arrow 801189DC 0012 cn Have\Hookshot 801189D5 ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 801189DA 0010 cn Have\Magic\Fairie's Wind 801189D7 000D cn Have\Magic\Nayru's Love 801189DD 0013 cn Have\Magic\Din's Fire 801189D1 0005 cn Bottles\Bottle 1 Modifier 801189DE ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 801189DF ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 801189E0 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 801189E1 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 801189E2 ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 801189E3 ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 80118996 0001 cn Have Quiver (Holds 30) 801189F9 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 801189FA ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 801189FB ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Press L To Levitate cd Press L To Levitate & Let go to land D011BB37 0020 811D9410 40CB cn Press L For infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D011BB37 0020 811D9C32 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D011BB37 0020 811D9410 40CB D011BB37 0000 811D9C32 000D 801189C8 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Play Beta Quest Worlds cd Put on the code on load up,After the Nintendo logo you will be in Hyrule Field,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D01C6A7D 0000 80119D6B ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 801197A5 ???? 0005:"Lake Hylia,08 Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Max\Double Defense Power cd This gives you White Border Hearts 80118A27 0014 cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 81119D20 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 80119D29 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F1850 0005 801EE290 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 80119D2D 00B4 cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 8002399C 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C6A7D 0010 81119CBE 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 80119841 00FF 80119CB7 ???? 0000:"Off",0001:"Off" cn Always Have Wallet Size 801189FA ???? 0047:"Kid Wallet (Holds 99)",0057:"Adult Wallet (Holds 200)",0067:"Giant Wallet (Holds 500)" cn Language Select 80119D61 ???? 0000:"English",0001:"German",0002:"French" crc 1D4136F3-AF63EEA9-C:50 gn Legend of Zelda, The - Ocarina of Time - Master Quest (E) cn Infinite\Rupees cd This cheat allows you to have the max Rupees to the Wallet you currently Hold 81119D04 0001 cn Max\Double Defense Power cd This gives you White Border Hearts 80118A07 0014 cn Use Any Item In Any House cd do not use under or in water 81119B5A 0000 81119B5C 0000 cn Have\All Equipment cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 811189D4 7777 cn Have\All Quest/Status Items cd This cheat causes the Goron Temple door not to open, but if you go to the very top of the mountain where the fairy is, next to her entrance is another one in to the fire temple.once inside put on the hover boots & infinite hover cheat to hover over to the ledge on the left hand side.From here you can carry on the game as normal 801189DD ???? 801189DE ???? 801189DF ???? 00FF:"On",0000:"Off" cn Max\Heart Containers 81118966 0140 cn Max\Gold Skulltulas Killed 80118A09 0064 cn Time of Day Modifier 81118944 ???? 4000:"At Sunrise",5800:"Daylight Out",7000:"Very Bright Out",C000:"At Sunset",D000:"Fairly Dark" cn Infinite\Energy 81118968 0140 cn Infinite\Magic D0118971 0008 80118972 0001 80118974 0001 8011896B 0060 cn Tunic & Boot Options cd This changes what you are wearing,once you have enabled the code press Start & then start again. 801189A8 ???? 0011:"Kokiri Tunic & Kokiri Boots",0012:"Goron Tunic & Kokiri Boots",0013:"Zora Tunic & Kokiri Boots",0014:"Black Tunic & Kokiri Boots",0015:"White Tunic & Kokiri Boots",0016:"Yellow Tunic & Kokiri Boots",0021:"Kokiri Tunic & Iron Boots",0022:"Goron Tunic & Iron Boots",0023:"Zora Tunic & Iron Boots",0024:"Black Tunic & Iron Boots",0025:"White Tunic & Iron Boots",0026:"Yellow Tunic & Iron Boots",0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Infinite\Deku Sticks 801189C4 0009 cn Infinite\Deku Nuts 801189C5 0009 cn Infinite\Bombs 801189C6 0009 cn Infinite\Arrows 801189C7 0009 cn Infinite\Deku Seeds 801189CA 0009 cn Infinite\Bombchu's 801189CC 0009 cn Infinite\Magic Beans 801189D2 0009 cn Infinite\Big Key,Small Keys,Compass,& Map 801189E0 0007 801189E1 0007 801189E2 0007 801189E3 0007 801189E4 0007 801189E5 0007 801189E6 0007 801189E7 0007 801189E8 0007 801189E9 0007 801189EA 0007 801189F7 0009 801189F8 0009 801189F9 0009 801189FA 0009 801189FB 0009 80118A01 0009 80118A04 0009 801189FF 0009 cn Have\Ocarina 801189B3 ???? 0007:"Fairy Ocarina",0008:"Ocarina Of Time" cn Have\Boomerang 801189B8 000E cn Have\Lens of Truth 801189B9 000F cn Have\Megaton Hammer 801189BB 0011 cn Have\Deku Stick 801189AC 0000 cn Have\Deku Nut 801189AD 0001 cn Have\Bombs 801189AE 0002 cn Have\Fairy Bow 801189AF 0003 cn Have\Fairy Slingshot 801189B2 0006 cn Have\Bombchu 801189B4 0009 cn Have\Arrows\Fire Arrow 801189B0 0004 cn Have\Arrows\Ice Arrow 801189B6 000C cn Have\Arrows\Light Arrow 801189BC 0012 cn Have\Hookshot 801189B5 ???? 000A:"Hookshot",000B:"Longshot" cn Have\Magic Beans 801189BA 0010 cn Have\Magic\Fairie's Wind 801189B7 000D cn Have\Magic\Nayru's Love 801189BD 0013 cn Have\Magic\Din's Fire 801189B1 0005 cn Bottles\Bottle 1 Modifier 801189BE ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 2 Modifier 801189BF ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 3 Modifier 801189C0 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Bottles\Bottle 4 Modifier 801189C1 ???? 0014:"Empty Bottle",0015:"Red Potion",0016:"Green Potion",0017:"Blue Potion",0018:"Bottled Fairy",0019:"Fish",001A:"Lon Lon Milk",001B:"Letter",001C:"Blue Fire",001D:"Bug",001E:"Big Poe",001F:"Lon Lon Milk (Half)",0020:"Poe" cn Trading\Adult Link Item 801189C2 ???? 002D:"Pocket Egg",002E:"Pocket Cucco",002F:"Cojiro",0030:"Odd Mushroom",0031:"Odd Potion",0032:"Poacher's Saw",0033:"Goron's Sword (Broken)",0034:"Prescription",0035:"Eyeball Frog",0036:"Eye Drops",0037:"Claim Check" cn Trading\Young Link Item 801189C3 ???? 0021:"Weird Egg",0022:"Chicken",0023:"Zelda's Letter",0024:"Keaton Mask",0025:"Skull Mask",0026:"Spooky Mask",0027:"Bunny Hood",0028:"Goron Mask",0029:"Zora Mask",002A:"Gerudo Mask",002B:"Mask of Truth",002C:"SOLD OUT" cn Turn Giant's Knife Into Biggoron's Sword 80118976 0001 cn Have Quiver (Holds 30) 801189D9 0001 cn Equipment Modifier 1 cd This modifies the equipment you are carrying. 801189DA ???? 0002:"Silver Scale",0004:"Golden Scale",0006:"Giant's Knife (Broken)",0035:"Black Gauntlets",0040:"Bullet Bag (Holds 30)",0080:"Bullet Bag (Holds 40)",00C0:"Bullet Bag (Holds 50)" cn Equipment Modifier 2 cd This modifies the equipment you are carrying. 801189DB ???? 0008:"Bomb Bag (Holds 20)",0010:"Bomb Bag (Holds 30)",0018:"Bomb Bag (Holds 40)",0020:"Goron's Bracelet",0028:"Silver Gauntlets",0030:"Golden Gauntlets" cn Warp Song Location\Minuet of Forest & Serenade of Water cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0000:"Sacred Forest Meadow",0004:"Lake Hylia",0015:"Inside Jabu Jabu's Belly",0018:"Dodongo's Cavern",0068:"Inside The Deku Tree" cn Warp Song Location\Prelude of Light & Nocturne of Shadow cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0003:"Kakariko Windmill",0007:"Bombchu Bowling Alley",000F:"Zelda & Impa Flee",0014:"Kakariko Village",0017:"Ganon,Final Battle",001D:"Top of Ganon's Tower",0028:"Bombchu Shop",002C:"Bazaar",0030:"Happy Mask Shop",0034:"Ganon's Tower",0038:"Ganon's Castle",004C:"Inside Spirit Door",006C:"Burning Castle",0050:"House of Skulltula",0064:"Death Mountain Trail",0068:"Graveyard",0070:"Thieves' Hideout",0074:"Royal Family's Tomb",0078:"Great Fairy Fountain 1",0084:"Forest Temple,Room With Falling Floor",0088:"Great Fairy Fountain 2",0099:"Grotto 01",009D:"Grotto 02",00A4:"Grotto 04",00A8:"Grotto 05",00B3:"Grotto 06",00B0:"Grotto 07",00B4:"Grotto 08",00B8:"Grotto 09",00C3:"Grotto 10",00C0:"Grotto 11",00C4:"Grotto 12",00FC:"Grotto 13",00D3:"Bottom of the Well",00D0:"Lon Lon Ranch Shed",00D3:"Lon Lon Ranch Outside Shed",00D8:"Ice Cavern",00E3:"Outside Cow Pen",00E0:"Lost Woods Bridge",00E4:"Lon Lon Ranch Chicken Room",00E8:"In Front of Deku Tree",00EB:"Spirit Temple Boss",00F1:"Castle Courtyard,In Front of Zelda",00F4:"Temple of Time",00F8:"Gerudo Fortress Jail" cn Warp Song Location\Bolero of Fire cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0003:"Castle Courtyard",000B:"Dodongo's Cavern Boss",0010:"Inside The Deku Tree Boss",0014:"Shadow Temple Boss",0017:"Water Temple Boss",001C:"Ganon's Castle Tower",001F:"Ganon First Battle",0028:"Ganon's Castle Room Before Ganon",002B:"Inside Ganon's Castle Room With Pillar",002F:"Lon Lon Ranch",0033:"Mido's House",0037:"Saria's House",004B:"Bearded Man's House",0040:"Top of Ganon's Castle",0047:"Outside Saria's House",004F:"Dampe's Race",0057:"Kokiri Forest",005B:"Top of Death Mountain",005F:"Fishing Pond",0068:"Inside Ganon's Castle",007F:"Hyrule Castle Gate",00BA:"Top of Ganon's Tower",00C2:"Great Fairy Fountain",00D6:"Lost Woods Goron Entrance",00DA:"Lost Woods River Entrance",00DE:"Lost Woods Bridge Field Entrance",00E3:"Goron City Lost Woods Entrance",00F6:"Death Mountain Crater",00FD:"Ganon's Castle" cn Warp Song Location\Requiem of Spirit cd For this cheat to work,You have to have the Ocarina & Songs. make your choice & Play the song of the cheat name to get where you chose. 80119CCD ???? 0005:"Lake Hylia",0008:"Zora's Domain",0018:"Gerudo Valley",001E:"Lost Woods",0028:"Gerudo Fortress",0030:"Haunted Wasteland",0034:"Ganon's Castle Inside Burning Castle",0038:"Hyrule Castle",003A:"Ganon's Castle",003D:"Death Mountain Trail",004D:"Goron City",0065:"Fire Temple",0069:"Forest Temple",006E:"Shooting Gallery",0079:"Ganon's Castle Inside Burning Castle",007E:"Kakariko Village Entrance",007B:"Zora's River Entrance",0085:"Kokiri Forest Entrance",008A:"Lake Hyrule Entrance",008E:"Gerudo Valley Entrance",0092:"Death Mountain Trail Entrance",0095:"Graveyard Entrance",009E:"Zora's Domain Entrance",00A2:"Zora's Fountain Entrance",00BA:"Goron City Entrance",00BE:"Death Mountain Trail",00C1:"Goron City",00C5:"Lakeside Laboratory",00C9:"Top of Ganon's Castle",00CD:"Hyrule Market (Child Link's)",00CF:"Hyrule Market (Adult Link's)",00F1:"Desert Colossus",00FA:"Lon Lon Ranch Entrance",00FD:"Hyrule Field" cn Nayru's Love is Always cd For this to work On Or off, you have to walk through a Doorway to activate the Change. 81119D00 ???? 0000:"OFF",FFFF:"ON" cn Infinite\Timers\All Other Timers cd This cheat works on all Race Timers not the final Boss and Under Water with iron Boots etc. 8011B9A1 0032 cn Epona\Max Carrots\Lon Lon Raunch cd This is For Practicing,Racing.Warning take this off before jumping the exit fence after winning Epona 801F1A68 0005 801EE508 0005 cn Infinite\Timers\Escape From Gannons Tower cd This cheat works only on The Final Boss. 80119D0D 00B4 cn Beta\Play Beta Quest Worlds cd Put on the code on load up,& then press reset (F1) you will be in Beta Mode,There are no icons, energy bar etc. on the screen.When you press a C-Buttton you can use an object.Here the objects for the C-Buttons:C-left: arrows, C-down: bombs, C-right: Ocarina of Time. There is also no Navi and start menu.When you go to some places the game will freeze or you can't move. D011BB71 0000 80119D4B ???? 0000:"World 01",0001:"World 02",0002:"World 03",0003:"World 04",0004:"World 05",0007:"World 06",0008:"World 07",0016:"World 08" cn Level Select D01C6E35 0000 8111893A ???? 0000:"Inside the Deku Tree",0004:"Dodongo's Cavern",0008:"Gerudo Training Ground",000C:"Below The Phantom Gannon Boss",0010:"Water Temple",0027:"Inside Jabu-Jabu's Belly",002C:"Royal Family's Tomb",0036:"Shoadow Temple",0042:"Lakeside Laboratory",0052:"Temple Of Time",006C:"?" cn Language Select 80119D41 ???? 0000:"English",0001:"German",0002:"French" cn Press L\To Levitate cd Press L To Levitate & Let go to land D011BB11 0020 811D93D0 40CB cn Press L\For Infinite Hover Boots cd Press L For Infinite Hover Boots & Let go to land,This Only works when you have the Boots on D011BB11 0020 811D9BF2 000D cn Instant Step Hoover Boots cd Take off from Anywhere & to go higher just press L Once, this will lift you higher while walking.to come back Down Keep R pressed.Once you have enabled the code press Start & then start again. D011BB11 0020 811D93D0 40CB D011BB11 0000 811D9BF2 000D 801189A8 ???? 0031:"Kokiri Tunic & Hover Boots",0032:"Goron Tunic & Hover Boots",0033:"Zora Tunic & Hover Boots",0034:"Black Tunic & Hover Boots",0035:"White Tunic & Hover Boots",0036:"Yellow Tunic & Hover Boots" cn Beta\Specific things lean cd This code will cause all items on a specific plane to lean. This is helpful for areas in which the plane causes the crash (Ex. Weird Zora's Fountain Beta Quest World 01) 8002397C 0001 cn Beta\Appear in Strange Places (Hold R) cd If you go to an area where Link is immobile or invisible, using the "appear in strange places" code will almost always fix it, but you'll start somewhere outside of the Arena and in air. I recommend using the infinite step Hover boots code already supplied with PJ64 so you can float back into the arena in the event that this happens. D01C681D 0010 81119C9E 0001 cn Beta\Interface always off/on cd If you go to an area where the interface is accessible, this signigfies that you're not in 'beta' mode anymore. Using the "interface always off/on" code, you can stay in 'beta' mode regardless of what happens. This may cause more crashes in SOME areas, but it's rare and is not too severe. If you need to explore a beta area with the interface, "use the interface always on" portion of the code. Don't use the codes as you start the game. If you need the interface on/off at a specific time, start the game, go to the area, activate the code, keep it on until next reset. 80119821 00FF 80119C97 ???? 0000:"Off",0001:"On" cn Language Select 80119D41 ???? 0000:"English",0001:"German",0002:"French" cn Have\Status Heart Containers 801189DC ???? 0030:"On",0000:"Off" crc 60460680-305F0E72-C:50 gn Lode Runner 3-D (E) cn Infinite Lives 81157EAE 0063 cn Access Secret Worlds 81152946 0064 cn Access All Navigation Cards 80157E9B 0005 cn Max & Total Gold 80157E4B 0063 80157E4F 0063 cn Access All In-Game Cheats cd Pause Gameplay To Access 81157E46 000F 81157E56 FFFF crc 0AA0055B-7637DF65-C:50 gn DAFFY DUCK STARRING cn Infinite\Lives 80026DE7 0063 cn Infinite\Health 80026DE3 0004 cn Infinite Time\Basketball Gym 8029F901 0042 cn Infinite Time\Flight Test Range 802BA3A9 0042 cn Infinite Time\Cecil's Flying Toys 802A5575 0042 cn Infinite Time\Slippery Slide 802A7E8D 0042 cn Tennis CPU Can't Score 801D7B4B 0000 cn Infinite\Atoms 80159667 00C8 cn Infinite\Quarks 80159663 00C8 crc 1145443D-11610EDB-C:50 gn Mace - The Dark Age (E) cn Infinite Health Player 1 8008B287 0064 cn Infinite Health Player 2 8008AEFF 0064 cn Extra Characters 8007FA98 0001 cn Ned The Janitor 8013C281 0001 cn Infinite\Time 8113C5BA 0B9E cn Infinite\Time To Choose Character D0137ABE 0001 81137ABE 02A2 cn Infinite\Continues 8015183B 0006 cn One Hit Death\Player 1 D008B287 0064 8008B287 0001 cn One Hit Death\Player 2 D008AEFF 0064 8008AEFF 0001 cn Play As Options\Player 1 8113C6E2 ???? 3334:"Executioner",335C:"Lord Deimos",33C4:"Ragnar",33AC:"Koyasha",33D4:"Taria",33FC:"AL-Rashid",3424:"Takeshi",344C:"Mordoskull",3474:"Xiao Lang",449C:"Namira",358C:"Dregan",353C:"Hellnight",34C4:"Big Guy with spikes and a skull staff",3514:"Monk dude with sword",3564:"Pojo The Chicken",35B4:"War Mech" cn Play As Options\Player 2 8113C6DE ???? 3334:"Executioner",335C:"Lord Deimos",33C4:"Ragnar",33AC:"Koyasha",33D4:"Taria",33FC:"AL-Rashid",3424:"Takeshi",344C:"Mordoskull",3474:"Xiao Lang",449C:"Namira",358C:"Dregan",353C:"Hellnight",34C4:"Big Guy with spikes and a skull staff",3514:"Monk dude with sword",3564:"Pojo The Chicken",35B4:"War Mech" cn Fight With Bunny Slippers On 81138914 0100 crc 62E957D0-7FC15A5D-C:50 gn MarioGolf64 cn Unlock all Characters and Birdy Badges cd Unlocks Metal Mario, Maple, Luigi, Sonny, Wario, Harry, Bowser, Yoshi, Mario and DK 50006C01 0000 801304A4 0001 50000901 0000 80130518 0001 50000901 0000 80130521 0001 cn Wind Speed Select 800BACA1 ???? 0000:"0 MPH",0014:"20 MPH" cn Weather Select 800BACAB ???? 0000:"Never Rains",0001:"Always Rains" cn All Golf Courses Unlocked 80130FED 0001 cn Always On 1st Stroke 801B74F3 0000 cn Infinite Power Shots 801B74F8 0042 crc C3B6DE9D-65D2DE76-C:50 gn Mario Kart 64 (E) (V1.0) cn Infinite Items 8016609D ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Off-Road Tires\Player 1 50000418 0000 810F6C74 0140 cn Off-Road Tires\Player 2 50000418 0000 810F7A4C 0100 cn Off-Road Tires\Player 3 50000418 0000 810F8824 0100 cn Off-Road Tires\Player 4 50000418 0000 810F9644 0100 cn Have Bonus Mode and All Gold Cups 50000402 0000 8018EE50 ???? 0000:"Off",00FF:"On" cn Press GS\For Full Debug Menu cd Press GS at the Press Start Menu to access the Debug Menu 8818EF2F 0002 cn Press L To Levitate\Player 1 D00F6A55 0020 810F6B08 4000 cn Press L To Levitate\Player 2 D00F6A65 0020 810F78E0 4000 cn Press L To Levitate\Player 3 D00F6A75 0020 810F86B8 4000 cn Press L To Levitate\Player 4 D00F6A85 0020 810F9490 4000 crc 2577C7D4-D18FAAAE-C:50 gn Mario Kart 64 (E) (V1.1) cn Infinite Items 80165FBD ???? 000D:"Double Mushroom",0009:"Fake Item Box",000B:"Ghost",000A:"Invincible Star",0008:"Lightning",0001:"Single Banana",0003:"Single Green Shell",000C:"Single Mushroom",0005:"Single Red Shell",000F:"Super Mushroom",0004:"Triple Green Shell",000E:"Triple Mushroom",0006:"Triple Red Shell",0002:"Banana Bunch",0007:"Blue Spiny Shell" cn Have Bonus Mode and All Gold Cups 50000402 0000 8018ED70 ???? 0000:"Off",00FF:"On" cn Off-Road Tires\Player 1 50000418 0000 810F6B94 0140 cn Off-Road Tires\Player 2 50000418 0000 810F796C 0100 cn Off-Road Tires\Player 3 50000418 0000 810F8744 0100 cn Off-Road Tires\Player 4 50000418 0000 810F951C 0100 cn Press GS\For Full Debug Menu cd Press GS at the Press Start Menu to access the Debug Menu 8818EE4F 0002 cn Press L To Levitate\Player 1 D00F6975 0020 810F6A28 4000 cn Press L To Levitate\Player 2 D00F6985 0020 810F7800 4000 cn Press L To Levitate\Player 3 D00F6995 0020 810F85D8 4000 cn Press L To Levitate\Player 4 D00F69A5 0020 810F93B0 4000 crc 9C663069-80F24A80-C:50 gn Mario Party (E) cn Top Left Character\Coin Options cd If you want to have full 255 Coins,1st use the 100 Option then put on 255. this will stop the numbers from changing & spoiling the result. 800FFAA9 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Left Character\Star Options 800FFAAC ???? 0000:"0 Stars",0064:"99 Stars" cn Top Right Character\Coin Options 800FFAD9 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Right Character\Star Options 800FFADC ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Left Character\Coin Options 800FFB09 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Left Character\Star Options 800FFB0C ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Right Character\Coin Options 800FFB39 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Right Character\Star Options 800FFB3C ???? 0000:"0 Stars",0064:"99 Stars" cn Top Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800DDC92 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Top Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800DDCD6 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800DDD1A ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800DDD5E ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Mini Game\Unlimited 99 lives 800FFF58 0063 cn Mini Game\Max 99 Coins 800FFF61 0063 crc C5674160-0F5F453C-C:50 gn Mario Party 3 (E) cn Top Left Character\Coin Options cd If you want to have full 255 Coins,1st use the 100 Option then put on 255. this will stop the numbers from changing & spoiling the result. 810D0F92 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Left Character\Star Options 800D0F96 ???? 0000:"0 Stars",0064:"99 Stars" cn Top Right Character\Coin Options 810D0FCA ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Top Right Character\Star Options 800D0FCE ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Left Character\Coin Options 810D1002 ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Left Character\Star Options 800D1006 ???? 0000:"0 Stars",0064:"99 Stars" cn Lower Right Character\Coin Options 810D103A ???? 0000:"0 Coins",000A:"10 Coins",0064:"100 Coins",00FF:"255 Coins" cn Lower Right Character\Star Options 800D103E ???? 0000:"0 Stars",0064:"99 Stars" cn Top Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDA55 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Top Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDAA1 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Left Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDAED ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" cn Lower Right Character\Dice Always cd With this option you can calculate exactly how many you need to get on the position of your choice. 800CDB39 ???? 0000:"Rolls In Random",0001:"Rolls In 1",0002:"Rolls In 2",0003:"Rolls In 3",0004:"Rolls In 4",0005:"Rolls In 5",0006:"Rolls In 6",0007:"Rolls In 7",0008:"Rolls In 8",0009:"Rolls In 9",000A:"Rolls In 10" crc 839F3AD5-406D15FA-C:50 gn MarioTennis cn Have All\Characters Available 810657A0 FFFF cn Have All\Courts Available 810657A4 FFFF cn Score\Player 1 80152DFA ???? 0000:"0",0001:"15",0002:"30",0003:"40" cn Score\Player 2 80152DFB ???? 0000:"0",0001:"15",0002:"30",0003:"40" crc DED0DD9A-E78225A7-C:50 gn MICKEY USA PAL cn Play As 800D33D1 ???? 0000:"Mickey Mouse",0001:"Daisy Duck",0002:"Goofy",0003:"Pete",0004:"Minnie Mouse",0005:"Donald Duck",0006:"Huey",0007:"Dewey",0008:"Louie",0009:"Lugwig Von Drake" cn Traffic Troubles\Indianapolis\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B4332 0063 cn Traffic Troubles\San Fransisco\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B7602 0063 cn Traffic Troubles\New Mexico\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B5902 0063 cn Traffic Troubles\Grand Canyon\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B8CF2 0063 cn Motor Way Mania\Los Angeles\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B3792 0063 cn Motor Way Mania\Alaska\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B3F22 0063 cn Motor Way Mania\Las Vegas\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B85B2 0063 cn Motor Way Mania\Philadelphia\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B9502 0063 cn Freewayphobia\Dakota\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B2CB2 0063 cn Freewayphobia\Seattle\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B5892 0063 cn Freewayphobia\New York\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B4FB2 0063 cn Freewayphobia\Chicago\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B7AE2 0063 cn Victory Vehicles\Yellowstone\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B2F62 0063 cn Victory Vehicles\Washington DC\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801BD102 0063 cn Victory Vehicles\Everglades\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B56C2 0063 cn Victory Vehicles\Malibu\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B7152 0063 cn Frantic Finale\Hawaii\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B7B12 0063 cn Frantic Finale\Oregon\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B44E2 0063 cn Frantic Finale\Texas\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B4C82 0063 cn Frantic Finale\Colorado\Max Tokens cd Only use one One Max Token Track code of each Level at a time, if you enable all tracks Max Token on that level Or all levels and tracks it will crash. 801B7432 0063 cn Level Select 801AD159 ???? 0000:"Traffic Troubles",0001:"Motor Way Mania",0002:"Freewayphobia",0003:"Vitory Vehicles",0004:"Frantic Finale",0005:"Time Trial",0006:"Practice",0007:"Contest",0008:"Options" cn Difficulty Select 8007C1C0 ???? 0000:"Amateur",0001:"Intermediate",0002:"Professional",0003:"Mirror Mode" cn Unlock Everything cd This will unlock all characters, tracks, mirror mode, all in-game cheats, postcards, pluto's collar and give you all Trophies for every track and difficulties. To have this cheat save to mempak, enable it and then go into the Options Menu and disable the cheat. Go to the Wide-Screen Settings and Change it to Wide-Screen [16.9] and then the B button to get back to Wide-Screen Settings, now go back into Wide-Screen [16.9] and change it back to Normal [4.3].and press the B button until you come back to the main Options Menu.Close the game and load it again to see everything saved to the Mempak and unlocked. 800D3478 008F 800D3479 0094 800D347A 0003 800D347C 0001 800D347F 0080 50000502 0000 800D3480 0009 50000502 0000 800D3481 0024 800D348A 0015 800D348B 007F 800D348C 0001 800D348D 00FF 800D348E 0004 800D348F 0022 cn Always 1st & final time 00:00.00 cd All Levels 50000301 0000 801CE959 0000 cn Traffic Troubles\Indianapolis\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B430B 00FF cn Traffic Troubles\San Fransisco\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B75DB 00FF cn Traffic Troubles\New Mexico\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B58DB 00FF cn Traffic Troubles\Grand Canyon\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B8CCB 00FF cn Motor Way Mania\Los Angeles\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B207B 00FF cn Motor Way Mania\Alaska\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B280B 00FF cn Motor Way Mania\Las Vegas\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B6E9B 00FF cn Motor Way Mania\Philadelphia\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B7DEB 00FF cn Freewayphobia\Dakota\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B159B 00FF cn Freewayphobia\Seattle\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B417B 00FF cn Freewayphobia\New York\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B4A5B 00FF cn Freewayphobia\Chicago\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B758B 00FF cn Victory Vehicles\Yellowstone\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B2A0B 00FF cn Victory Vehicles\Washington DC\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801BCBAB 00FF cn Victory Vehicles\Everglades\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B516B 00FF cn Victory Vehicles\Malibu\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B6BFB 00FF cn Frantic Finale\Hawaii\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801B75BB 00FF cn Frantic Finale\Oregon\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801BABEB 00FF cn Frantic Finale\Texas\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801BB38B 00FF cn Frantic Finale\Colorado\Always Have Shield Shell cd Only use one Always Have Shield Shell code of each Level at a time, if you enable all tracks Always Have Shield Shell on that level Or all levels and tracks it will crash. 801BDB3B 00FF cn Re-name Characters\Mickey\Letter 1 801E39B9 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 2 801E39BA ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 3 801E39BB ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 4 801E39BC ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 5 801E39BD ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Mickey\Letter 6 801E39BE ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 1 801E39C0 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 2 801E39C1 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 3 801E39C2 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 4 801E39C3 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 5 801E39C4 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Minnie\Letter 6 801E39C5 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 1 801E39C7 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 2 801E39C8 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 3 801E39C9 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 4 801E39CA ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 5 801E39CB ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Donald\Letter 6 801E39CC ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 1 801E39CE ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 2 801E39CF ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 3 801E39D0 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 4 801E39D1 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Daisy\Letter 5 801E39D2 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 1 801E39D4 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 2 801E39D5 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 3 801E39D6 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 4 801E39D7 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Goofy\Letter 5 801E39D8 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 1 801E39DA ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 2 801E39DB ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 3 801E39DC ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Pete\Letter 4 801E39DD ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 1 801E39DF ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 2 801E39E0 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 3 801E39E1 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Huey\Letter 4 801E39E2 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 1 801E39E4 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 2 801E39E5 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 3 801E39E6 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 4 801E39E7 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Dewey\Letter 5 801E39E8 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 1 801E39EA ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 2 801E39EB ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 3 801E39EC ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 4 801E39ED ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Louie\Letter 5 801E39EE ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 1 801E39F0 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 2 801E39F1 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 3 801E39F2 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 4 801E39F3 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 5 801E39F4 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" cn Re-name Characters\Ludwig\Letter 6 801E39F5 ???? 0000:"",0020:"",0021:"!",0022:"\"",0023:"#",0024:"",0025:"%",0026:"&",0027:"'",0028:"(",0029:")",002A:"*",002B:"+",002C:"",002D:"-",002E:".",002F:"/",0030:"0",0031:"1",0032:"2",0033:"3",0034:"4",0035:"5",0036:"6",0037:"7",0038:"8",0039:"9",003A:":",003B:";",003C:"<" crc 2A49018D-D0034A02-C:50 gn Micro Machines 64 Turbo (E) cn Always 1st 810BB1F8 0100 cn One Lap To Race 810B88DE 0101 cn Infinite 255 Lives 800BB1C2 00FF cn Access All Tracks 810B88DA 0001 cn Always Win Head 2 Head 810BD590 0008 cn Always Turbo Level 1 cd In Easy Mode 810B4070 3100 810BBD30 0000 crc 418BDA98-248A0F58-C:50 gn Mischief Makers cn Marina\Infinite Health 810E1120 0BB8 cn Teran\Infinite Health 810E5DA0 03E8 cn Infinite Max Red Gems 81169C66 25C2 cn All Stages & Chapters Unlocked 80163648 003B cn All 52 Gold Gems Collected 80163640 0003 80163641 007E 80163642 00FF 80163643 00EF 80163644 00FF 80163645 007F 80163646 00FF 80163647 00FC cn Marina\Press A To Levitate D0128BF4 0080 800E1132 0091 cn Teran\Press A To Levitate D0128BF4 0080 800E5DB2 0091 cn Infinite Time to Watch Ending 800E6613 0063 crc 2256ECDA-71AB1B9C-C:50 gn MISSION IMPOSSIBLE cn Invincibility 810864C4 0101 cn Infinite\Ammo All Guns 50000610 0000 800A9097 00FF cn Infinite\Health 810864C2 FFFF cn Access All Levels 8008AA56 0001 8008AD3A 0001 8008A862 0001 8008A876 0001 8008A88A 0001 8008A89E 0001 8008A8B2 0001 8008A8C6 0011 8008A8DA 0021 8008AD4E 0001 8008A916 0011 8008A92A 0041 8008A93E 0021 8008A966 0001 8008A98E 0001 8008AD62 0001 8008A9DE 0001 8008A9F2 0011 8008AA06 0021 8008AD76 0001 8008A7D6 0001 8008A7EA 0001 8008A812 0001 cn Freeze All Timers 81093F50 0063 81093F52 0063 81093F54 0063 cn Weapon Select 800A90B5 ???? 800A90C5 ???? 800A90D5 ???? 0000:"9MM Hi Power",0001:"Silenced Pistol",0002:"Uzi",0003:"Fists",0032:"Gas Spray",0036:"Blow Torch",001F:"Fire Extinguisher",0024:"Spray Paint",0027:"Electrostunner",000B:"Blow Dart Gun",000C:"Dart Hand Gun",002D:"Mini Rocket Launcher" cn Walk Through Walls & Objects cd This will allow you to pass through anything & even walk on water.if you amerge somewhere in the ground just press the A button. 80094105 ???? 0080:"On",0000:"Off" crc 73036F3B-CE0D69E9-C:50 gn Mortal Kombat 4 (E) cn Unlimited Energy\Player 1 810FE208 0001 810FE20A 0000 cn Unlimited Energy\Player 2 81127084 0001 81127086 0000 cn Infinite Run\Player 1 811050FC 0001 811050FE 0000 cn Infinite Run\Player 2 811051B0 0001 811051B2 0000 cn Play As\Player 1 800FE3C3 ???? 0000:"Scorpion",0001:"Raiden",0002:"Sonya",0003:"Liu Kang",0004:"Sub-Zero",0005:"Fujin",0006:"Shinnok",0007:"Reiko",0008:"Quan Chi",0009:"Tanya",000A:"Reptile",000B:"Kai",000C:"Jarek",000D:"Jax",000E:"Johnny Cage",000F:"Goro",0011:"Noob Saibot" cn Play As\Player 2 80126FBF ???? 0000:"Scorpion",0001:"Raiden",0002:"Sonya",0003:"Liu Kang",0004:"Sub-Zero",0005:"Fujin",0006:"Shinnok",0007:"Reiko",0008:"Quan Chi",0009:"Tanya",000A:"Reptile",000B:"Kai",000C:"Jarek",000D:"Jax",000E:"Johnny Cage",000F:"Goro",0011:"Noob Saibot" cn Choose A Costume\Player 1 8104A612 ???? 0000:"Normal",0001:"First",0002:"Second",0003:"Third" cn Choose A Costume\Player 2 8104A616 ???? 0000:"Normal",0001:"First",0002:"Second",0003:"Third" cn Infinite Time 8110524A 0063 cn Enable Restart Match option 800494BB 0002 crc 8C3D1192-BEF172E1-C:50 gn Mortal Kombat Trilogy (E) cn Unlimited Energy\Player 1 801698AD 00A6 cn Unlimited Energy\Player 2 80169B81 00A6 cn Aggressor Energy Bar\Player 1 80169941 0030 cn Aggressor Energy Bar\Player 2 80169943 0030 cn Infinite Time 8114C2FC 000A cn Unlock Secret 80169F41 0004 cn Infinite Run\Player 1 811698B4 0030 cn Play As\Player 1 8016989D ???? 0000:"Kano",0001:"Sonya",0002:"Jax",0003:"Nightwolf",0004:"Cage",0005:"Stryker",0006:"Sindel",0007:"Sektor",0008:"Cyrax",0009:"Kung Lao",000A:"Kabal",000B:"Sheeva",000C:"Shang Tsung",000D:"Liu Kang",000E:"Smoke",000F:"Kitana",0010:"Jade",0011:"Mileena",0012:"Scorpion",0013:"Reptile",0014:"Ermac",0015:"Sub-Zero",0016:"Human Smoke",0017:"Noob Saibot",0018:"Rayden",0019:"Baraka",001A:"Rain",001B:"Khameleon" cn Infinite Run\Player 2 81169B88 0030 cn Play As\Player 2 80169B41 ???? 0000:"Kano",0001:"Sonya",0002:"Jax",0003:"Nightwolf",0004:"Cage",0005:"Stryker",0006:"Sindel",0007:"Sektor",0008:"Cyrax",0009:"Kung Lao",000A:"Kabal",000B:"Sheeva",000C:"Shang Tsung",000D:"Liu Kang",000E:"Smoke",000F:"Kitana",0010:"Jade",0011:"Mileena",0012:"Scorpion",0013:"Reptile",0014:"Ermac",0015:"Sub-Zero",0016:"Human Smoke",0017:"Noob Saibot",0018:"Rayden",0019:"Baraka",001A:"Rain",001B:"Khameleon" cn Pick Your Kombat Zone 812575A4 ???? 0000:"Subway",0001:"Street",0002:"Courtyard",0003:"Pit",0004:"Kahn's Tower",0005:"Bridge",0006:"Soul Chamber",0007:"Bell Tower",0008:"Kombat Temple",0009:"Graveyard",000A:"Pit 3",000B:"River Kombat",000C:"Scorpion's Lair",000D:"Kahn's Kave",000E:"Jade's Desert",000F:"Lost Bridge",0010:"Hidden Portal",0011:"Dead Pool",0012:"Wasteland",0013:"Rooftop",0014:"Armory",0015:"Living Forest",0016:"Tower",0017:"Portal",0018:"Lair",0019:"Tomb",001A:"Pit 2",001B:"Star Bridge",001C:"Pit Bottom" cn Max Aggressor\Player 1 cd Press L Button To Activate D02B5285 0020 811698D4 5100 D02B5285 0020 811698DC 5100 cn Max Aggressor\Player 2 cd Press L Button To Activate D02B528D 0020 811698D6 5100 D02B528D 0020 811698DE 5100 crc B8F0BD03-4479189E-C:50 gn MRC - Multi Racing Championship (E) cn Always 1st 800A9107 0000 cn Infinite Time 8009498F 003C cn Access all Gold Trophies cd Championshp & Match Mode 50000602 0000 810A9078 0000 cn Access All Tracks In Match Mode 50000602 0000 810A9080 0001 crc F5360FBE-2BF1691D-C:50 gn MYSTICAL NINJA cn Infinite\Health 8015D2E7 0028 cn Infinite\Lives 8015D2EF 000A cn Infinite\Ryo 8015D2EA 0010 cn Have\Chain Pipe 8015D3BF 0002 cn Have\Medal of Flames 8015D3DF 0001 cn Have\Ebisumaru 8015D3A3 0001 cn Have\Meat Saw Hammer 8015D3C0 0001 cn Have\Sasuke Character 8015D3A4 0001 cn Have\Fire Cracker Bomb 8015D3C4 0001 cn Have\Kunai of Severe Cold 8015D3D4 0001 cn Have\Yae Character 8015D3AB 0001 cn Have\Bazooka 8015D3CB 0001 cn Have\Flute 8015D3DB 0001 cn Have\Magic Mermaid 8015D3FB 0001 cn Have\Magic Sudden Impact 8015D3EC 0001 cn Have\Magic Mini Ebisu 8015D3F2 0001 cn Have\Magic Flying 8015D3F4 0001 cn Have\Shell 8015D3FC 0001 cn Have\Brown Item 8015D402 0001 cn Have\Brown Round Item 8015D40F 0001 cn Have\Gold Key 8015D412 0001 cn Have\Blue Sausage 8015D417 0001 cn Have\Pink Item 8015D41B 0001 cn Have\Gold Item 8015D41C 0001 cn Have\Blue Item 8015D422 0001 cn Access\Japanese Sombrero cd Use only one of these codes at a time! 8015D2F7 0001 cn Access\Metal Helmet cd Use only one of these codes at a time! 8015D2F7 0002 cn Access\Gold Helmet cd Use only one of these codes at a time! 8015D2F7 0003 cn Access\Infinite Health cd Use only one of these codes at a time! 802F706A 0999 cn Access\Infy Ryo cd Use only one of these codes at a time! 802F7667 0999 cn Access\Always have Big Laser cd Use only one of these codes at a time! 802F706F FFFF cn Access\Infinite Ryo Impact Running cd Use only one of these codes at a time! 812F70EA 270F cn Access\Infinite Ryo Impact Fighting cd Use only one of these codes at a time! 812F7066 0005 cn Access\Enemy Health Modifer attach Activator cd Use only one of these codes at a time! 812F7062 03E8 cn Access\Infinite Impact Oil cd Use only one of these codes at a time! 812F706A 0154 cn Access\Full Energy for Lazer cd Use only one of these codes at a time! 812F706E 0064 cn Access\Mystical Ninja Skating team 8120D620 4E20 8120DEF4 4E20 8116AE78 4E20 cn Access\Move Lock 8116AE6A 0000 8120D84A 0000 cn Access\Skating Team V2 8120D620 4E20 8120DEF4 4E20 8116AE78 4E20 8116AE6A 0001 8120D84A 0001 cn Keep Blue Fish 8015D303 0003 50000404 0000 8015D2F3 0003 crc 7F9345D3-841ECADE-C:50 gn Mystical Ninja 2 Starring Goemon (E) cn Play As\Player 1 80088E02 ???? 0000:"Goemon",0001:"Ebisumaru",0002:"Sasuke",0003:"Yae" cn Unlimited Gate Opener Things 80088EC6 0099 cn Unlimited Health\Player 1 80088ED4 0004 cn Unlimited Shield\Player 1 80088ED5 0004 8015D3C4 0001 cn Always Have Most Powerful Weapon 80088ED9 0003 crc AE4992C9-9253B253-C:50 gn NASCAR 99 (E) cn Laps To Race 81044B7E ???? 0001:"1 Lap",0002:"2 Laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7Laps",0008:"8 Laps",0009:"9 Laps" cn Access All Secret NASCAR Legends cd This will give you access to,Alan Kulwicki,Cale Yarborough,Bobby Allison,Davey Allison,Richard Petty,Benny Parsons 50000602 0000 810DF400 0101 crc 29CE7692-71C58579-C:50 gn NHL Breakaway 98 (E) cn Activate Cheat Menu 80053F78 0001 cn Home Team Scores 8012BC2C ???? 0000:"No Score",00FF:"Max Score" cn Away Team Score 8012BC2D ???? 0000:"No Score",00FF:"Max Score" crc 8A97A197-272DF6C1-C:50 gn Nuclear Strike 64 (E) cn Level & Scenario Select 800ACE5C 000B cn Invincibility cd Makes you also fly without any fuel 800ADB64 0001 cn Double MPG 800ADB69 0001 cn No Quad Damage 800ADB6B 0001 cn infinite Ammo For All Guns 800ADB65 0001 cn Infinite Attempts 800ADB66 0001 crc E86415A6-98395B53-C:50 gn O.D.T (Or Die Trying) (E) (M5) (Unreleased Final) cn Play As Select 800FCEC5 ???? 0000:"Ike Hawkings (Corporal)",0001:"Sophia Hawkings (Stowaway)",0002:"Julia Chase (Cartographer)",0003:"Karma (The Ex-Deviant)",0004:"Max Havok (Chief Enginer)",0005:"Solaar (Archbishop)",0006:"Mr Bodybolt (7th Passenger)" cn Infinite Max\999 Lives 810C8CF8 03E8 cn Infinite Max\Health 800C8AD9 0066 cn Infinite Max\Light Ammo 800C8CAB 0066 cn Infinite Max\Fire Ammo 800C8CB3 0066 cn Infinite Max\Ionic Ammo 800C8CBB 0066 cn Infinite Max\Fusion Ammo 800C8CC3 0066 cn Infinite Max\Mana 800C8CFF 0066 cn Have\All Magic 800CEB48 0010 800CEB4D 0000 800CEB57 0001 800CEB61 0002 800CEB6B 0003 800CEB75 0005 800CEB7F 0006 800CEB89 0008 800CEB93 0009 800CEB9D 000B 800CEBA7 000E 800CEBB1 000F 800CEBBB 0010 800CEBC5 0011 800CEBCF 000A 800CEBD9 000C 800CEBE3 000D cn Have\Magic On Level 4 810C8CDD FFFF 810C8CDE FFFF 810C8CDF FFFF 810C8CE0 FFFF 810C8CE1 FFFF 810C8CE2 FFFF cn Have\Weapons On Max Upgrade 800C8CAC 0009 800C8CB4 0009 800C8CBC 0009 800C8CC4 0009 cn Have\Max Armour Level 800C8D00 0064 cn Have\Max Spirit Level 800C8D04 0064 cn Have\Max Weapon Level 800C8D02 0064 cn Have\Max Experience Level 800C8CFC 00FF cn Infinite Air Under Water 800C8BE4 0069 cn Press A For Bionic Jump cd This will make you jump to a great height D00C8BCA 0080 810C8AE8 ???? 0250:"Medium Jump",0800:"Max Jump" crc 812289D0-C2E53296-C:50 gn Off Road Challenge (E) cn 1 Player\Always Place 1st 80103CD7 0000 cn Multi and 1 Player\Infinite Gent Turbos\Player 1 cd Can be used in 1 Player and Multiplayer Modes for Player 1 81103F3A 02F4 cn 1 Player\Max\Acceleration 8012C51F 000A cn 1 Player\Max\Shocks 8012C527 000A cn 1 Player\Max\Speed 8012C523 000A cn 1 Player\Max\Tires 8012C52B 000A cn Multi and 1 Player\Max Crash Helmets\Player 1 cd Can be used in 1 Player and Multiplayer Modes for Player 1 80103F33 0064 cn Multi and 1 Player\Infinite Gent Turbos\Player 2 cd Multiplayer Mode Only for Player 2 8110422E 02F4 cn Multi and 1 Player\Max Crash Helmets\Player 2 cd Multiplayer Mode Only for Player 2 80104227 0064 crc D5898CAF-6007B65B-C:50 gn OPERATION WINBACK cn Infinite\Health 80179F8B 0064 cn Infinite\Ammo and No Reloads 80157C9B 0078 80157C94 0078 80157C90 0063 80179F6F 001E 80157C91 0063 80179F83 0008 cn C4 Explosives cd Slot 1 80157C93 0001 cn Flash Light cd Slot 2 80157C95 0001 cn C4 Detector cd Slot 3 80157C98 0001 cn Key cd Slot 2 80157C99 0001 cn Card Key cd Slot 3 80157C9A 0001 cn Max Power Mode 8015C8E7 0001 cn All Multiplayer Characters 8015C8E1 000F 8015C8E2 00FF 8015C8E3 00FF cn Walk Through Walls/Objects cd Press Z Button And Joystick Forward Dont Stand Too Close To Wall/Object D0139BC4 0020 8117964C 43C7 cn Weapon modifier 80179F78 ???? 0000:"Handgun",0001:"Submachine gun",0002:"Shotgun",0003:"Rocket launcher",0014:"Handgun w/ silencer" cn Sudden death & trial modes unlocked 8015C8E0 00A0 cn Time is always 00:20:38 8010D342 0078 crc AC976B38-C3A9C97A-C:50 gn Paperboy 64 (E) cn Level Select cd Also accesses All Bonus Levels 8006A6A7 0001 cn Invincibility 81268D1A 0001 cn Infinite Newspapers 81268D12 0001 cn Big Newspapers 81268D5A 0001 cn Throw Newspapers Forwards 81268D46 0001 cn Throw Newspapers Backwards 81268D4A 0001 cn Turbo Mode 81268D36 0001 cn Super Jump Springs 81268D3A 0001 cn Rocket Boosters 81268D3E 0001 cn 99 Total Houses 8106A61A 0063 crc 19AB29AF-C71BCD28-C:50 gn PAPER MARIO cn Infinite & Max HP + FP cd Do not enable this code before you have made a save, when a new game is started up. 50000601 0000 8010DD91 0063 cn Access\All Star Spirits cd Disable this code as soon as you have reached level 8, or everything will be removed again 8110E01E 0007 cn Access\Max Star Energy 8010E01E 0007 cn Access\Infinite Star Spirits 8010E020 0007 cn Access\Infinite Coins 8110DD9C 03E7 cn Access\Max Star Points cd You will level up, everytime you get a Star point 8010DDA0 0063 cn Access\Max Star Pieces 8010DD9F 0063 cn Access\Max Badge Points 8010DD98 ???? 003C:"60 Badge Points",007F:"127 Badge Points" cn Access\Level 99 8010DD99 0063 cn Access\all members in your party 50000C08 0000 8010DDAC 0001 cn Access\Ultra Rank cd This will give you Goombario,Kooper,Bombette,Parakarry,Bow Watt, Sushie & Lakilester 50000C08 0000 8010DDAD 0002 50000C08 0000 8010DDED 0002 cn Press L Button For Moon Jump D0071337 0020 8010DAF4 0043 crc C83CEB83-FDC56219-C:50 gn Penny Racers (E) cn Super Speed cd This is Turbo fast,So to slow it down a little more keep the B button pressed down 81228FA8 4800 cn Always 1st 8022CC16 0001 cn Class Select cd This code is useful because you can play Class AA without having to beat a level!& then once any edit is done while the game is running 8021C297 ???? 0000:"Class C",0001:"Class B",0003:"Class AA",0004:"1 Play",0005:"2 Play",0006:"3 Play",0007:"4 Play" crc E4B08007-A602FF33-C:50 gn Perfect Dark (E) cn Have All\Weapons\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 802037F0 0007 801EA7F0 0007 801D17F0 0007 cn Infinite\Ammo\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80202F7F 00FF 801E9F7F 00FF 801D0F7F 00FF 802027DB 00FF 801E97DB 00FF 801D07DB 00FF cn Infinite\Health\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 8120205C 3F80 811E905C 3F80 811D005C 3F80 cn Infinite\Shield\Player 1 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 81202070 3F80 811E9070 3F80 811D0070 3F80 cn Have All\Weapons\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80205460 0007 801EC460 0007 801D3460 0007 cn Infinite\Ammo\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 80204BEF 00FF 801EBBEF 00FF 801D2BEF 00FF 8020444B 00FF 801EB44B 00FF 801D244B 00FF cn Infinite\Health\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 81203CCC 3F80 811EACCC 3F80 811D1CCC 3F80 cn Infinite\Shield\Player 2 cd This code is for all Low/High Res Solo & Multi-Player Level ;) Enjoy 81203CE0 3F80 811EACE0 3F80 811D1CE0 3F80 cn Have All\Levels Complete & All Challenges cd Have all levels Complete on Solo Missions, & Acces all Challenges & CO-OP Levels 50003C02 0000 800A27C1 0001 50001E1A 0000 80088A0D 0001 50001E1A 0000 80088A0E 0001 50001E1A 0000 80088A0F 0001 50001E1A 0000 80088A10 0001 cn Carrington Institute\Have 999 points in Firing Range 810AD712 03E7 cn Carrington Institute\Have Infinite time in Firing Range 810AD70E 004D cn Carrington Institute\Have 255 targets destroyed 810AD714 00FF cn Single & Co-Op\Press B To Levitate\Player 1 cd To activate the moon jump you must Hold B while in the air. You can get in the air by going down steps, or hills or by going off the edge of something D00980C4 0040 81202000 40F2 D00980C4 0040 80201FB3 0000 D00980C4 0040 811E9000 40F2 D00980C4 0040 801E8FB3 0000 D00980C4 0040 811D0000 40F2 D00980C4 0040 801CFFB3 0000 crc 1AA05AD5-46F52D80-C:50 gn Pilot Wings64 cn Infinite Fuel\Gyrocopter 80366989 0081 cn Infinite Fuel\Rocket Belt 803669A9 0081 cn Time Always 00'00'10 cd This Cheat code is for All Events 803668B8 0001 cn Choose Vehicle cd Make your Choice & then Press GS To Activate,But do not use with any other Press GS Cheat Codes. 88366807 ???? 0000:"Hang Glider",0001:"Rocket Belt",0002:"Gyrocopter",0003:"Cannonball",0004:"Skydiving",0005:"Jumble Hopper",0006:"Birdman" cn [Perfect Score] (All Class & Level's) cd To make these codes save to Game-Pak; just pick a level and lose, choose Next then Quit. Enable Disable Perfect Score then save and disable before using the Extra Games Perfect Score Cheat. 50000330 0000 803683ED 0064 50000330 0000 80368A81 0064 50000330 0000 80368BD1 0064 50000330 0000 80369115 0064 50000330 0000 80369265 0064 50000330 0000 803693B5 0064 50000330 0000 803697A9 0064 50000330 0000 803698F9 0064 50000330 0000 80369A49 0064 cn Infinite Photos 813545EE 0000 cn [Perfect Score] Extra Games (All Class & Level's) cd To make these codes save to Game-Pak; just pick a level and lose, choose Next then Quit. Enable Disable Perfect Score then save and disable before using the Extra Games Perfect Score Cheat. 8036847D 0019 803685CD 0019 8036871D 0019 8036886D 0019 803684AD 0064 803684DD 0064 80368B11 0019 80368C61 0019 80368DB1 0019 80368F01 0019 80368B41 0064 80368B71 0064 803691A5 0019 803692F5 0019 80369445 0019 80369595 0019 803691D5 0064 80369205 0064 cn Music Volume Select 80250FA4 ???? 0000:"No Music",003F:"Default Volume",0080:"Max Volume" crc 4FF5976F-ACF559D8-C:50 gn POKEMON SNAP cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C2712 0006 crc 84077275-57315B9C-C:50 gn Pokemon Stadium (E) cn Infinite Health\Stadium\Free Battle 80287D79 0064 cn Infinite Health\Stadium\Poke Cup 80285399 0064 cn Infinite Health\Stadium\Pica Cup 80284659 0064 cn Infinite Health\Stadium\Prime Cup 80285FE9 0064 cn Infinite Health\Stadium\Petit Cup 80286C29 0064 cn Infinite Health\Stadium\Mewto 802825B9 0064 cn Gym Leader Castle\Elite Four & Rival 80286859 00A1 cn Gym Leader Castle\Brock 80287539 00A1 cn Gym Leader Castle\Misty 80287E79 00A1 cn Gym Leader Castle\Surge 80286BD9 00A1 cn Gym Leader Castle\Erika 80286BA9 00A1 cn Gym Leader Castle\Koga 80287519 00A1 cn Gym Leader Castle\Sabrina 802870A9 00A1 cn Gym Leader Castle\Blaine 80286B69 00A1 cn Gym Leader Castle\Giovani 80287169 00A1 cn Infinite Health\Player 1 810AE686 03E7 810AE6AA 03E7 810AE6DA 03E7 810AE6FE 03E7 cn All Pokemon Level 100\Player 1 50000654 0000 800AE654 0064 cn Infinite Attacks All Pokemon\Player 1 50000654 0000 810AE650 6363 50000654 0000 810AE652 6363 cn Infinite Attacks All Pokemon\Player 2 50000654 0000 810AE86C FFFF 50000654 0000 810AE86E FFFF cn Infinite Attacks All Pokemon\Player 3 50000654 0000 810AE86C FFFF 50000654 0000 810AE86E FFFF cn Infinite Attacks All Pokemon\Player 4 50000654 0000 810AEA88 FFFF 50000654 0000 810AEA8A FFFF cn Game Difficulty D312FC40 FD70 D312FC40 A528 8112FC40 ???? 0000:"Hard",0001:"Normal",0002:"Easy",000F:"Extra Hard" cn Catch\Mew on GB Tower 80171E17 0015 cn Catch\Mewtwo on GB Tower 80171E17 0083 cn Infinite coins for coin case 801723E3 0099 cn Infinite cash 81172186 9999 cn Pokemon beach stop code D00488A1 0020 80202BB5 0001 cn Clefairy Says\Infinite Health\Player 1 8118F438 0064 cn Clefairy Says\Extended Life Bar\Player 1 8118F43A 0049 cn Clefairy Says\Infinite Health\Player 2 8118F5F8 0064 cn Clefairy Says\Extended Life Bar\Player 2 8118F5FA 0049 cn Clefairy Says\Infinite Health\Player 3 8118F7B8 0064 cn Clefairy Says\Extended Life Bar\Player 3 8118F7BA 0049 cn Clefairy Says\Infinite Health\Player 4 8118F978 0064 cn Clefairy Says\Extended Life Bar\Player 4 8118F97A 0049 cn Rock Harden\Infinite Armour\Player 1 81193B78 0190 cn Rock Harden\Infinite Armour\Player 2 81193E2C 0190 cn Rock Harden\Infinite Armour\Player 3 811940E0 0190 cn Rock Harden\Infinite Armour\Player 4 81194394 0190 cn Infinite Health against Mew Two 810AE632 FFFF 812823E8 FFFF cn All Pokmon Have Max Hp 81285AE8 0096 crc 2952369C-B6E4C3A8-C:50 gn Pokemon Stadium 2 (E) cn Infinite Health Stadium & Gym Leader Castle 801DD22D 0030 cn Mini Games\Player 1\Gutsy Golbat has 99 Hearts D017711F 0001 8017711F 0063 cn Mini Games\Player 2\Gutsy Golbat has 99 hearts D017714B 0001 8017714B 0063 cn Mini Games\Player 3\Gutsy Golbat has 99 hearts D0177177 0001 80177177 0063 cn Mini Games\Player 4\Gutsy Golbat has 99 hearts D01771A3 0001 801771A3 0063 cn Mini Games\Player 1\Clear Cut Challenge gets perfect score 801744C3 0063 cn Mini Games\Player 1\Topsy Turvy cd Immediatly wins D01769E7 0001 801769E7 0005 cn Mini Games\Player 1\Egg Emergency perfect score 80191C3F 0064 cn Mini Games\Player 1\Furret Frolic Perfect Score 801E9623 0063 cn Mini Games\Player 1\Streaming Stampede Perfect Score 8018138B 0063 cn Mini Games\Player 1\Delibird Delivery Perfect Score 801AC2CC 0063 cn Mini Games\Player 1\Roll Out Rampage Always in 1st Place 80103179 0001 crc 16931D74-65DC6D34-C:50 gn Quake 64 (E) cn Infinite\Ammo 50000402 0000 8016426D 0064 50000402 0000 8116426C 03E7 cn Have\All Weapons 8016422B 007F cn Debug Mode 8006C4E3 0001 cn Have\All Keys 80164229 000F cn Infinite\Armor 81164184 42C8 cn Infinite\Health 81164170 42C8 cn Infinite\Bio Suit 811641C0 42C8 cn Have\Quad Damage 811641BC 42C8 cn Have\Ring of Shadows 81164228 ???? 42C8:"On",0000:"Off" cn Rapid Fire D00CB220 0020 801641AD 0001 cn Multi\Infinite Health\Player 1 81166AD0 42C8 cn Multi\Infinite Armor\Player 1 81166AE4 42C8 cn Multi\Infinite Bio Suit\Player 1 81166B20 42C8 cn Multi\Have All Weapons\Player 1 80166B8B 007F cn Multi\Infinite Ammo\Player 1 50000402 0000 81166BCC 03E7 cn Multi\Infinite Health\Player 2 81166DA0 42C8 cn Multi\Infinite Armor\Player 2 81166DB4 42C8 cn Multi\Infinite Bio Suit\Player 2 81166DF0 42C8 cn Multi\Have All Weapons\Player 2 80166E5B 007F cn Multi\Infinite Ammo\Player 2 50000402 0000 81166E9C 03E7 crc 7433D9D7-2C4322D0-C:50 gn QUAKE II cn Invincible 8002E618 0000 cn Status Bar Always On 8008E4CF 0001 cn Have All Weapons and Infinite Max Ammo\Level 01 50000904 0000 802A46AB 0001 50000604 0000 812A46CE 02F4 cn Have All Weapons and Infinite Max Ammo\Level 02 50000904 0000 8028A47B 0001 50000604 0000 8128A49E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 03 50000904 0000 8027223B 0001 50000604 0000 8127225E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 04 50000904 0000 8026A70B 0001 50000604 0000 8126A72E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 05 50000904 0000 8028812B 0001 50000604 0000 8128814E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 06 50000904 0000 8027DA0B 0001 50000604 0000 8127DA2E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 07 50000904 0000 802811CB 0001 50000604 0000 812811EE 02F4 cn Have All Weapons and Infinite Max Ammo\Level 08 50000904 0000 8027C45B 0001 50000604 0000 8127C47E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 09 50000904 0000 80247C7B 0001 50000604 0000 81247C9E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 10 50000904 0000 80276C4B 0001 50000604 0000 81276C6E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 11 50000904 0000 80278AFB 0001 50000604 0000 81278B1E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 12 50000904 0000 8028F69B 0001 50000604 0000 8128F6BE 02F4 cn Have All Weapons and Infinite Max Ammo\Level 13 50000904 0000 80278A4B 0001 50000604 0000 81278A6E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 14 50000904 0000 802807DB 0001 50000604 0000 812807FE 02F4 cn Have All Weapons and Infinite Max Ammo\Level 15 50000904 0000 8027636B 0001 50000604 0000 8127638E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 16 50000904 0000 8028B7FB 0001 50000604 0000 8128B81E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 17 50000904 0000 8027278B 0001 50000604 0000 812727AE 02F4 cn Have All Weapons and Infinite Max Ammo\Level 18 50000904 0000 8026594B 0001 50000604 0000 8126596E 02F4 cn Have All Weapons and Infinite Max Ammo\Level 19 50000904 0000 8024A28B 0001 50000604 0000 8124A2AE 02F4 crc 9B500E8E-E90550B3-C:50 gn Resident Evil 2 (E) cn Infinite Health 810DDE22 00C8 cn Condition Always Fine 810DDEE4 0000 cn Infinite Time 800E57BF 0010 cn Access ChestAnywhere cd Press L Button + Start D1014FA4 0020 81122598 0100 cn Access Quick Save cd Press Z Button + B Button D1014FA4 6000 810E5428 8007 D1014FA4 6000 810E542A 0E30 cn Access All Items Chest cd Disable After First Save 50003504 0100 810E59F4 2FFE cn Infinite Ammo 811224AE 03E7 cn Access Ink Ribbons cd Disable After First Save 810E59C8 1EFF cn Access Weapons\Grenadelauncher & Acid Rounds cd Disable After First Save 810E59CC 0BFF cn Access Weapons\Bow Gun cd Disable After First Save 810E59D0 0CFF cn Access Weapons\Rocket Launcher cd Disable After First Save 810E59D4 11FF cn Access Weapons\Gatling Gun cd Disable After First Save 810E59D8 12FF cn Number Of Saves Will Always Be 0 810E5650 0000 cn Have 2 Extra Slots In Inventory D10E584E 0000 810E584E 0001 cn Play As 810DDC38 ???? 0080:"Leon Original",0180:"Claire Original",0280:"Leon Original",0380:"Claire Original",0480:"Leon Wounded",0580:"Claire without jacket",0680:"Leon Wounded",0780:"Claire without jacket",0880:"Leon as Stars",0980:"Claire as Biker",0A80:"Leon as Biker",0B80:"Claires body Leons outfit",0C80:"Hunk (can crash the game)",0D80:"To Fu",0E80:"Ada (can crash the game)",0F80:"Cheryl" cn Play Extra Mission 810DDBEE ???? 0048:"The 4th Survior",0049:"To-Fu" cn Max Item Modifier\Slot 01 800E59C8 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59C9 00FF cn Max Item Modifier\Slot 02 800E59CC ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59CD 00FF cn Max Item Modifier\Slot 03 800E59D0 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59D1 00FF cn Max Item Modifier\Slot 04 800E59D4 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59D5 00FF cn Max Item Modifier\Slot 05 800E59D8 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59D9 00FF cn Max Item Modifier\Slot 06 800E59DC ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59DD 00FF cn Max Item Modifier\Slot 07 800E59E0 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59E1 00FF cn Max Item Modifier\Slot 08 800E59E4 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59E5 00FF cn Max Item Modifier\Slot 09 800E59E8 ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59E9 00FF cn Max Item Modifier\Slot 10 800E59EC ???? 0000:"Nothing",0001:"Knife Hunk",0002:"Handgun Hunk",0003:"Handgun Different Ada",0004:"Custom Handgun Hunk",0005:"Magnum Hunk",0006:"Custom Magnum Hunk",0007:"Shotgun Hunk",0008:"Custom Shotgun Hunk",0009:"Grenade Launcher Claire",000A:"Grenade Launcher (Flame Rounds) Claire",000B:"Grenade Launcher (Acid Rounds) Claire",000C:"Bowgun Claire",000D:"Colt S.A.A. Claire",000E:"Spark Shot Claire",000F:"Sub Machine Gun Leon",0010:"Flamethrower Leon",0011:"Rocket Launcher Claire",0012:"Gatling Gun Claire",0013:"Machine Gun ???",0014:"Handgun Bullets",0015:"Shotgun Shells",0016:"Magnum Bullets",0017:"Fuel",0018:"Grenade Rounds",0019:"Flame Rounds",001A:"Acid Rounds",001B:"Machine Gun Bullets",001C:"S. Shot Bullets",001D:"Bow Gun Bolts",001E:"Ink Ribbon",001F:"Small Key",0020:"Hand Gun Parts",0021:"Magnum Parts",0022:"Shotgun Parts",0023:"First Aid Spray",0024:"Chemical FR-W09",0025:"Chemical AC-W24",0026:"Green Herb",0027:"Red Herb",0028:"Blue Herb",0029:"Mixed Herb (Green)",002A:"Mixed Herb (Red&Green)",002B:"Mixed Herb (Blue&Green)",002C:"Mixed Herb (?)",002D:"Mixed Herb (?)",002E:"Mixed Herb (?)",002F:"Lighter",0030:"Lock Pick",0031:"Picture",0032:"Valve Handle",0033:"Red Jewel",0034:"Red Card Key",0035:"Blue Card Key",0036:"Serpent Stone",0037:"Jaguar Stone",0038:"Blue Stone",0039:"Blue Stone (?)",003A:"Eagle Stone",003B:"Bishop Plug",003C:"Rook Plug",003D:"Knight Plug",003E:"King Plug",003F:"W. Box Key",0040:"Detonator",0041:"Plastic Bomb",0042:"Bomb&Detonator",0043:"Crank",0044:"Film",0045:"Film (?)",0046:"Film (?)",0047:"Unicorn Medal",0048:"Eagle Medal",0049:"Wolf Medal",004A:"G. Cogwheel",004B:"Manhole Opener",004C:"Main Fuse",004D:"Fuse Case",004E:"Vaccine",004F:"Vaccine Cart.",0050:"Film",0051:"Base Vaccine",0052:"G-Virus",0053:"Special Key",0054:"Joint S Plug",0055:"Joint N Plug",0056:"Cord",0057:"Film",0058:"Cabin Key",0059:"Precinct Key (blue)",005A:"Precinct Key (red)",005B:"Precinct Key (?)",005C:"Precinct Key (green)",005D:"C. Panel Key (red)",005E:"C. Panel Key (yellow)",005F:"P. Room Key",0060:"MO Disk",0061:"Lab Card Key",0062:"Master Key",0063:"Platform Key",0064:"No Item",0065:"No Item",0066:"No Item",0067:"No Item",0068:"Chris's Diary",0069:"Mail to Chris",006A:"Memo to Leon",006B:"Police Memorandum",006C:"Operation Report 1",006D:"Mail to the Chief",006E:"Mail to the Chief (?)",006F:"Secretary's Diary A",0070:"Secretary's Diary B",0071:"Operation Report 2",0072:"User Registration",0073:"Film A",0074:"Film B",0075:"Film C",0076:"Patrol Report",0077:"Watchman's Diary",0078:"Chief's Diary",0079:"Sewer Manager Diary",007A:"Sewer Manager Fax",007B:"Film D",007C:"Vaccine Synthesis",007D:"Lab Security Manual",007E:"P-Epsilon Report",007F:"Rookie Files",0080:"Rookie Files (?)",0081:"No Item",0082:"Spade Key",0083:"Diamond Key",0084:"Desk Key",0085:"Heart Key",0086:"Club Key",0087:"Virgin Heart",0088:"Square Crank",0089:"Down Key",008A:"Up Key",008B:"Locker Key" 800E59ED 00FF crc C3E7E29E-5D7251CC-C:50 gn Re-Volt (E) cn Access All\Cars & Tracks 8104ADF6 0001 cn Access All\Cups 5000032C 0000 8105444A 00FF cn Always 1st 811157AE 0001 811157B6 0000 8110C33E 02F4 cn Infinite Continues 8110C332 0006 cn Drones Have No Weapons 8111CECE 0000 cn Infinite Weapons\Player 1 81115798 0000 8111579A ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 8111579E 0001 cn Laps To Race 8107DD1E ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Number Of Drones In The Race 8110FFF6 ???? 0001:"1 Drone",0002:"2 Drones",0003:"3 Drones",0004:"4 Drones",0005:"5 Drones",0006:"6 Drones",0007:"7 Drones",0008:"8 Drones",0009:"9 Drones" cn 99 Points Player 1 8010C33F 0063 cn Infinite Weapons\Player 2 81117C60 0000 81117C62 ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 81117C66 0001 cn Infinite Weapons\Player 3 8111A128 0000 8111A12A ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 8111A12E 0001 cn Infinite Weapons\Player 4 8111C5F0 0000 8111C5F2 ???? 0000:"Green Missile",0001:"Orange Missile",0002:"Multi-Orange Missiles",0003:"The Bomb",0004:"Water Balloon",0005:"Blue Protector",0006:"Oil Slick",0007:"Bowling Ball Mine",0008:"Yellow Protector",0009:"Lightning Bolt",000A:"Orange Star",000B:"Beach Ball" 8111C5F6 0001 crc 02D8366A-6CABEF9C-C:50 gn Road Rash 64 (E) cn Always 1st 810D7D96 0000 cn Max Cash 810D6FBA FFFF cn Access All Bikes & Tracks 810A7D16 0063 cn Access All Weapons For All Modes 50000E02 0000 811B9EFA 0505 cn Infinite Damage 801C1257 0002 cn Infinite Health\To Bike 811B9BB8 4270 cn Infinite Health\To Character 811C0F90 4489 cn No Music In Game 810D61AE 0000 cn No Music Elsewhere 810D61AA 0000 crc 74E87A70-6293AED4-C:50 gn ROADSTERS TROPHY cn Always 1st 800C1F81 0001 cn Laps To Race 800A4649 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Access All Trophies cd Also gives you all extra features in quick race & Trophy mode 800BAA9B 0007 800BACAF 0007 cn Max Race Points 800BACBE 00FF cn Have Lots Of Seasons 810BACAA 02F4 cn Max Cash 810BACA4 3AFF 810BACA6 F3FA cn Cheats Enabled Modifier 8108F8F0 ???? 0004:"Fast Bucks (You Get 250",0008:"Easy Money (You Get 1",0010:"Trophies (Second And Third Championships Wins)",0020:"Smurfing (High Pitched Voices)",0040:"Big Wheels (Big Foot Cars)",0080:"Skywalker (Hover Cars)",0100:"Car Radio (Remote Control Cars)",0200:"Chopper (Top Down View)",0400:"Anyway (Race Circuits Backwards)",0800:"Extra Resolution (Able To Change Resolution In Options Screen)" cn Easy Win cd Right After Start,Go, Quit Race, And you Have Won 800BACAD 000A cn All Cars\Max Upgrade 5000220C 0200 810BAD56 0270 cn All Cars\Infinite Supply Of Super Tires 5000220C 0000 810BAD58 0F0F 5000220C 0000 810BAD5A 0F0F cn Special Category A Car\Mind Star 600 810BAE8E 3D70 810BAE90 0F0F 810BAE92 0F0F cn Special Category B Car\Vertige Stallion 810BAE16 2378 810BAE18 0F0F 810BAE1A 0F0F cn Special Category C Car\Mind Star 200R 810BAD86 0A78 810BAD88 0F0F 810BAD8A 0F0F cn Race Direction Options 810A4600 ???? 0000:"Normal",0001:"Reverse",0002:"Mirrored Normal",0003:"Mirrored Reverse" cn View Select cd Select your View and then at start of Race press C-Up Button D00C2171 0000 800C2171 ???? 0000:"Inside Car",0001:"Behind View",0002:"Further Behind View",000B:"Distant Behind View",00FF:"Helicopter View" cn Track Select 8008FA5D ???? 0000:"Rocket Base",0001:"Temple",0002:"Ski Resort",0003:"Lumber Mill",0004:"Area 51",0005:"Oilfields",0006:"Tudor Village",0007:"Chateau",0008:"Docklands",0009:"Titus Park" crc 9FF69D4F-195F0059-C:50 gn Robotron 64 (E) cn Infinite Lives 8109B0EE 03E7 810AD24E 03E7 cn Level select cd Set Up In Menu 81076FB6 6F74 cn Fast Run 8009B14F 0003 cn Rapid fire 8009B15F 0003 cn Easy Difficulty level 800AD243 0000 cn Speed level 1 Slow 800AD247 0000 crc 9FD375F8-45F32DC8-C:50 gn Rocket - Robot on Wheels (E) cn Infinite & Max Health 8109FB82 000C 8109FB84 000A cn Activate All In-Game Cheats cd With this code on, all rocket's abilities are now max 810A6846 F5FF cn Access All Ticket Switches & Vehicles 800A5E1F 0001 50002004 0000 810A5D70 FFFF crc 60D5E10B-8BEDED46-C:50 gn Rayman2 The Great Escape (E) cn Infinite\Max Health 811BC54C 001E cn Infinite\Oxygen 810F4A80 4396 cn Open Options\levels & Map 50000801 0000 801F1101 00FF cn Open Options\Open all cages 801F1032 0050 50000602 0000 811F10E0 FFFF cn Have All\Yellow Lums 50006401 0000 800C6FF8 00FF 50001901 0000 800C6FAD 00FF 811F1072 0005 50005702 0000 811F1078 FFFF cn Have All\Crates 810C6FE8 7FFF 50000602 0000 810C6FEA FFFF 800C6FF2 00FF cn All Masks cd Press GS To Activate All Masks 891F1110 8780 crc 8BD4A334-1E138B05-C:50 gn Ready 2 Rumble Boxing (E) cn Infinite\Health 810D8E8A ???? 810E6522 ???? 0064:"Infinite",0000:"No Health" cn Infinite\Stamina 810D8E8E ???? 810E6526 ???? 0064:"Infinite",0000:"No Stamina" cn Have Max Rumble 810D8E96 ???? 810E61B8 ???? 0030:"Max",0000:"Never Rumble" cn Infinite\Cash 810EB852 FC9A cn Infinite\Time 810E6486 0E10 crc FEE97010-4E94A9A0-C:50 gn RR64 - Ridge Racer 64 (E) cn Always 1st 810569B4 0001 cn Infinite Time 811280B2 0C00 cn Freeze Lap Timer cd Select Car Attack, And You'll Have All The Cars At Your Disposal For A Quick Spin !! 810569DE 014D cn Access All\Cars,Tracks & Golg Trophies 50000402 0000 81043AA0 FFFF cn Access All\Platinum Trophies 8102F70C FFFF 8102F70E FFFF cn Ultra 64 cd Pick any car, beat stage 8: RR Extreme Extra and the UFO car is yours to drive! 8113DDBA 0018 cn Access\Galage '88 UFO Car 810E2C20 0028 cn Easy Win 810569BA 0007 cn Easy Mode 81057B10 0001 cn Freeze Lap Timer 810569DE 014D 810569CA 00C7 810569CE 00C7 810569EA 014D 810569EE 014D 810569F2 014D cn Always Engine Class S 81043AB0 0000 cn Laps to Race cd Here you can choose how many laps are in the race, 1-9. Do not use with Option 7-9. 8111CA16 ???? 0001:"1 Lap to Race",0002:"2 Laps to Race",0003:"3 Laps to Race",0004:"4 Laps to Race",0005:"5 Laps to Race",0006:"6 Laps to Race",0007:"7 Laps to Race",0008:"8 Laps to Race",0009:"9 Laps to Race" crc 4D3ADFDA-7598FCAE-C:50 gn Rugrats - Treasure Hunt (E) cn Infinite Energy\Player 1 80254A76 001E 8025CCF6 001E cn Infinite Energy\Player 2 80257B86 001E 80260846 001E cn Infinite Energy\Player 3 8025ACA6 001E 802637A6 001E cn Infinite Energy\Player 4 8025E0E6 001E 80266B76 001E crc 0AC61D39-ABFA03A6-C:50 gn Rugrats in Paris - The Movie (E) cn Tickets\Red 8111F8C6 FFFF cn Tickets\Gold 8111F8C8 FFFF cn Access all items In Inventory 8111F8BE 1FFF crc 67D21868-C5424061-C:50 gn Rakuga Kids (E) cn Infinite Energy\Player 1 800ACB89 ???? 0000:"None",0040:"Max" cn Infinite Energy\Player 2 800ACC79 ???? 0000:"None",003F:"Max" cn Super Attacks\Player 1 800ACB8D ???? 0000:"None",0003:"3" cn Super Attacks\Player 2 800ACC7D ???? 0000:"None",0003:"3" cn Infinite Match Time 800ABC33 0000 cn Unlock Extras 800ACD55 00FF 800ACD57 00FF crc 918E2D60-F865683E-C:50 gn S.C.A.R.S. (E) cn Always 1st 813E00E8 0001 cn Access\All Cups 50000302 0000 812CB7C8 0001 cn Access\All Challenges 50000502 0000 813DD428 0001 cn Access\All Cars 50000402 0000 813DFC6A 0001 cn Infinite\Turbo's 8039B464 0000 8039B467 0000 8039B469 0009 cn Infinite\Magnet's 8039B464 0001 8039B467 0001 8039B469 0009 cn Infinite\Stinger's 8039B464 0003 8039B467 0003 8039B469 0009 cn Infinite\Boomerang's 8039B464 0004 8039B467 0004 8039B469 0009 cn Infinite\Seeker's 8039B464 0005 8039B467 0005 8039B469 0009 cn Infinite\Stopper's 8039B464 0006 8039B467 0006 8039B469 0009 cn Infinite\Bullet's 8039B464 0007 8039B467 0007 8039B469 0009 cn Infinite\Shield's 8039B464 0008 8039B467 0008 8039B469 0009 cn Laps To Race 813BBD5C ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Infinite\CREDITS 80388F3D 0003 cn Psycho Weapons 8039B469 0003 802B85A3 0003 crc 61D116B0-FA24D60C-C:50 gn San Francisco Rush - Extreme Racing (E) cn Always 1st 80101409 0000 cn Max Race Points 810DACCA 02F4 cn Laps To Race 800E7411 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Gravity Modifier 800F3E61 ???? 0000:"Ballon & Two Weights",0001:"One Weight",0002:"Two Weights" cn No\Car Collisions 800F4120 0001 cn No\Auto Abort 800F4140 0001 cn Resurrect In Place 800F4150 0001 cn Stop Timer 800F4160 0001 cn Big Front Wheels 800DA02C 0002 cn Big Back Wheels 800DA03C 0002 cn Difficulty Very Easy 810D9F7A 0002 cn Automatic Transmission 800C8100 0001 cn Access The Rock Alcatraz bonus level cd Press C-right, on any level, at the track selection screen D00F4174 0002 80100120 0006 cn All\Keys & Cars 50000E16 0000 810CAD52 FFFF cn All\Keys & Cars Circuits 8105696E FFFF 8105699A FFFF 50000404 0000 81056910 FFFF crc B7CF2136-FA0AA715-C:50 gn San Francisco Rush 2 - Extreme Racing USA (E) cn Always 1st 80115499 0000 cn Max Points In Total 810E235A 03E7 cn Laps To Race 811088D0 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Number Of Drones In Race 810E1B88 ???? 0001:"1 Drone",0002:"2 Drones",0003:"3 Drones",0004:"4 Drones",0005:"5 Drones",0006:"6 Drones",0007:"7 Drones",0008:"8 Drones",0009:"9 Drones" cn Best Stunt Points cd On Track 8110B438 02F4 cn Max & Best Score cd On Stunt Track 50000502 0000 810C4702 FFFF cn All Keys,Cars & Cans 50000E02 0000 810C4574 FFFF cn Access All In-Game Cheats cd In Set-Up Menu 810C48F8 0100 cn Activate All In-Game Cheats 50000E02 0000 810C48A4 FFFF cn Access Midway Track 810C4890 02F4 cn Easy Difficulty 8010FFAA 0000 cn No\Checkpoints Extended Time 8010FF47 0000 cn No\Wind 80116E98 0000 crc 51D29418-D5B46AE3-C:50 gn San Francisco Rush 2049 (E) cn Always 1st 80177D4E 0000 cn Max Race Points 8117CE22 02F4 cn Laps To Race 81177A18 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" cn Number Of Drones In Race 81163240 ???? 0001:"1 Drone",0002:"2 Drones",0003:"3 Drones",0004:"4 Drones",0005:"5 Drones",0006:"6 Drones",0007:"7 Drones",0008:"8 Drones",0009:"9 Drones" cn Access All In-Game Cheats 81118E9A 0001 cn Activate All In-Game Cheats 50000D02 0000 81118E82 0101 cn All Silver & Gold Coins cd Single, Practice & Circuit Mode 50000660 0000 8116375C FFFF cn All Silver & Gold Coins cd Circuit Mode - Using Controller Pack 50000660 0000 811C542C FFFF cn All Silver & Gold Coins cd Stunt Mode 50000440 0000 81163BBC FFFF cn Extended Time In Battle & Stunt Mode To 2.05 Hours 811633BA 457C 811636EE 4514 cn Stunt Wings All Modes cd Where Wings Are Available Press D-Pad Up On Wing Select D017055A 0004 50000C02 0000 811139D0 0202 cn Stunt Wings Circuit Mode cd Press D-Pad Up On Wing Select D017055A 0004 50000C02 0000 801756A1 0202 cn Easy Difficulty level 80177A3C 0000 cn Max Points Stunt Mode 81177A55 3AFF 81177A57 F3FA crc E3BD221D-3C0834D3-C:50 gn Scooby-Doo - Classic Creep Capers (E) cn Have All Items\What a night for a knight 811BA010 0101 811BA012 0101 811BA014 0101 811BA016 0101 811BA018 0101 cn Infinite Courage 810BB096 0007 F107D9B0 0000 crc 60C437E5-A2251EE3-C:50 gn Shadowman (E) cn Have All\Items cd Youll not miss out any part of the game for having all parts of LEclipsers with a new game D0059047 0001 50001D20 0000 80030613 000B cn Have All\Gads & The Poign 80030E57 000F cn Have All\Levels Unlocked 5000101C 0000 80030A0E 0001 cn Have All\Cheats: Book of Shadows 81075F4E 0FFF cn Have All\Dark Souls Collected D00590B3 0001 80075F49 007C cn Infinite\Shotgun Shells 80075B2F 0063 cn Infinite\Violator Ammo 81075B32 029A cn Infinite\Cadeaux' 81075B36 029A cn Infinite\0.9mm Ammo 81075B3A 0190 cn Infinite\Max Health/Air/Shadow Charge & Voodoo Power 50000604 0000 81075B16 2710 cn Infinite\Accumulators 800306D7 0005 cn Infinite\Retractors 800308B7 0003 cn Infinite\Prisms 80030957 0003 cn Ammo always displayed on screen 50000408 0000 80075ACD 0007 cn Press L To Levitate D0059097 0020 80075578 0041 crc 5FD7CDA0-D9BB51AD-C:50 gn Snowboard Kids (E) cn Infinite Cash 8112272A 02F4 cn Access Everything cd "Have All Characters,Cups,Courses,&Boards" 810B3160 0100 810B3164 0F00 cn 1 Lap To Race D01226C8 0000 801226C8 0009 cn Infinite Tools Options 801226D5 ???? 0001:"Fan",0002:"Ghost",0003:"Pan",0004:"Rock",0005:"Mouse",0006:"Board" cn Infinite Weapons\Lucky Dip cd "Lucky Dip is Infinite Usage Of What Ever You Get From Each Red Box" 801226D4 0003 crc C2751D1A-F8C19BFF-C:50 gn Snowboard Kids 2 (E) cn Max Coins 8120639E 270F cn Access Everything\Start New Game 50000502 0002 80204F3B 0013 50000502 0002 80204F42 0009 50000402 0002 80204F43 000A 80204F4B 000D 81204F4C 0E0F 81204F4E 0101 81204F5A 0100 cn Trick Game 300 Points 812065D2 012C cn Infinite Tools Options 80206404 ???? 0001:"Frying Pan",0002:"Ghost",0003:"Super Ghost",0004:"Fan",0005:"Rocket",0006:"Invisible",0007:"Rock",0008:"Rat Face",0009:"Super Rat Face",000A:"Wings" cn Infinite Weapons Options 80206402 ???? 0001:"Slap Stick",0002:"Parachute",0003:"Freeze Shot",0004:"Snowman",0005:"Bomb",0006:"Whirlwind" 80206403 0009 cn Max Money(Story Mode) 81204EB0 0098 81204EB2 967F cn Open Extra Characters 81204F4E 0101 80204F50 0001 cn Have All Snowboards 80204F3C 0001 81204F3E 0101 81204F40 0101 crc 20B53662-7B61899F-C:50 gn South Park (E) cn Have Cheats Menu 800D77D6 01FF cn Infinite Energy 802FD209 0064 cn Infinite Credits 802FD215 0064 cn Infinite Sponge Darts 802FD223 0064 cn Infinite Suckers 802FD222 0064 cn Infinite Balls 802FD21F 0064 cn Start with 9999 Monster Score 812FD20E 270F crc 4F8AFC3A-F7912DF2-C:50 gn South Park Rally (E) cn Infinite Credits 8008D659 0005 cn Have All Tracks 8108875A FFFF cn Have All Races 81088756 FFFF cn Unlock All Characters & Extra Cheats 81088750 FFFF 81088752 FFFF crc FC70E272-08FFE7AA-C:50 gn Silicon Valley cn Great Score 813F2E22 02F4 cn Title Screen cd Press the Pause Button to takes you to Title Screen 803F6799 0000 cn Debug Mode 803F651F 0001 cn Enable Secret Mini Game 803F652D 0001 cn High Score In Evo's Escape 813E4DDA 7FFF cn 0 Enemies To Kill In Big Celebration Parade 803E4DBB 0000 cn Infinite Health\EVO 801DE085 0080 cn Always Raining 803F2E5F 0005 cn Always Snowing 803F2E5D 0005 cn Always in 2nd Camera Angle 803F2B89 0001 cn All levels open 50002001 0000 803F7ED0 0001 cn Infinite Health\2 Mouse,Hyena cd Only Use Infinite Health Codes For Animals You Need 801DFB51 0080 cn Infinite Health\Rocket Dog cd Only Use Infinite Health Codes For Animals You Need 801DEC01 0080 cn Infinite Health\King Rat cd Only Use Infinite Health Codes For Animals You Need 801E19F1 0080 cn Infinite Health\Spit Dog, Bear, King Pen, FB EVO cd Only Use Infinite Health Codes For Animals You Need 801DE459 0080 cn Infinite Health\Fox, Pen, Husky, Tortoise Tank cd Only Use Infinite Health Codes For Animals You Need 801DFF25 0080 cn Infinite Health\Bunny, Racing Turtle cd Only Use Infinite Health Codes For Animals You Need 801DF3A9 0080 cn Infinite Health\Rocket Husky cd Only Use Infinite Health Codes For Animals You Need 801E1DC5 0080 cn Infinite Health\Cool Cod cd Only Use Infinite Health Codes For Animals You Need 801E4039 0080 cn Infinite Health\Elephant cd Only Use Infinite Health Codes For Animals You Need 801DE82D 0080 cn Infinite Health\Lion, Camel cd Only Use Infinite Health Codes For Animals You Need 801E02F9 0080 cn Infinite Health\Desert Fox cd Only Use Infinite Health Codes For Animals You Need 801E161D 0080 cn Infinite Health\A. Desert Rat, Vulture, Box, Kang cd Only Use Infinite Health Codes For Animals You Need 801DEFD5 0080 cn Infinite Skill\A\Power Mouse cd Only Use Infinite Skill A Codes For Animals You Need 801DFCE4 0004 cn Infinite Skill\A\Rocket Dog cd Only Use Infinite Skill A Codes For Animals You Need 801E3A24 0004 cn Infinite Skill\A\King Rat cd Only Use Infinite Skill A Codes For Animals You Need 801E1B84 0004 cn Infinite Skill\A\King Penguin cd Only Use Infinite Skill A Codes For Animals You Need 801DE5EC 0004 cn Infinite Skill\B\Rocket Dog cd Only Use Infinite Skill B Codes For Animals You Need 801E3A28 0004 cn Infinite Skill\B\Bear cd Only Use Infinite Skill B Codes For Animals You Need 801DE5F0 0004 cn Infinite Skill\B\Power Pen, Husky, Fox, Tort Tank cd Only Use Infinite Skill B Codes For Animals You Need 801E00BC 0004 cn Infinite Skill\B\Bunny, Racing Turtle cd Only Use Infinite Skill B Codes For Animals You Need 801DF540 0004 cn Infinite Skill\B\Rocket Husky cd Only Use Infinite Skill B Codes For Animals You Need 801E1F5C 0004 cn Infinite Skill\B\Hyena cd Only Use Infinite Skill B Codes For Animals You Need 801DF914 0004 cn Infinite Skill\B\Lion cd Only Use Infinite Skill B Codes For Animals You Need 801E0490 0004 cn Infinite Skill\B\Armed Desert Rat cd Only Use Infinite Skill B Codes For Animals You Need 801DF16C 0004 cn Infinite Skill\B\Desert Fox cd Only Use Infinite Skill B Codes For Animals You Need 801E17B4 0004 cn Infinite Skill\B\Boxing Kangeroo cd Only Use Infinite Skill B Codes For Animals You Need 801DF16C 0004 crc 42CF5EA3-9A1334DF-C:50 gn StarCraft 64 (E) cn Infinite Vespene gas,minerals & Most missions 50003202 0000 800B1D96 00FF cn All levels complete 800D1364 000C 50000501 0000 800D1365 000A crc F4CBE92C-B392ED12-C:50 gn STARFOX64 Lylat Wars (E) cn Unlimited\Boost 8113E6FC 0000 8113E6FE 0000 811415DC 0000 811415DE 0000 8013E7FD 0000 801416DD 0000 cn Have All Medals cd For Expert & Normal Modes 50000802 0000 8017A9D9 7777 cn Infinite\Hyper Laser 80163B13 0002 cn Loads O' Hits 80163B03 00FF cn Infinite\Armor\Slippy 8017418B 00FF cn Infinite\Energy 80141587 00FF 8013E6A7 00FF cn Infinite\Lives 80163B09 0063 cn Unlimited\Smart Bombs 80179E0B 0063 cn Infinite\Armor\Falco 80174187 00FF cn Infinite\Armor\Peppy 8017418F 00FF cn Infinite\Dual Blue Lasers 80163C13 0002 cn Level Select 8017A29F ???? 0000:"Corneria",0001:"Meteo",0002:"Sector X",0003:"Area 6",0004:"Glitch",0005:"Sector Y",0006:"Venom 1",0007:"Solar",0008:"Zoness",0009:"Venom 2",000A:"Training Mode Level",000B:"Macbeth",000C:"Titania",000D:"Aquas",000E:"Fortuna",0010:"Katina",0011:"Bolse",0012:"Sector Z",0013:"Venom With Starwolf",0014:"Corneria (Multi)" cn 999 Kills 80163B03 00FF crc D89E0E55-B17AA99A-C:50 gn Starshot - Space Circus Fever (E) cn Infinite Lives 801A3E83 0063 cn Infinite Shots 801A3EB7 0064 cn Infinite Flight Time 801A3F1F 0064 cn Infinite Mega Fuel 801A3EEB 0064 crc 7EE0E8BB-49E411AA-C:50 gn Star Wars - Rogue Squadron (E) cn Infinite Lives cd This Also accesses advanced Shields & Radar 81130B38 01C0 cn Invincibility cd This Also Accesses All Levels And Makes All Crafts Available 80130B2D 00FF cn Infinite Secondary Weapon 8010CA02 0063 80130B23 ???? 0001:"Ion Cannon",0002:"Missiles",0003:"Seeker Missiles",0004:"Bombs",0005:"Proton Bombs",0007:"Cluster Missiles",0008:"Seeker Torpedos",0009:"Seeker Cluster Missiles" cn Completion Time 0:00 80130B85 3FCB cn Enemies Destroyed 756 81130B64 02F4 cn Accuracy 100% 80130B5F 0063 cn Friendly Saves 756 80130B66 02F4 cn Bonus Collected 756 80130B67 02F4 cn Always Pass Mission 80130AF4 0001 cn Accesses\All Levels,Ships & Advanced Weapons 80130B3B 00FF cn Access\69 Buick Electra cd Replaces The V-Wing 81130B3A 000E cn Access AT-ST Level 81130B38 1250 crc 219191C1-33183C61-C:50 gn Star Wars - Rogue Squadron (E) (V1.1) cn Infinite\Infinite Lives 80130B10 0008 cn Extra Shields 81137E7C 4316 cn Infinite\Infinite Secondary Weapons 8010CA32 0008 cn Infinite\Infinite Health 81137E7C 4316 cn Have 99\Bonus Collected 80130B87 0063 cn Have 99\Kills 80130B85 0063 cn Have 99\Saves 80130B86 0063 cn 1-Hit Death 81137E7C 4136 cn Have Medals For\Ambush at Mos Eisley 88130B1C ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Rendezvou on Bankhesh 88130B1D ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\The Search For The Noonnah 88130B1E ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Defection At Corellia 88130B1F ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Liberation V 88130B20 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\The Jade Moon 88130B21 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Imperial Construction Yard 88130B22 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Assault on Kile II 88130B23 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Rescue on Kessel 88130B24 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Prisons on Kessel 88130B25 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Battle Above Taloraan 88130B26 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Escape From Fest 88130B27 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Blockade on Chandrila 88130B28 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Raid on Sullust 88130B29 ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Moff Seerdon's Revenge 88130B2A ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\The Battle of Calamari 88130B2B ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Beggar's Canyon 88130B2C ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\The Death Star Trench Run 88130B2D ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" cn Have Medals For\Battle of Hoth 88130B2E ???? 0000:"None",0001:"Bronze Medal",0002:"Silver Medal",0003:"Gold Medal" crc 4D486681-AB7D9245-C:50 gn Shadow of the Empire cn Access In-Game Cheat Menu cd Pause gameplay and pink text will appear in top screen. scroll with multiple buttons and select with 'A' D10DDE2E 0001 810D3F32 0001 D10DDE14 0002 810D3F32 0001 D10E28D4 0011 810D3F32 0001 D10E28D4 0011 810D3F32 0001 cn Access Wampa Stompa cd Important To Get All Codes To Work! Select empty file "Wampa Stompa" will now be your playername. 8118D4E8 2057 8118D4EA 616D 8118D4EC 7061 8118D4EE 2020 8118D4F0 5374 8118D4F2 6F6D 8118D4F4 7061 cn Access All Levels cd Must be used with Access Wampa Stompa 810DE2EA 0004 cn Max Challenge Points 8118F370 000F cn Extra Jump Power 810E2220 3F92 cn Freeze Timer 810E2230 4018 crc EAE6ACE2-020B4384-C:50 gn Star Wars Episode I - Battle for Naboo (E) cn Level Select 8004C650 0013 cn Always Pass Mission 8105C88E 0001 cn Advanced Weapons,Shields & Extra Ships 8104C636 00FF cn 2X Secondary Weapons 8104C62A 0080 cn Infinite Lives 80067553 03E7 cn Access All Platinium Medals 50001301 0000 8004C63D 0004 cn Completion Time 0:00 8105C892 0000 cn Enemies Destroyed 756 8005C89D 02F4 cn Accuracy 100% 8105C896 0064 8105C89A 0064 cn Friendly Saves 756 8005C89E 02F4 cn Bonus Collected cd Where Bonus Are Available 8005C89F 0002 cn Lives Remaining 756 8005C8A0 02F4 crc 53ED2DC4-06258002-C:50 gn Star Wars Episode I - Racer (E) cn No Damage cd If when Racing Your Pod Over heats & bursts into flames Press "R" & you will Repair the Damage. 800AA5D7 0001 cn Infinite Truguts 8111CB1A FFFF 8111CB18 7FFF cn Always 1st 80121C8C 0001 80125489 0001 cn Enable In-Game cheat Menu & Cheats cd Here you can Activate the IN-Built Cheats Menu. At the Front Screen Just Press C-Button Right.This will open up All Tracks & Characters In Free Play & Time Attack. Also In A Race, Press The Start/Pause button to Access the In-Cheat-Menu Option.You can also choose how many Pod's Racers are in the Race & also how many Laps are in the Race in Free Play & Time Attack 810A0D27 000A 810A0D2A FFFF cn Unlock All Tracks & Characters cd When using Unlock All Tracks & Characters For can to pick & choose what ever you want to play As & where ;) 8011CB08 00FF 8011CB09 00FF 8011CB0B 00FF 8111CB08 FFFF 8111C80A FFFF 8011CB14 007D 8111CB16 FFFF cn Have All Tracks Completed 8111CB0A FFFF 8111CB0C 3FFF 8111CB0E 3FFF 8111CB10 3FFF 8111CB12 00FF crc A03CF036-BCC1C5D2-C:50 gn SUPER MARIO 64 cn Press GS For 255 Coins 893094D8 00FF cn Have\Level Select A02F973C 0001 cn Don't Hurt Mario\Monsters 80309457 0001 cn Infinite\Lives 803094DD 0064 cn Infinite\Energy & Breath 803094DE 0008 cn Have\Debug Mode A02F9748 ???? 0001:"On",0000:"Off" cn Mario's Cap\Off Options cd Here you can Choose Options with Mario without His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 80309437 ???? 0001:"Mario No Cap",0002:"Invisible Mario",0004:"Metal Mario",0008:"Flying Mario",000A:"Invisible Flying Mario",000D:"Metal Flying Mario",000F:"Invisible Metal Flying Mario" cn Mario's Cap\On Options cd Here you can Choose Options with Mario with His Cap on,Do not use with any other Mario with/without Options,Use only one at a time 80309437 ???? 0012:"Invisible Mario",0015:"Metal Mario",0016:"Invisible Metal Mario",0019:"Flying Mario" cn Funny Mario Options\Mario's Cap\Off & in His Hand cd Here you can Choose Options with Mario with His Cap off & in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 80309437 ???? 0020:"Cap In Hand",0022:"Invisible Mario Cap In Hand",0024:"Metal Mario Cap In Hand",0026:"Invisible Metal Mario Cap In Hand",0028:"Flying Mario Cap In Hand" cn Funny Mario Options\Mario's Cap\On & An Extra in His Hand cd Here you can Choose Options with Mario with His Cap on & An Extra in His Hand,Do not use with any other Mario with/without Options,Use only one at a time 80309437 ???? 0030:"Cap In Hand",0032:"Invisible Mario Cap In Hand",0034:"Metal Mario Cap In Hand",0036:"Invisible Metal Mario Cap In Hand",0038:"Flying Mario Cap In Hand" cn Press L To Levitate cd Press L to levitate & Let go to land D0309261 0020 8130947C 4220 D0309261 0020 8130943C 0300 D0309261 0020 8130943E 0880 cn [Slot A Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80202F23 0001 80202F0B 00C7 50001101 0000 80202F0C 00FF cn [Slot A Codes]\Have all key doors unlocked (and mote empty) 80202F0A 007E cn [Slot A Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80202F25 0064 cn [Slot B Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80202F93 0001 80202F7B 00C7 50001101 0000 80202F7C 00FF cn [Slot B Codes]\Have all key doors unlocked (and mote empty) 80202F7A 007E cn [Slot B Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80202F95 0064 cn [Slot C Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80203003 0001 80202FEB 00C7 50001101 0000 80202FEC 00FF cn [Slot C Codes]\Have all key doors unlocked (and mote empty) 80202FEA 007E cn [Slot C Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80203005 0064 cn [Slot D Codes]\Have All 120 Stars cd Have 120 Stars,once the Code is activated, you will see it as a new option in Save Slot A.This will have the Cannon open already to get upto Yoshi on the Roof. but make sure to save the game after collecting Red Coins and turn this code off before saving. you will now have it all saved to mempak 80203073 0001 8020305B 00C7 50001101 0000 8020305C 00FF cn [Slot D Codes]\Have all key doors unlocked (and mote empty) 8020305A 007E cn [Slot D Codes]\Have All Max 100 Coin Records For All Levels 50000F01 0000 80203075 0064 crc 93945F48-5C0F2E30-C:50 gn Super Smash Bros (E) cn Give Kirby A Wierd Blow-Up 802669B8 000A cn Story Mode\Skip Straight To Master Hand 800AD347 000D cn Story Mode\Infinite Time 810AD38E 43CB cn Story Mode\Player 1\Infinite Lives 800AD3A3 0004 cn Story Mode\Player 2\Infinite Lives 800AD417 0004 cn Story Mode\Player 3\Infinite Lives 800AD48B 0004 cn Story Mode\Player 4\Infinite Lives 800AD4FF 0004 cn Story Mode\Player 1\Low % Health 810AD3E6 0000 cn Story Mode\Player 2\Low % Health 810AD45A 0000 cn Story Mode\Player 3\Low % Health 810AD4CE 0000 cn Story Mode\Player 4\Low % Health 810AD542 0000 cn Story Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code could also result freezing at the end of the Level. 800AD39B ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800AD40F ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800AD483 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800AD4F7 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 1\Kirby B Button Move\Hyrule Castle 8027136F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Yoshi's Island 802716AF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Sector Z 80279957 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Peach's Castle 8026C5FF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Saffron City 8027C2F7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Congo Jungle 8027932F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Kirby's Dreamland 8027639F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Planet Zebes 80278807 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Metal Mario Stage 8026BDF7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Fighting Polygon Team 8026AF7F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Master Hand Stage 8027A4AF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Infinite Time 810AD57E 43CB cn VS. Mode\Player 1\Low % Health 810AD5D6 0000 cn VS. Mode\Player 2\Low % Health 810AD64A 0000 cn VS. Mode\Player 3\Low % Health 810AD6BE 0000 cn VS. Mode\Player 4\Low % Health 810AD732 0000 cn VS. Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800AD58B ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800AD5FF ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800AD673 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800AD6E7 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 1\Kirby B Button Move\Hyrule Castle 8026C24F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Yoshi's Island 80276B17 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Sector Z 802747E7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn P1 Press Down On D-Pad To Make Items Appear In Random Spots D10A7804 0400 81195902 0001 cn Have All Characters 810AD198 0FF0 cn VS. Mode\Have Mushroom Kindom 800AD197 00FF cn Story Mode\Always Get Pacifist (60,000 Points) 810AD3CE 0000 cn Bonus Stage Character Modifier (Training Mode) cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 80197A33 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Jump off to win 810AD3A2 0000 crc B44CAB74-07029A29-C:50 gn Superman (E) cn Infinite Options\Freezing Breath 8122CDE8 42C8 cn Infinite Options\Health 8122CDD4 42C8 cn Infinite Options\Laser Eye 8122CDE4 42C8 cn Infinite Options\Running Boosts 8122CDDC 42C8 cn Infinite Options\X-Ray Vision 8122CDE0 42C8 cn For More Time Press D-pad up D00EA380 0008 8115F0D2 1724 D00EA380 0008 8115F0DA 003C cn Level Select D00EA380 0020 8117A378 0013 D00EA380 0020 8117A388 000F 81144727 0063 crc E0C4F72F-769E1506-C:50 gn Tigger's Honey Hunt (E) cn Max Honey Pots 810A288A 03E7 cn Infinite Lives 810A2886 0009 cn Have Mouse Card\The Adventure Begins 800A2864 0001 cn Have Mouse Card\Night Tail 800A2865 0001 crc 2B4F4EFB-43C511FE-C:50 gn TOM AND JERRY cn [Unlock All Characters] cd This Gives you all Characters to choose from plus fixes A freeze on the Charecter Select Menu by having it on 800E4933 00FF cn Open All Versus Arenas 800E4934 00FF 800E4935 00FF cn Infinite Health 800E2BDD 00C8 cn One Hit To Kill\Player 1 cd This Will Give Player 1 A One Hit Kill Over Player 2 800E2EB4 0080 cn One Hit To Kill\Player 2 cd This Will Give Player 2 A One Hit Kill Over Player 1 800E2BDC 0080 cn Always Have Weapon Options\Player 1 810E2DD4 ???? 0079:"Anvil",0003:"Club",0004:"Bird bath",0008:"Broom",0009:"NCube knife",000A:"NCube missiles",000B:"Chair",000C:"Champagne",000E:"Chicken",000F:"Crate",0014:"Deck chair",0016:"Egg",001A:"Fish",001D:"Gardeners Fork",001E:"Frying Pan",001F:"Wooden Chair",0029:"Bouy",002A:"Mallet",002B:"Watermelon",002D:"Milk Bottle",0039:"Plank",0041:"Rolling Pin",0046:"Spade",0047:"Stool",0048:"Tennis Racket",004E:"Spanner",0055:"Stick",0063:"Blue Swordfish",0064:"Saucepan",0065:"Wooden Spoon",006B:"Stool",006D:"Bee hive",0078:"Mooses head" cn Always Have Weapon Options\Player 2 810E30AC ???? 0079:"Anvil",0003:"Club",0004:"Bird bath",0008:"Broom",0009:"NCube knife",000A:"NCube missiles",000B:"Chair",000C:"Champagne",000E:"Chicken",000F:"Crate",0014:"Deck chair",0016:"Egg",001A:"Fish",001D:"Gardeners Fork",001E:"Frying Pan",001F:"Wooden Chair",0029:"Bouy",002A:"Mallet",002B:"Watermelon",002D:"Milk Bottle",0039:"Plank",0041:"Rolling Pin",0046:"Spade",0047:"Stool",0048:"Tennis Racket",004E:"Spanner",0055:"Stick",0063:"Blue Swordfish",0064:"Saucepan",0065:"Wooden Spoon",006B:"Stool",006D:"Bee hive",0078:"Mooses head" cn Infinite time 800FF18E 00F0 cn No music 800B7718 0000 crc 9F8926A5-0587B409-C:50 gn Tony Hawk's Pro Skater 1 (E) cn Access all Levels,tapes,boards & Officer Dick 50000C14 0000 800DE9FC 001E cn Access All gold medals cd Also opens San Francisco & Downtown Minneapolis 50000C14 0000 800DEA03 00FF 50000C14 0000 800DEA06 00FF 50000C14 0000 800DEA08 00FF cn 10x Trick Multiplier 800D60FE 0001 cn Max\Balance 800D62DF 00FF cn Max\Turning 800D6220 00FF cn Max\Speed 800DE83A 0001 cn Max\Air 800D62DC 00FF crc 84EAB557-C88A190F-C:50 gn Tony Hawk's Pro Skater 2 (E) cn Access In-Game Cheat Menu 50001104 0000 800E9E98 0001 cn 10x Points Multiplier 800EAD8F 0001 cn Perfect Balance 800E9EAA 0010 cn Always Special 800E9EAC 0001 800E9EAE 0001 cn Moon Psysics 800E9ECE 0001 cn Hoffmann Factory & Skate heaven Unlocked 800EA18B 003F cn Access\Spider-Man 800E9E98 0001 800F0C5B 0001 cn Access\Officer Dick 800E9E9C 0001 800F093B 0001 cn Infinite Time 800E886A 0001 cn Max Cash cd All standard players,Officer Dick & Spider-Man 50000EE4 0000 810E88F8 000A 50000EE4 0000 810E88FA 2B1F 50000EE4 0000 810E88FC 000A 50000EE4 0000 810E88FE 2B1F cn Level Goals 100% cd All standard players,Officer Dick & Spider-Man, Use together with 50000EE4 0000 810E8900 FFFF 50000EE4 0000 810E8902 FFFF 50000EE4 0000 810E8904 FFFF 50000EE4 0000 810E8906 FFFF 50000EE4 0000 810E8908 FFFF 50000EE4 0000 810E890A FFFF 50000EE4 0000 810E890C FFFF 50000EE4 0000 810E890E FFFF 50000EE4 0000 810E8920 FFFF cn All Gaps 50000A0C 0000 810E9D84 FFFF 50000A0C 0000 810E9D86 FFFF 50000A0C 0000 810E9D8A FFFF 50000402 0000 810E9DF4 FFFF cn Max Cash For All Custom Players 500004E4 0000 810E948C 000A 500004E4 0000 810E948E 2B1F 500004E4 0000 810E9490 000A 500004E4 0000 810E9492 2B1F cn Levels Goals 100% All Custom Players 50000802 0000 810E9494 FFFF 50000802 0000 810E9578 FFFF 50000802 0000 810E965C FFFF 50000802 0000 810E9740 FFFF crc 5F3F49C6-0DC714B0-C:50 gn Top Gear Hyper-Bike (E) cn Access All\Bikes 8107F6EE FFFF cn Access All\Tracks 8107F6F0 00FF 8107F6F2 FFFF cn Infinite\Nitro 810BA540 4296 cn Infinite\Nitro Always On 810BA52C 0010 cn Laps 2 Race 800F36B8 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" crc D09BA538-1C1A5489-C:50 gn Top Gear Overdrive (E) cn Extra Cars & Tracks 80102A71 000E 80102A68 0005 cn Infinite Money 810F5905 0FA0 cn Infinite Nitro 800F590F 000F cn Laps 2 Race 80118E20 ???? 0001:"1 Lap",0002:"2 laps",0003:"3 Laps",0004:"4 Laps",0005:"5 Laps",0006:"6 Laps",0007:"7 Laps",0008:"8 Laps",0009:"9 Laps" crc 7F43E701-536328D1-C:50 gn TOP GEAR RALLY cn Have 1-6 Level Points 8032685F 0064 80326861 0064 80326863 0064 80326865 0064 80326867 0064 80326869 0064 cn Extra Cars & Tracks 8032690F 00FF 8032690C 00FF 8032690D 00FF cn Only Race 1 Lap Championship Mode 8031EBDB 0002 cn Always Place 1st 8031EC0F 0000 crc BEBAB677-51B0B5E4-C:50 gn TOP GEAR RALLY 2 cn Always 1st 80032713 0001 cn No Damage Or Failures 80031BA7 0001 cn 100.000 Sponsor Credits & 950 Championship Points In Support Van cd You Also Have Access To All Cars, Tracks & Extra Features 80031BB3 00F3 cn No Cones Hit cd In ARSG Rally School 80032743 0000 80032B1B 0000 cn No Navigator 80032677 0000 cn Max Sponsor Credits 803D27E2 0010 803D27E4 0001 cn Infinite Cash 803D004E 4000 cn Freeze Timer 8003271F 0000 crc CCEB3858-26952D97-C:50 gn Toy Story 2 (E) cn Have 99 coins 810BB4FE 0063 cn Have all 5 collectables 801C7E62 0005 cn Infinite Lives 800BB4FA 0009 cn Infinite Battery Power 810BB4F6 000E cn Hold jump to fly 810BB4EC 0002 crc 2F7009DD-FC3BAC53-C:50 gn Turok - Dinosaur Hunter (E) (V1.0) cn Infinite\Lives 80128D7F 00FF cn Infinite\Body Armor 81128D96 5B23 80128DD7 0001 cn Infinite\Air 801290E0 0063 801E869A 0063 cn Infinite\Health 812C1634 1E61 812A25A4 1E61 cn Have\All Level Keys 50000604 0000 80128DE3 0007 80128DFB 001F 80128E1B 00FF cn Have\All Weapons 50000B04 0000 80128DB7 0001 80128D33 0001 cn Infinite\Ammo 50000404 0000 80128D63 00FF 80128D73 00FF 80128D7F 00FF 50000504 0000 80128D83 00FF 80128F0B 00FF 80128F07 00FF cn Diffuculty Modifier 801195DF ???? 0000:"Easy",0001:"Normal",0002:"Hard" cn Have\Backpack 80128CEB 0001 80128D2B 0001 cn Open All Portals cd Press L to Access Map 8114F8CA F803 81128D4E 0003 81128D52 0003 81128D56 0003 81128D5A 0003 81128D5E 0003 81128D62 0003 81128D66 0005 cn Have All\Gems 80128F07 00FF cn Have\Cheat Menu 811195F0 FFFF 811195F2 FFFF crc 2F700DCD-176CC5C9-C:50 gn Turok - Dinosaur Hunter (E) (V1.1) cn Infinite\Lives 80128E1F 00FF cn Infinite\Body Armor 81128E36 5B23 80128E77 0001 cn Infinite\Air 80129180 0063 801E873A 0063 cn Infinite\Health 812C16D4 1E61 812A2644 1E61 cn Have\All Level Keys 50000604 0000 80128E83 0007 80128E9B 001F 80128EBB 00FF cn Have\All Weapons 50000B04 0000 80128E57 0001 80128DD3 0001 cn Infinite\Ammo 50000404 0000 80128E03 00FF 80128E13 00FF 80128E1F 00FF 50000504 0000 80128E23 00FF 80128FAB 00FF 80128FA7 00FF cn Diffuculty Modifier 8011967F ???? 0000:"Easy",0001:"Normal",0002:"Hard" cn Have\Backpack 80128D8B 0001 80128DCB 0001 cn Open All Portals cd Press L to Access Map 8114F96A F803 81128DEE 0003 81128DF2 0003 81128DF6 0003 81128DFA 0003 81128DFE 0003 81128E02 0003 81128E06 0005 cn Have All\Gems 80128FA7 00FF cn Have\Cheat Menu 81119690 FFFF 81119692 FFFF crc 1EA26214-E790900F-C:50 gn Turok - Rage Wars (E) cn Have All Medals cd Unlocks the In-Game Cheat Menu.Only works with a Controller-Pak 8010EB50 0003 50000601 0000 8010EB4A 00FF cn Have All Mini Game Icons cd Only works with a Controller-Pak 8010EB17 0024 cn Infinite Lives\Player 1 8033637E 0064 cn Infinite Health\Player 1 80336527 0064 80692B86 0064 cn Infinite Ammo All Guns\Player 1 50000302 0000 80336535 0063 50000702 0000 80692B95 0063 cn All Levels Completed cd Unlocks Frag Fest & Time Trial 50000601 0000 8010EB7D 00FF cn All Characters 50000301 0000 8010EB51 00FF cn Deaths Modifier 8110EB76 ???? 000A:"10",0014:"20",001E:"30",0028:"40",0032:"50",0064:"100",00C8:"200",0190:"400",0320:"800",0640:"1600",03E7:"Infinite" cn Wins Modifier 8110EB72 ???? 000A:"10",0014:"20",001E:"30",0028:"40",0032:"50",0064:"100",00C8:"200",0190:"400",0320:"800",0640:"1600",03E7:"Infinite" cn Total Kills Modifier 8110EB6E ???? 000A:"10",0014:"20",001E:"30",0028:"40",0032:"50",0064:"100",00C8:"200",0190:"400",0320:"800",0640:"1600",03E7:"Infinite" crc E0B92B94-80E87CBD-C:50 gn Turok 2 - Seeds of Evil (E) cn Access In-Game Cheat Menu 8112167C FFFF 8112167E FFFF cn Access All Nuke Pieces 1-6 cd Enter the In-game inventory option, and press L Button D00FC701 0020 50000601 0000 802FC99C 0030 crc 6A162FF2-2093704C-C:50 gn Turok 3 - Shadow of Oblivion (E) cn Infinite\Grenade Gun Ammo 8133340A 0064 cn Have\a Grenade Launcher 80333954 0001 cn Infinite\Shotgun Ammo 81333932 0064 cn Have\Shotgun 80333950 0001 cn Infinite\Arrows 81333928 0063 cn Infinite\Life Units 813334FC 0063 cn Access\All Cheats & Level Warp 811659D4 FFFF 811659D6 FFFF crc E688A5B8-B14B3F18-C:50 gn TWISTED EDGE cn Max\50000 Stunt Points 81082AD8 C350 cn Low Timer 80082A04 0000 80182A06 0000 cn Have\All Characters 81082B18 07FF cn Have\All Difficulties 81082B10 0700 cn Have\All Tracks 81082B1C BFFE cn Have\All Boards 81082B24 0003 81082B26 FFFF crc 151F79F4-8EEDC8E5-C:50 gn Vigilante 8 (E) cn All Quests Completed 80193CA4 003F 50000C01 0000 80193C98 001F cn Max Stats All Characters 50000B24 0000 811896EC 1414 50000B24 0000 811896EE 1400 cn Access All Characters 81193CA4 3F00 50000602 0000 81193C98 1F1F crc 98F9F2D0-03D9F09C-C:50 gn Virtual Pool 64 (E) cn Foul score will stay at 0 802EF725 0000 cn Score 0 points in shark skins 802EF723 0000 cn Have 5 games won 802EF721 0005 cn Pot 1 to win Set points to 25 in straight pool 802EF71D 0019 crc 636E6B19-E57DDC5F-C:50 gn V-Rally Edition 99 (E) cn Access\All Cars 8015EC13 003F cn Access\All Tracks 8015EC0E 0070 cn Access\Championship,World,Expert 8015EC1C 0001 cn Access\Expert Times 8015EC10 0031 cn Access\In-Game Cheat Menu cd On The Title Screen, Hold Z Button & Push L Button 811CFE09 00FF 811F31FF 04FF 811CE165 FF03 crc 93053075-261E0F43-C:50 gn Waialae Country Club - True Golf Classics (E) cn All Players On 1st Shot 813013DA 0000 crc D715CC70-271CF5D6-C:50 gn WAR GODS cn Infinite Time 8033F6FB 0064 cn Enable Cheat Menu 80336973 0001 cn Skill Select\Player 2 cd Max Skill makes the player more Skillful while easier to hurt where as Weak Skill is Non Skillful yet harder to harm. 80335C20 ???? 0080:"Max Skill",0000:"Weak Skill" cn Skill Select\Player 1 cd Max Skill makes the player more Skillful while easier to hurt where as Weak Skill is Non Skillful yet harder to harm. 80335C1D ???? 0080:"Max Skill",0000:"Weak Skill" cn Difficulty Select 80336953 ???? 0000:"Very Easy",0001:"Easy",0002:"Medium",0003:"Hard",0004:"Very hard" cn Infinite Max Continues 80336963 0005 cn Easy Fatality Select 8033584F ???? 0000:"Always Off",0001:"Always On" cn Press D-Pad\Right to Play As Exor cd Press D-Pad Right at the character Select screen to Replace Maximus with Exor. Do not use with the Play As Cheat D033C263 0008 800EAF87 000B cn Press D-Pad\Left to Play As Grox cd Press D-Pad Left at the character Select screen to Replace Maximus with Grox. Do not use with the Play As Cheat D033C263 0004 800EAF87 000A cn Music Select 80336954 ???? 0000:"Off",0001:"On" cn Level Select 80335C27 ???? 0000:"Off",0001:"Pagan",0002:"Anubis",0003:"Warhead",0004:"Ahau Kin",0005:"Voodoo",0006:"Kabuki" cn Fatalities Select 8033695C ???? 0000:"Off",0001:"On" cn Play As 800EAF87 ???? 0000:"Warhead",0001:"Tak",0002:"Voodoo",0003:"Pagan",0004:"Kabuki Jo",0005:"Vallah",0006:"Ahau Kin",0007:"Anubis",0008:"CY-5",0009:"Maximus",000A:"Grox",000B:"Exor" crc 650EFA96-30DDF9A7-C:50 gn Wave Race 64 (E) cn Set\Speed Size 801C0077 ???? 0001:"Slow",000A:"Medium",000F:"Fast" cn Misses Don't Count\Player 1 801C007F 0000 cn Set\Wave Size 800E6B90 ???? 0000:"Smooth",0019:"Medium",0064:"Rough",00FF:"Oh My God" cn Infinite Time Stunt Mode 801C020E 00FF cn Maximum Power\Player 1 801C0077 0005 cn Maximum Power\Player 2 801C069A 0005 801C093A 0005 cn Only Play Glacier Coast 800D8003 0007 cn Always Place 1st\Player 1 801BFF4F 0000 cn Lap Timer Below 0'00'10\Player 1 811C00E6 0000 cn Misses Don't Count\Player 2 811C03F6 0000 cn Lap Timer Below 0'00'10\Player 2 811C045E 0000 crc 661B45F3-9ED6266D-C:50 gn Wayne Gretzky's 3D Hockey '98 (E) cn Max Score\Team 1 81120220 FFFF cn Max Score\Team 2 81123730 FFFF cn Difficulty Mod 801247F9 ???? 0000:"",0001:"",0002:"",0003:"" cn Anger metre always full 800D9B38 00FF 800D9826 00FF crc CEA8B54F-7F21D503-C:50 gn Wetrix (E) cn Always Empty Drain 801BF991 0000 811BF992 0000 811BF994 0000 cn Bezerk Mode 801BF9AF 00FF cn Stop Level Timer 801BF9B2 00FF crc 54310E7D-6B5430D8-C:50 gn Wipeout 64 cn Access\Velocitar 800927F9 0001 cn Access\Pirahna 2 80092979 0001 cn Access Pirahna 2 cd Multiplayer 80091259 0001 8109125A 0001 cn Access\Super Combo 81092ACC 0000 cn Infinite\Ammo 80091254 0001 cn Cyclone Option 80091258 ???? 0000:"Off",0001:"On" cn Always First 810A9248 0001 8109F3E6 0003 cn Freeze Checkpoint Timer 810CE1D2 BCCC cn A perfect Lap 800914B4 0001 cn Access\All Gold Challenges\Race 81092CCC 0000 cn Access\All Gold Challenges\Time Trial 8109354C 0000 cn Access\All Gold Challenges\Weapon 8109394C 0000 cn Access\All Gold Challenges\Super Combo 81093D4C 0000 cn Access\All Gold Awards 50001C2C 0000 800941BC 0003 cn [Infinite Sheild] 5000030C 0000 810A92C2 0000 810A92F2 0000 cn always 1st 810A9248 0001 crc 6D8DF08E-D008C3CF-C:50 gn WWF No Mercy (E) cn Infinite\Money\Championship Mode cd For Championship Mode 8109940A FFFF cn Infinite\Money\Smackdown Mall Shop cd For Smackdown Mall Shop 8114FAD6 FFFF cn Have All\Characters,Costumes, & Moves 50000B02 0000 810BEE40 FFFF cn Max Spirit\Player 1 D015A5D1 0015 8015AF5F 00FF cn Max Spirit\Player 2 D015A5D1 0015 8015B2B7 00FF cn Max Spirit\Player 3 D015A5D1 0015 8015B60F 00FF cn Max Spirit\Player 4 D015A5D1 0015 8015B967 00FF cn Always Special\Player 1 D015A5D1 0015 8015AF9E 0004 cn Always Special\Player 2 D015A5D1 0015 8015B2F6 0004 cn Always Special\Player 3 D015A5D1 0015 8015B64E 0004 cn Always Special\Player 4 D015A5D1 0015 8015B9A6 0004 cn Ultimate Code\Player 1 D015A5D1 0015 8015AF5E 0064 cn Ultimate Code\Player 2 D015A5D1 0015 8015B2B6 0064 cn Ultimate Code\Player 3 D015A5D1 0015 8015B60E 0064 cn Ultimate Code\Player 4 D015A5D1 0015 8015B964 0064 cn 2 Player Championship Mode cd This lets player 2 play with you in championship mode so if you have a friend that you want to tag team up with in tag team championship now you can. 810A755E 0002 cn CPU To Human Control\Player 1 8015AF99 ???? 0017:"Human",0018:"CPU" cn CPU To Human Control\Player 2 8015B2F1 ???? 0017:"Human",0018:"CPU" cn CPU To Human Control\Player 3 8015B649 ???? 0017:"Human",0018:"CPU" cn Can't Pin\Player 1 cd Do not use with Auto Pin 8016CE23 0004 cn Can't Pin\Player 2 cd Do not use with Auto Pin 8016CE17 0004 cn Can't Pin\Player 3 cd Do not use with Auto Pin 8016CE2F 0004 cn Can't Pin\Player 4 cd Do not use with Auto Pin 8016CE3B 0004 cn Auto-Pin\Player 1 cd Do not use with Cant Pin 8016CE23 0003 cn Auto-Pin\Player 2 cd Do not use with Cant Pin 8016CE17 0003 cn Auto-Pin\Player 3 cd Do not use with Cant Pin 8016CE2F 0003 cn Auto-Pin\Player 4 cd Do not use with Cant Pin 8016CE3B 0003 cn Play As\Player 1\Option 1 cd Do not use this with anyother Play As Player 1 Option, only use one option at a time 810AAAD0 ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 1\Option 2 cd Do not use this with anyother Play As Player 1 Option, only use one option at a time 810AAAD0 ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 1\Option 3 cd Do not use this with anyother Play As Player 1 Option, only use one option at a time 810AAAD0 ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Play As\Player 2\Option 1 cd Do not use this with anyother Play As Player 2 Option, only use one option at a time 810AAADC ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 2\Option 2 cd Do not use this with anyother Play As Player 2 Option, only use one option at a time 810AAADC ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 2\Option 3 cd Do not use this with anyother Play As Player 2 Option, only use one option at a time 810AAADC ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Play As\Player 3\Option 1 cd Do not use this with anyother Play As Player 3 Option, only use one option at a time 810AAAE8 ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 3\Option 2 cd Do not use this with anyother Play As Player 3 Option, only use one option at a time 810AAAE8 ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 3\Option 3 cd Do not use this with anyother Play As Player 3 Option, only use one option at a time 810AAAE8 ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Play As\Player 4\Option 1 cd Do not use this with anyother Play As Player 4 Option, only use one option at a time 810AAAF4 ???? 0001:"Rock",0002:"SCSA",0003:"Undertaker",0004:"Kane",0005:"Richards",0006:"Mankind",0007:"Cactus",0008:"Mick",0009:"HBK",0101:"HHH",0102:"X-Pac",0103:"Mr. Ass",0104:"Road Dogg",0201:"Benoit",0202:"Malenko",0203:"Saturn",0204:"Guerrero",0301:"Jericho",0302:"Angle",0303:"Tazz",0304:"Test",0305:"GodFather",0306:"D`Lo",0307:"Venis",0308:"Shamrock" cn Play As\Player 4\Option 2 cd Do not use this with anyother Play As Player 4 Option, only use one option at a time 810AAAF4 ???? 0401:"Rikishi",0402:"Sexay",0403:"Scotty",0404:"Edge",0405:"Christian",0406:"Matt",0407:"Jeff",0501:"Faarooq",0502:"Bradshaw",0503:"D-Von",0504:"Buh Buh",0505:"Hardcore",0506:"Crash",0507:"Bossman",0508:"Albert",0601:"Al",0602:"Blackman",0603:"Bulldog",0604:"Henry",0605:"Viscera",0606:"Andre",0607:"Buchanan",0608:"Rios",0609:"Taka",0701:"Chyna" cn Play As\Player 4\Option 3 cd Do not use this with anyother Play As Player 4 Option, only use one option at a time 810AAAF4 ???? 0702:"Stephanie",0703:"Tori",0704:"Debra",0705:"Trish",0706:"Lita",0801:"Jacqueline",0802:"Linda",0803:"Kat",0804:"Moola",0805:"Ho",0901:"Vince",0902:"Shane",0903:"Hebner",0904:"Jim Ross" cn Cannot Be Grabbed\Player 1 D115AEC6 0052 8115AEC6 0001 D115AEC6 00A1 8115AEC6 00C1 cn Cannot Be Punched\Player 1 D115AEC6 002D 8115AEC6 0001 D115AEC6 0035 8115AEC6 00C1 cn Cannot Be Knocked Down\Player 1 D115AEC6 0031 8115AEC6 0001 cn Wrestler Size & Shape\Player 1\Thin wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B468 3D80 cn Wrestler Size & Shape\Player 1\Wide wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B468 3FFF cn Wrestler Size & Shape\Player 1\Short wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B47C 3E80 cn Wrestler Size & Shape\Player 1\Tall wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B47C 3FFF cn Wrestler Size & Shape\Player 1\Flat wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B490 3D80 cn Wrestler Size & Shape\Player 1\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B490 3FFF cn Wrestler Size & Shape\Player 1\Giant wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8106B4A4 3E80 cn Wrestler Size & Shape\Player 1\Small wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8106B4A4 3FFF cn Wrestler Size & Shape\Player 2\Thin wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B528 3D80 cn Wrestler Size & Shape\Player 2\Wide wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B528 3FFF cn Wrestler Size & Shape\Player 2\Short wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B53C 3E80 cn Wrestler Size & Shape\Player 2\Tall wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B53C 3FFF cn Wrestler Size & Shape\Player 2\Flat wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B510 3DFF cn Wrestler Size & Shape\Player 2\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B510 3FFF cn Wrestler Size & Shape\Player 2\Giant wrestler cd Do not use this with anyother Size & Shape Player 2 Option, only use one option at a time 8006B564 3E80 cn Wrestler Size & Shape\Player 2\Small wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B564 3FFF cn Wrestler Size & Shape\Player 3\Thin wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5E8 3D80 cn Wrestler Size & Shape\Player 3\Wide wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5E8 3FFF cn Wrestler Size & Shape\Player 3\Short wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5FC 3E80 cn Wrestler Size & Shape\Player 3\Tall wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B5FC 3FFF cn Wrestler Size & Shape\Player 3\Flat wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B610 3D80 cn Wrestler Size & Shape\Player 3\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B610 3FFF cn Wrestler Size & Shape\Player 3\Giant wrestler cd Do not use this with anyother Size & Shape Player 3 Option, only use one option at a time 8006B624 3E80 cn Wrestler Size & Shape\Player 3\Small wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B624 3FFF cn Wrestler Size & Shape\Player 4\Thin wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6A8 3D80 cn Wrestler Size & Shape\Player 4\Wide wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6A8 3FFF cn Wrestler Size & Shape\Player 4\Short wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6BC 3E80 cn Wrestler Size & Shape\Player 4\Tall wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6BC 3FFF cn Wrestler Size & Shape\Player 4\Flat wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6D0 3D80 cn Wrestler Size & Shape\Player 4\Bulgy wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6D0 3FFF cn Wrestler Size & Shape\Player 4\Giant wrestler cd Do not use this with anyother Size & Shape Player 4 Option, only use one option at a time 8006B6E4 3E80 cn Wrestler Size & Shape\Player 4\Small wrestler cd Do not use this with anyother Size & Shape Player 1 Option, only use one option at a time 8006B6E4 3FFF cn Z LADDER cd Press Z for the ladder to appear, sometimes there is an invisable ladder D1064880 2000 8116C768 0000 D1064880 2000 8116C76A 0019 D1064880 2000 8116C76C 0000 D1064880 2000 8116C76E 0019 D1064880 2000 8116C788 8104 cn Replace Raw War with\TOKYO DOME cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 810528F4 7223 810528F6 0119 81050124 0100 81050126 0100 81050128 0100 8105012A 0100 8105012C 0100 8105012E 0100 81050130 0100 81050132 0100 81050134 0100 81050136 0100 8105010E 0999 81050400 03A5 81050402 0385 81050404 0385 81050406 0385 81050408 0385 8105040A 03A5 8105040C 03A5 8105040E 043F 81050430 043F 8105042C 03A5 81050430 21A5 81050432 0100 81050434 0000 81050436 2CFB 81050438 0899 8105043C 03AF 81050440 03AF 81050442 03A5 810500E8 24C3 81050444 0100 81050190 09EF 81050192 0000 81050194 09EF 81050196 2CFD cn Replace Raw War with\BARBEDWIRE ROPES cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050110 04F3 81050112 04F4 81050114 04F5 81050116 04F3 81050118 04F4 8105011A 04F5 8105011C 04F3 8105011E 04F4 81050120 04F5 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81079D90 3F6C 81079D94 3F48 81079DA4 3D10 81079DB8 3F71 81079E6C 3F6C 81079E80 3D10 81079E90 3F47 81079F48 3F6C 81079F4C BF4C 81079F5C 3D10 81079F70 3F71 8107A024 3F6C 8107A028 3F28 8107A038 3D10 8107A04C 3F71 8107A100 3F6C 8107A114 3D10 8107A124 3F23 8107A1DC 3F6C 8107A1E0 BF2A 8107A1F0 3D10 8107A204 3F71 8107A2B8 3F6C 8107A2BC 3F02 8107A2CC 3D10 8107A2E0 3F71 8107A394 3F6C 8107A3A8 3D10 8107A3B8 3F00 8107A470 3F6C 8107A474 BF02 8107A484 3D10 8107A498 3F71 81050144 0569 81050154 07F7 810528F4 0C01 810528F6 0555 81050140 04F4 81050150 2CFB 8107A628 3F60 8107A63C 3D10 8107A64C 3F52 8107A650 BF80 8107A8BC 3F56 8107A8C4 BA00 8107A8D0 3D10 8107A8DC 3C5A 8107A8E0 3F30 8107A8E4 BF80 8107ADE4 3F56 8107ADEC BA00 8107ADF8 3D10 8107AE04 3C5A 8107AE08 3F0E 8107AE0C BF80 8107AB7C 3F00 D115AF56 2EB2 8115AEC6 0017 D115B2AE 2EB2 8115B21E 0017 D115B606 2EB2 8115B570 0017 D115B95E 2EB2 8115B8CE 0017 81052922 FFFF 81052924 FFFF 81052926 FFFF cn Replace Raw War with\BARBEDWIRE SQUARE\Part 1 cd Both Parts must be on for this Press the C Left Button to make your opponent bleed,These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050110 04F3 81050112 04F4 81050114 04F5 81050116 04F3 81050118 04F4 8105011A 04F5 8105011C 04F3 8105011E 04F4 81050120 04F5 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81079D90 3F6C 81079D94 3F48 81079DA4 3D10 81079DB8 3F71 81079E6C 3F6C 81079E80 3D10 81079E90 3F47 81079F48 3F6C 81079F4C BF4C 81079F5C 3D10 81079F70 3F71 8107A024 3F6C 8107A028 3F28 8107A038 3D10 8107A04C 3F71 8107A100 3F6C 8107A114 3D10 8107A124 3F23 8107A1DC 3F6C 8107A1E0 BF2A 8107A1F0 3D10 8107A204 3F71 8107A2B8 3F6C 8107A2BC 3F02 8107A2CC 3D10 8107A2E0 3F71 8107A394 3F6C 8107A3A8 3D10 8107A3B8 3F00 8107A470 3F6C 8107A474 BF02 8107A484 3D10 8107A498 3F71 81050144 0569 81050154 07F7 810528F4 0C01 810528F6 0555 81050140 04F4 81050150 2CFB 8107A628 3F60 8107A63C 3D10 8107A64C 3F52 8107A650 BF80 8107A8BC 3F56 8107A8C4 BA00 8107A8D0 3D10 8107A8DC 3C5A 8107A8E0 3F30 8107A8E4 BF80 8107ADE4 3F56 8107ADEC BA00 8107ADF8 3D10 8107AE04 3C5A 8107AE08 3F0E 8107AE0C BF80 8107AB7C 3F00 D115AF56 2EB2 8115AEC6 0017 D115B2AE 2EB2 8115B21E 0017 D115B606 2EB2 8115B570 0017 D115B95E 2EB2 8115B8CE 0017 81052922 FFFF 81052924 FFFF 81052926 FFFF 8116C330 0000 8116C332 000A 8116C334 0000 8116C336 000A 8116C378 42B4 cn Replace Raw War with\BARBEDWIRE SQUARE\Part 2 cd Both Parts must be on for this Press the C Left Button to make your opponent bleed,These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8116C382 0000 8116C38C FFFF 81052C9C 0672 81052CA4 2CFB D1064880 0002 8115B21E 002F D1064886 0002 8115AEC6 002F 8116C3E4 0000 8116C3E6 000C 8116C3E8 0000 8116C3EA 000C 8116C428 C3D4 8116C440 FFFF 81052CB2 2CC2 81052CB4 0805 81052CB6 2CFB D1064880 2000 8116C3E6 001F D1064880 2000 8116C3EA 001F D1064880 2000 81005592 3F81 D1005592 3F81 8116C3E6 001F D1064880 2000 81005592 3F81 D1005592 3F81 8116C3EA 001F D1064886 2000 8116C3E6 001F D1064886 2000 8116C3E6 001F D1064886 2000 81005592 3F81 D1005592 3F81 8116C3EA 001F 81052CF8 04F4 81052D00 2CFB 8116C3E4 0000 8116C3E6 0015 8116C3E8 0000 8116C3EA 0015 8116C428 0000 8116C42A 0000 8116C42C 43EB 8116C42E 0000 8116C430 C3A6 8116C432 0000 8116C436 0400 8116C43A 0000 8116C43E 0000 8116C440 FFFF 8116C442 0000 810855A8 3F00 81085684 3F00 81085750 3F00 8108583C 3F00 81050100 2CFB 8105010E 2CFB cn Replace Raw War with\FLAMING TURNBUCKLES cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8116C334 FFFF 8116C336 001F 8116C374 C350 8116C376 FFF3 8116C378 4377 8116C37A 2689 8116C37C C380 8116C37E 0406 8116C382 0D14 8116C386 0FCC 8116C38A 07DC 8116C38C FFFF 8116C38E FDE3 8116C3E8 FFFF 8116C3EA 001F 8116C428 C360 8116C42C 4370 8116C430 4376 8116C436 0D14 8116C43A 0FCC 8116C43E 07DC 8116C442 F9C4 8116C49C FFFF 8116C49E 001F 8116C4DC 4360 8116C4E0 4370 8116C4E4 4380 8116C4EA 0CD0 8116C4EE 0136 8116C4F2 04EE 8116C4F6 F601 8116C550 FFFF 8116C552 001F 8116C590 434F 8116C594 4370 8116C598 C36C 8116C59E 0E70 8116C5A2 0F58 8116C5A6 0814 8116C5AA F1E6 cn Replace Raw War with\REMOVE RING cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050150 0000 81050152 0000 81050154 0000 810500E8 0000 810855A8 3F00 81085684 3F00 81085750 3F00 8108583C 3F00 81079C08 3F00 81079C14 3F00 81079B10 3F00 cn Replace Raw War with\BACKYARD ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105010E 0F76 8105010C 0F76 810482E8 002F 81050150 2CFD 810528F4 33FF 810528F6 33FF 81050152 2DC7 81050114 04F4 81050116 04F5 8105011E 04F3 81050128 07FF 8105012A 07FF 81050132 07FF 81079F48 400C 81079F5C 3F00 81079F70 3FFF 8107A024 4010 8107A038 3F00 8107A04C 4020 8107A060 3F84 8107A394 4012 8107A3A8 3F00 8107A3BC 4030 8107A3D0 3F84 8105042C 0949 81050436 07FF 81050438 07FF 8105043A 07FF 8105043C 0000 8105043E 07FF 81050440 0949 81050442 0949 81050430 0F76 81050128 07FF 8105012A 07FF 8105012C 0000 8105012E 07FF 81050130 07FF 81050132 07FF 81050134 0000 81050136 08F9 81050196 2CFD 81050194 09EF 81050192 0000 81050190 09EF 8116C49E 0019 8116C4B8 0004 8116C4DC C2E1 8116C4E0 42B4 810500FE 2D2D 81050100 2D2D 81050102 2D2D 81050400 2DC7 81050402 2DC7 81050404 2DC7 81050406 2DC7 81050408 2DC7 8105040A 2DC7 8105040C 2DC7 8105040E 2DC7 50001002 0000 810501B8 0000 50000402 0000 810501E0 0000 50000902 0000 81050262 0000 50001402 0000 81050290 0000 50002C02 0000 810502EC 0000 8107941C 3FE0 81079428 3FFF 810500EC 06FE 810500EE 06FD 810500F8 07FF 810500FA 0997 81050110 06FC 81050112 06FB 8105011A 06FF 8105011C 06FA 81052CF0 2CC9 81052CF4 2D1B 81052CD0 2CD1 81052CD4 0963 81052C84 2CBF 81052C8A 0961 81052CB8 2CC4 81052CBC 2DD7 81052CC8 2CD1 81052CCC 2CFB 81052C78 2CBC 81052C80 2D31 81052CF8 2CC1 81052D00 2DD7 cn Replace Raw War with\BACKYARD WEAK cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 0E88 8105042E 2D0D 81050430 2D0D 81050432 2D0D 81050434 2D0D 81050436 07FD 8105043A 2CFB 8105043C 2D0D 8105043E 2D0D 81050440 2D0D 81050442 2D0D 810500E8 2D0D 8105010E 2D0D 8105010C 2D0D 81050150 2D0D 81050196 2CFB 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81050136 2CFB 81050400 2D0D 81050402 2D0D 81050404 2D0D 81050406 2D0D 81050408 2D0D 8105040A 2D0D 8105040C 2D0D 8105040E 2D0D 810528F4 2D0D 810528F6 2D0D 81052CE8 2CC9 81052CEC 2D2D cn Replace Raw War with\BARBEDWIRE ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 2CFB 8105042E 2CFB 81050430 2CFB 81050432 2CFB 81050434 2CFB 81050436 2CFB 81050438 2CFB 8105043A 2CFB 8105043C 2CFB 8105043E 2CFB 81050440 2CFB 81050442 2CFB 810500E8 2CFB 8105010E 2CFB 8105010C 2CFB 81050150 2CFB 81050196 2CFB 81050124 2CFB 81050126 2CFB 81050128 2CFB 8105012A 2CFB 8105012C 2CFB 8105012E 2CFB 81050130 2CFB 81050132 2CFB 81050134 2CFB 81050136 2CFB 810528F4 DDDD 810528F6 DDDD 81052CE8 2CCA 81052CEC 2CFB 81050400 2CFB 81050402 2CFB 81050404 2CFB 81050406 2CFB 81050408 2CFB 8105040A 2CFB 8105040C 2CFB 8105040E 2CFB cn Replace Raw War with\DUDLEY ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 21A7 8105042E 2D0D 81050432 2D0D 81050436 21A7 8105043E 2D0D 81050440 0000 81050442 0000 810500E8 2D0D 8105010C 2CFD 8105010E 2CFD 81050150 2D29 81050152 2CFB 81050400 09EF 81050402 09EF 81050404 0000 81050406 0000 81050408 0000 8105040A 0000 8105040C 09EF 8105040E 09EF 81050188 04F6 8105018A 04F7 8105018C 04F8 8105018E 04F9 81050190 09EF 81050192 0000 81050194 09EF 81050196 2D0D 810528F4 6666 810528F6 6666 81052CE8 2CC2 81052CEC 2D0D 81052D1C 2CD3 81052D1E 2CD4 81052D20 2CD5 81052D22 2CD6 81052D24 2CFD 81052D26 2CFD 81052D28 2CFB 81052D2A 2CFB 81050124 2CFD 81050126 2CFD 81050128 2CFD 8105012A 2CFD 8105012C 2CFD 8105012E 2CFD 81050130 2CFD 81050132 2CFD 81050134 2CFD 81050136 2CFD 81050154 2CFB 811533F8 002E cn Replace Raw War with\FLAME ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105010E 0EFE 8105010C 0EFE 810528F4 2508 810528F6 2508 81050430 2401 81050430 2401 81050404 2401 81050406 2401 81050408 2401 81050409 2401 8105040A 2401 8105040C 2401 810500E8 2401 cn Replace Raw War with\GREENWICH STREET ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 81050430 2DC5 81050436 0000 81050438 0000 8105043A 0000 8105043E 0000 810504E8 0EFE 8105010E 2DC5 8105010C 2DC5 81050196 2CFD 81050136 0FB6 81050134 0FC6 81050132 0FB6 81050130 0FC6 8105012E 0FB6 8105012C 0FC6 8105012A 0FB6 81050128 0FC6 81050126 0FB6 81050124 0FC6 81050440 0000 81050442 0000 50002C02 0000 81050378 0000 50002C02 0000 810502EC 0000 50001402 0000 81050290 0000 50000902 0000 81050262 0000 50000402 0000 810501CE 0000 50001002 0000 810501B8 0000 50000402 0000 810501E0 0000 8105042C 2D0D 81050430 0000 81050150 24F0 cn Replace Raw War with\HHH ARNEA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105040E 24EF 8105040C 24EF 8105040A 24EF 81050408 24EF 81050406 24EF 81050404 24EF 81050402 24EF 81050400 24EF 81050436 24E9 81050440 24E9 81050442 24E9 8105043E 24EF 8105042E 24EF 8105043C 24EF 8105042C 24E9 8105010E 24E9 8105010C 24E9 81050196 24E9 8105042E 24EF 81050432 24EF 810500F8 24EF 810500FA 24EF 810500FC 24EF 810500FC 24EF 81050100 24EF 81050100 24EF 81052CE8 2CCA 81052CEC 24EF 81050150 24E9 81050152 24E9 81050154 24E9 810528F4 24E9 810528F6 24E9 cn Replace Raw War with\HOSPITAL ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 0949 8105042E 283F 81050428 0949 81050430 0949 81050430 0949 81050436 096B 81050438 0993 8105043A 096B 8105043E 283F 81050440 283F 81050442 283F 810504E8 0949 81050150 283F 81050196 283F 81050400 283F 81050402 283F 81050404 283F 81050406 283F 81050408 283F 8105040A 283F 8105040C 283F 8105040E 283F 810500F8 283F 810500FA 283F 810500FC 283F 810500FE 283F 81050100 283F 81050100 283F 81052CE8 2CCA 81052CEC 283F 8105010E 283F 8105010C 283F 81050124 0949 81050126 0949 81050128 0949 8105012A 0949 8105012C 0949 8105012E 0949 81050130 0949 81050132 0949 81050134 0949 81050136 0949 810500E8 0949 810528F4 0000 81052CE0 2CC9 cn Replace Raw War with\KANE ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 0A61 8105042E 0A61 81050428 2B6C 81050430 2B6C 81050430 2B6C 81050436 2B57 81050438 2B57 8105043A 2B57 8105043E 0A61 81050440 2B57 81050442 2B57 810500E8 1B1E 8105010E 2D37 8105010C 209F 81050194 0955 81050196 2B57 81050400 2699 81050402 2699 81050404 2699 81050406 2699 81050408 2699 8105040A 2699 8105040C 2699 8105040E 2699 cn Replace Raw War with\SHIMMER ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 1932 8105042E 1932 81050430 1932 81050434 1932 81050432 1932 81050436 1932 81050438 1932 8105043A 1932 8105043E 1932 81050440 1932 81050442 1932 81050150 1932 81050152 1932 81050154 1932 81050190 1932 81050192 1932 81050194 1932 81050196 1932 81050124 1932 81050126 1932 81050128 1932 8105012A 1932 8105012C 1932 8105012E 1932 81050130 1932 81050132 1932 81050134 1932 81050136 1932 810500E8 1932 8105010E 1932 8105010C 1932 cn Replace Raw War with\SPACE SHIP ARENA cd These Replace Raw War Arena With what ever coice you make. Only use 1 option at a time. 8105042C 094D 8105042E 0953 81050430 0953 81050432 0F0E 81050434 0953 81050436 0F0E 81050438 0899 8105043C 0953 8105043E 0899 81050440 0963 81050442 0963 81050400 0953 81050402 0953 81050404 0953 81050406 0953 81050408 0953 8105040A 0953 8105040C 0953 8105040E 0953 810500E8 0A75 810528F4 7223 810528F6 0119 81050150 0963 81050152 0963 81050190 0953 81050192 0953 81050194 0953 81050196 0963 8105010E 0F0E 8105010C 0F0E 81050124 0F10 81050126 0F10 81050128 0F10 8105012A 0F10 8105012C 0F10 8105012E 0F10 81050130 0F10 81050132 0F10 81050134 0F10 81050136 0F10 810500F8 0963 810500FA 0963 810500FC 0963 810500FE 0963 81050100 0963 81050102 0963 81052CE8 2CCA 81052CEC 0963 cn Tables\IN RING TABLE\Part 1 cd To Make the Table look broken Keep the Z Button press down, To make player stand on the Table, Stand next to it & Keep C-Right Pressed Down.Put all Parts on Together for this Cheat to work 81052CF0 06E1 81052CF4 09F1 81052CF8 06E2 81052D00 09F1 81052D0C 06E3 81052D0E 06E4 81052D10 09EF 81052D12 09EF 81052D14 06E5 81052D16 06E6 81052D18 09EF 81052D1A 09EF D1064880 0001 8115AFB0 432C D1064880 0001 8115B308 432C D1064880 2000 8115AFB0 42B4 D1064880 2000 8115B308 42B4 8116C330 0000 8116C332 0014 8116C334 0000 8116C336 0014 8116C374 4210 8116C376 C0B1 8116C378 432F 8116C37A 51DC 8116C37C 4210 8116C37E 92F1 8116C382 0800 8116C386 05A0 8116C38A 0800 8116C38C FFFF 8116C38E F3BC 8116C3E4 0000 8116C3E6 0015 8116C3E8 0000 8116C3EA 0015 8116C428 4210 8116C42A C0B1 8116C42C 432F 8116C42E 51DC 8116C430 4210 8116C432 92F1 8116C436 0800 8116C43A 05A0 8116C43E 0800 8116C440 FFFF 8116C442 F3BC D1064880 2000 8116C378 42E0 cn Tables\IN RING TABLE\Part 2 cd To Make the Table look broken Keep the Z Button press down, To make player stand on the Table, Stand next to it & Keep C-Right Pressed Down.Put all Parts on Together for this Cheat to work D1064880 2000 8116C382 07E0 D1064880 2000 8116C38A 0680 D1064880 2000 8116C42C 42E0 D1064880 2000 8116C436 0820 D1064880 2000 8116C43E 0980 8116C498 0000 8116C49A 0017 8116C49C 0000 8116C49E 0017 8116C4DC 4210 8116C4DE C0B1 8116C4E0 432A 8116C4E2 51DC 8116C4E4 4210 8116C4E6 92F1 8116C4EA 0800 8116C4EE 05A0 8116C4F2 0800 8116C4F4 FFFF 8116C4F6 F3BC 8116C54C 0000 8116C54E 0018 8116C550 0000 8116C552 0018 8116C590 4210 8116C592 C0B1 8116C594 432A 8116C596 51DC 8116C598 4210 8116C59A 92F1 8116C59E 0800 8116C5A2 05A0 8116C5A6 0800 8116C5A8 FFFF 8116C5AA F3BC D1064880 2000 8116C4E0 42E0 D1064880 2000 8116C4EA 07E0 D1064880 2000 8116C4F2 0680 D1064880 2000 8116C594 42E0 D1064880 2000 8116C59E 0820 D1064880 2000 8116C5A6 0980 cn Novalty\Truck In The Crowd 81050110 0747 81050112 0748 81050114 0749 81050116 074A 81050118 074B 81050124 0A4B 81050126 0A43 81050128 0A4B 8105012A 0A43 8105012C 0A43 8105012E 0A43 8105011A 074C 8105011C 074D 81050130 0A43 8105011E 074E 81050132 0A43 81050120 0746 81050134 0A4B 81050122 0743 81050136 0A4B D1064880 2000 8115AFB0 42EE D1064880 2000 8115B308 42EE cn CPU To Human Control\Player 4 8015B9A1 ???? 0017:"Human",0018:"CPU" cn Clock At 00:00 8115AB1E 0000 810A99F2 0000 cn Hacked Moves\Dragon Screw Stunner cd Dragon Screw 02 P1 does a Dragon Screw then picks up P2 (still holding his leg) and spins him around and gives him a Stone Cold Stunner D106B454 3749 D106B456 0094 8106B460 00E9 D106B454 3749 D106B456 0094 8106B462 B9BE D106B514 374A D106B516 0094 8106B520 00E9 D106B514 374A D106B516 0094 cn Hacked Moves\Morality Check to Back of head cd Replaces: Back Clothesline P1 is immediately backed up and does the Morality Check to P2 in the back of the head (misses by a little) D106B454 3892 D106B456 0000 8106B460 00B3 D106B454 3892 D106B456 0000 8106B462 194C cn Hacked Moves\Dragon Screw Suplex cd Replaces: Double Dragon Screw 02 P1 does a Dragon screw then picks then up (still holding their feet) and does a capture suplex. D106B454 3749 D106B456 007C 8106B460 00AD D106B454 3749 D106B456 007C 8106B462 DB2A D106B514 374A D106B516 007C 8106B520 00AD D106B514 374A D106B516 007C 8106B522 EAE0 D106B454 3749 D106B456 00A5 8115AF52 0000 D106B514 374A D106B516 00A5 8115B2AA 0000 cn Hacked Moves\Dominator into HHH Facebuster cd Replaces: Dominator D106B454 3810 D106B456 005C 8106B560 011A D106B454 3810 D106B456 005C 8106B562 A256 D106B514 3811 D106B516 005C 8106B520 011A D106B514 3811 D106B516 005C 8106B522 ACB0 D106B454 3810 D106B456 0075 8115AF52 0000 cn Hacked Moves\Capture Tazzplex cd Replaces: Capture Suplex P1 grabs P2's feet like a capture suplex, then lets go & does a Tazzplex. D106B454 3689 D106B456 0021 8106B460 00BC D106B454 3689 D106B456 0021 8106B462 A5E2 D106B514 368A D106B516 0021 8106B520 00BC D106B514 368A D106B516 0021 8106B522 B6BE cn Hacked Moves\Running Rock Bottom cd Replaces: Farooq Spinebuster P2 runs into P1 and P1 delivers a RockBottom to P2. D106B454 3A80 D106B456 0000 8106B460 00C1 D106B454 3A80 D106B456 0000 8106B462 F7A2 D106B514 3A81 D106B516 0000 8106B520 00C2 D106B514 3A81 D106B516 0000 8106B522 1210 cn Hacked Moves\Running Tazplex cd Replaces: Underhook Belly to Belly P2 runs into P1 and P1 does a Tazplex to P2. D106B454 3A7A D106B456 0000 8106B460 00BC D106B454 3A7A D106B456 0000 8106B462 A51E D106B514 3A7B D106B516 0000 8106B520 00BC D106B514 3A7B D106B516 0000 8106B522 B5FA cn Tables\MOVABLE TABLES\Part 1 cd You must use both parts for this cheat to work 81052C24 06E1 81052C26 06E3 81052C2C 09F1 81052C2E 09EF 81052C30 06E2 81052C32 06E5 81052C38 09F1 81052C3A 09EF 81052C48 06E4 81052C4A 06E6 81052C50 09EF 81052C52 09EF 8116C3E4 0000 8116C3E6 0001 8116C3E8 0000 8116C3EA 0001 8116C498 0000 8116C49A 0003 8116C49C 0000 8116C49E 0003 8116C330 0000 8116C332 0000 8116C334 0000 8116C336 0000 D116C556 0000 8116C33A 0000 D116C33A 0000 8116C3EE 0000 D116C3EE 0000 8116C4A2 0000 D116C556 0001 8116C33A 0001 D116C33A 0001 8116C3EE 0001 D116C3EE 0001 8116C4A2 0001 D116C556 0002 8116C33A 0002 D116C33A 0002 8116C3EE 0002 D116C3EE 0002 8116C4A2 0002 D116C556 0003 8116C33A 0003 D116C33A 0003 8116C3EE 0003 D116C3EE 0003 8116C4A2 0003 D116C556 FFFF 8116C33A FFFF D116C33A FFFF 8116C3EE FFFF D116C3EE FFFF 8116C4A2 FFFF D216C556 FFFF 81079B10 3F80 D1064886 2000 81079B10 3F81 D106488C 2000 81079B10 3F81 D1064892 2000 81079B10 3F81 cn Tables\MOVABLE TABLES\Part 2 cd You must use both parts for this cheat to work D116C33A FFFF 8116C382 0000 D116C382 0000 8116C386 0000 D116C386 0000 8116C38A 0000 D116C38A 0000 8116C38E 0000 D116C38E 0000 8116C436 0000 D116C436 0000 8116C43A 0000 D116C43A 0000 8116C43E 0000 D116C43E 0000 8116C442 0000 D116C442 0000 8116C4EA 0000 D116C4EA 0000 8116C4EE 0000 D116C4EE 0000 8116C4F2 0000 D116C4F2 0000 8116C4F6 0000 D116C594 42B4 D116C556 FFFF 8116C378 4335 D116C378 4335 8116C42C 4335 D116C42C 4335 8116C4E0 4335 D116C594 3DC7 D116C556 FFFF 8116C378 42B0 D116C378 42B0 8116C42C 42B0 D116C42C 42B0 8116C4E0 42B0 D1064880 2000 81079B10 3F81 D1079B10 3F81 D116C594 42B4 D116C556 FFFF 8116C378 42F0 D116C378 42F0 8116C42C 42F0 D116C42C 42F0 8116C4E0 42F0 D1079B10 3F81 8116C38A 0F00 D116C38A 0F00 8116C43E 0100 D116C594 3C93 8116C378 42B0 81052D18 0000 81052D1A 0000 D116C54C 0000 8116C54E 0018 D116C550 0000 8116C552 0018 cn Tables\Sabu Table cd Breakable/Fixable/Rebreakable/Refixable press Z to break, C-right + Cdown to fix 8116C49A 000C 8116C49E 000C 8116C4DC 43CC 8116C4E0 42E6 8116C4E4 C2C5 8116C4EE 0800 8116C602 000C 8116C606 000C 8116C648 42E6 8116C644 43CC 8116C64C C314 81052C54 06E3 81052C5C 09EF 8116C6F8 43CC 8116C6FC 42F0 8116C700 C2F1 8116C70A 0400 8116C428 43CC 8116C430 C2D0 8116C42C 42F0 8116C43A 0C00 8116C6B6 0004 8116C6BA 0004 8116C3E6 0004 8116C3EA 0004 D1064880 2000 81005592 3F81 D1005592 3F81 8116C4EA 0F00 D1005592 3F81 8116C652 0100 D1005592 3F81 8116C4E0 4240 D1005592 3F81 8116C648 4240 D1064880 0005 81005CD4 3F83 D1005CD4 3F83 8116C4EA 0000 D1005CD4 3F83 8116C652 0000 D1005CD4 3F83 8116C4E0 42E6 D1005CD4 3F83 8116C648 42E6 D1005CD4 3F83 D1064880 2000 81005CD4 0000 crc C71353BE-AA09A6EE-C:50 gn WWF WrestleMania 2000 (E) cn Have All Characters 8109ED5A FFFF cn Infinite Create-A-Wrestler Attribute Points 8011A81B 001E cn Timer Is Always 00:00 8016F0AF 0000 cn Max Attributes 8011A811 0032 8011A813 0032 8011A815 0032 8011A817 0032 8011A819 0032 cn Weapon Select\Player 1 81167236 0300 81166D90 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 81166D92 0000 80166E50 0000 cn Weapon Select\Player 2 811676CA 0300 81166DC0 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 80166DC2 0001 80166E51 0001 cn Weapon Select\Player 3 81167B5E 0300 81166DF0 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 80166DF2 0002 80166E52 0002 cn Weapon Select\Player 4 81167FF2 0300 81166E18 ???? 0000:"Broom",0101:"Shovel",0202:"Red And White Hockey Stick",0303:"Guitar",0404:"Night Stick",0505:"Head",0606:"Black Hockey Stick",0707:"Bottle",0808:"2x4",0909:"Big Purple Sheet",0A0A:"White Jug",0B0B:"Suit Case",0C0C:"Stick",0D0D:"Head",0E0E:"Big Mallot",0F0F:"Black Microphone",1010:"BaseBall Bat",1111:"Folding Chair",1212:"Board",1313:"Stairs",1414:"Trashcan",FFFF:"Nothing" 81166E1A 0003 80166E53 0003 cn Always Special\Player 1 80167235 0004 cn Always Special\Player 2 801676C9 0004 cn Always Special\Player 3 80167B5D 0004 cn Always Special\Player 4 80167FF1 0004 cn Specials Don't Run Out 8112AD94 2400 cn Max Spirit\Player 1 801671F5 00FF cn Always Normal Spirit\Player 1 801671F5 0032 cn No Spirit\Player 1 801671F5 0000 cn Max Spirit\Player 2 80167689 00FF cn Always Normal Spirit\Player 2 80167689 0032 cn No Spirit\Player 2 80167689 0000 cn Max Spirit\Player 3 80167B1D 00FF cn Always Normal Spirit\Player 3 80167B1D 0032 cn No Spirit\Player 3 80167B1D 0000 cn Max Spirit\Player 4 80167FB1 00FF cn Always Normal Spirit\Player 4 80167FB1 0032 cn No Spirit\Player 4 80167FB1 0000 cn Ultimate Codes\Player 1 801671F4 0064 cn Ultimate Codes\Player 2 80167688 0064 cn Ultimate Codes\Player 3 80167B1C 0064 cn Ultimate Codes\Player 4 80167FB0 0064 cn Easy Pins & Longer Submissions\Player 2 80167688 0064 cn Easy Pins & Longer Submissions\Player 3 80167B1C 0064 cn Easy Pins & Longer Submissions\Player 4 80167FB0 0064 cn Easy Pins & Longer Submissions\Player 1 801671F4 0064 crc 0A1667C7-293346A6-C:50 gn Xena Warrior Princess - Talisman of Fate (E) cn Infinite Health\Player 1 810B5EF0 42C8 cn Invisibility\Player 1 810BF3A2 0001 cn Infinite Health\Player 2 810B60D4 42C8 cn 1 Win To Win\Player 1 D00C0983 0000 800C0983 0001 cn 1-Hit Death to Player 2\Player 1 D10B60D4 42C8 810B60D4 4080 cn Player 2 Has No Energy\Player 1 810B60D4 C080 cn P2 Never Wins\Player 1 800C0985 0000 cn Needs 1 Win To Win\Player 2 D00C0985 0000 800C0985 0001 cn 1-Hit Death to Player 1\Player 2 D10B5EF0 42C8 810B5EF0 4080 cn Player 1 Has No Energy\Player 2 810B5EF0 C080 cn P1 Never Wins\Player 2 800C0983 0000 cn Join River Team cd Select Quest Mode 810BF482 0001 cn Fight Forest Team cd Select Hardest Difficulty + Quest Mode 810BF482 0001 cn Unlock Titan Difficulty Level 810BF4D2 0001 crc D3F97D49-6924135B-C:50 gn Yoshi's Story (E) //--------------- PAL (A) Region Cheat Codes cn Infinite\Health cd This is for All Yoshis All levels 50000804 0000 800F954F 0008 cn Infinite\Lives cd This is for All Yoshis All levels 800F958F 00FF cn Infinite Eggs cd This is for All Yoshis All levels 80285078 0006 crc 155B7CDF-F0DA7325-C:55 gn BANJO TOOIE cn Infinite\Energy\Banjo and Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 81120584 0A0A cn Infinite\Energy\Snowball cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 80120587 0005 cn Infinite\Energy\Bee cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 80120593 000A 80120594 000A cn Infinite\Energy\Washing Machine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 81120596 0A0A cn Infinite\Energy\Stony cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 80120599 000A 8011B44A 000A cn Infinite\Energy\Banjo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 8012059F 000A 801205A0 000A cn Infinite\Energy\Kazooie cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 811205A2 0A0A cn Infinite\Energy\Submarine cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 801205A5 000A 801205A6 000A cn Infinite\Energy\Mumbo cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 811205A8 0A0A cn Infinite\Energy\Detonator cd With Infinite Energy On Avoid Picking up the ! Or ? Stop Energy Honey Combs or you will be stuck. 8011FFA9 0063 811205AE 0A0A cn Infinite\Energy\T-Rex Baby 8011FFA9 0063 801205BF 000A 801205C0 000A cn Infinite\Air 8112FDC2 42C8 cn Instant Warp\Options\Not sure cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8012C390 ???? 00FC:"Lord woo fak fak",00F9:"Mr Patch",0121:"Inside Chuffy's wagon",0134:"Mumbo's Skull",0135:"Humba Wumba's wigwam 1",0157:"Humba Wumba's wigwam 2",019B:"Jingalings Zombified Palace",01A6:"Smuggler cavern",0141:"Inside the digger tunnel",0143:"Bottles house",0169:"Bottles house still",018A:"HAG Inside",019A:"HAG1 Final Boss" 8012C393 0001 cn Instant Warp\Options\Cauldron Keep cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 015D:"Cauldron Keep",015E:"The gatehouse",015F:"Tower of Tragedy Quiz",0160:"Gun chamber",016A:"Gun room still",017B:"Crazy Castle Stockade balloon burst multi",017C:"Crazy Castle Stockade Jump the hoops multi",017D:"Grunty Industries packing game",0180:"Colosseum kickball arena",0186:"Dodgems" 8012C393 0001 cn Instant Warp\Options\Spiral Mountain cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 00AD:"Grunty's Old Lair",00AE:"Behind The Waterfall",00AF:"Top Of Castle",0173:"Banjo's house" 8012C393 0001 cn Instant Warp\Options\Jinjo Village cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 0142:"Jinjo Village",0144:"King Jingalings throne room",0143:"Bottles house",0145:"Green Jinjo's House",0146:"Black Jinjo's House",0147:"Yellow Jinjo's House",0148:"Blue Jinjo's House",014A:"Brown Jinjo's House",014B:"Orange Jinjo's House",014C:"Purple Jinjo's House",014D:"Red Jinjo's House",014E:"White Jinjo's House" 8012C393 0001 cn Instant Warp\Options\Mayahem Temple cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 00B6:"Humba's Wigwam",00B7:"Mumbo's skull",00B8:"The Temple",00B9:"Prison Compound",00BC:"Code chamber",00C4:"Jade Snake Grove",00C5:"Treasure Chamber",00C6:"Kickball Arena",0177:"Targitzan's Slighty Sacred Temple",0178:"Inside Targitzans Temple",0179:"Targitzan Temple Lobby",017A:"Targitzan's Temple Boss",017F:"Mayan Kickball Arena",0166:"Multi",0167:"Still",00C8:"Kickball Arena",00C9:"Kickball Arena" 8012C393 0001 cn Instant Warp\Options\Glitter Gulch Mine cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 00C7:"Mine",00CA:"Fuel depot",00CB:"Crushing shed",00CC:"Flooded caves",00CD:"Water storage",00CE:"Waterfall cavern",00CF:"Power hut basement",00D0:"Chuffy's cab",00D1:"Inside chuffy's boiler boss",00D2:"Gloomy caverns",00D3:"Generator caverns",00D4:"Power hut",00D5:"Wumba's wigwam",00D7:"Train station",00D8:"Prospectors hut",00D9:"Mumbo's hut",00DA:"Toxic gas cave",00DB:"Canary cave",00DC:"Ordnance storage",00E9:"Humba",0126:"Water supply pipe",0163:"Ordnance Storage entrance",0164:"Ordnance Storage game",0165:"Ordnance Storage game Multi",016F:"Testing",0170:"Testing",0171:"Mumbo's skull" 8012C393 0001 cn Instant Warp\Options\Witchy World cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 00D6:"Witcy World",00DD:"Dodgem dome lobby",00DE:"Dodgem challenge \"1 vs 1\"",00DF:"Dodgem challenge \"2 vs 1\"",00E0:"Dodgem challenge \"3 vs 1\"",00E1:"Crazy castle stockade",00E2:"Crazy castle lobby",00E3:"Crazy castle pump room",00E4:"Balloon burst game",00E5:"Hoop hurry game",00E6:"Star spinner",00E7:"The inferno",00EA:"Cave of horrors",00EB:"Haunted cavern",00EC:"Train station",0124:"Saucer of Peril",013B:"Crazy castle stockade \"sop\"",013C:"Star spinner \"sop\"",0176:"Mumbo's skull" 8012C393 0001 cn Instant Warp\Options\Jolly Roger's Lagoon cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 00ED:"Jolly's",00EE:"Pawno's emporium",00EF:"mumbo's skull",00F4:"Ancient Swimming Baths",00F6:"Electric Eels lair",00F7:"Seaweed Sanctum",00F8:"Inside the big fish",00FA:"temple of the fishes",01A8:"Atlantis",01A9:"Seabottom",0181:"sea bottom cavern",0182:"submarine multi",01A7:"Jolly Roger's Lagoon",00FF:"Blubber's wave race hire" 8012C393 0001 cn Instant Warp\Options\Terrydacty Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 0112:"Terrydacty Land",0113:"Terry's nest",0114:"Train station",0115:"Oogle boogles cave",0116:"Inside the mountain",0117:"River passage",0118:"Styracosaurus family cave",0119:"Unga bunga's cave",011A:"Stomping plains",011B:"Bonfire caverns",011E:"Humba's Wigwam",0123:"Inside chompa's belly",0183:"Chompa's belly multi" 8012C393 0001 cn Instant Warp\Options\Grunty Industries cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 0100:"Outside",0101:"Inside",0102:"Train station",0103:"Workers quarters",0104:"Trash compactor",0105:"Elevator shaft",0106:"Floor 2",0107:"Floor 2 \"electromagnet chamber\"",0108:"Floor 3",0109:"Floor 3 \"boiler plant\"",010A:"Floor 3 \"packing room\"",010B:"Floor 4",010C:"Floor 4 \"cable room\"",010D:"Floor 4 \"quality control\"",010E:"Floor 5",010F:"Basement",0110:"Basement \"repair depot",0111:"Basement \"waste disposal\"",0125:"Water supply pipe",0172:"Mumbo's skull",0162:"Floor 4 \"clinkers cavern\"",0187:"Sewer entrance" 8012C393 0001 cn Instant Warp\Options\Hailfire Peaks cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 0127:"Lava side",0128:"Icy side",0129:"Lava train station",012A:"Ice train station",012B:"Chilli billi",012C:"Chilly willy",012D:"Colosseum kickball stadium lobby",0131:"Boggy's igloo",0132:"Icicle grotto",0133:"Inside the volcano",0168:"Icy side still" 8012C393 0001 cn Instant Warp\Options\Cloud Cuckoo Land cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 0136:"Cloud Cuckoo Land 1",0137:"Inside the trashcan",0138:"Inside the cheesewedge",0139:"Zubba's nest",013A:"Central cavern",013D:"Inside the pot o gold",013E:"Mumbo's skull",013F:"Mingy jongo's skull",0140:"Humba wumba's wigwam",0161:"Cloud Cuckoo Land 2",0188:"Zubba's nest multi",0185:"Trash can mini" 8012C393 0001 cn Instant Warp\Options\Isle O Hags cd Only use one Instant Warp Option At once, Make sure the other is off before putting this one on D008B284 0000 8112C390 ???? 014F:"Wooded Hollow",0150:"Heggy's egg shed",0151:"Jiggywiggy's temple",0152:"Plateau",0153:"Plateau \"Honey B's Hive\"",0154:"Pine Grove",0155:"Cliff top",0156:"Cliff top Mumbo's skull",015A:"wasteland",015B:"inside another digger tunnel",015C:"Quagmire" 8012C393 0001 cn Play As cd To use this cheat, put the cheat on, then press L as you walk through a door to become that chosen character D108B284 0000 8012BD9C ???? 0001:"Banjo and Kazooie",0002:"Snowball",0006:"Bee",0007:"Washing machine",0008:"Stony",000A:"Banjo",000B:"Kazooie",000C:"Submarine",000D:"Mumbo",000E:"Golden Goliath",000F:"Detonator",0010:"Truck",0012:"T-rex baby",0013:"T-rex daddy" cn Beta Bottles Revenge Mode cd Bottles Revenge is a Beta mode from Banjo Tooie that the RWP team recently uncovered after an extraordinary amount of effort. Bottles the Spirit transforms into Bottles the Devil and posses enemies nearby and allows a second player hooked up to Pad 2 to play as that Posses character to try to foil Banjos Plans. As player one goes about its business, player two uses every enemy nearby to try to nab Banjo and take away some life. This mode is incredible, and you can control almost every enemy in the game: slot machines, flying creatures, uggers, zubbas...and this is just the beginning. (Congrats Rare Witch Project) 80130172 0001 8008B4D1 0002 crc 7BB18D40-83138559-C:55 gn Pokemon Snap (A) cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C2CD2 0006 crc 2483F22B-136E025E-C:55 gn Lylat Wars (A) cn Unlimited\Boost 8113E6FC 0000 8113E6FE 0000 811415DC 0000 811415DE 0000 8013E7FD 0000 801416DD 0000 cn Have All Medals cd For Expert & Normal Modes 50000802 0000 8017A9D9 7777 cn Infinite\Hyper Laser 80163B13 0002 cn Loads O' Hits 80163B03 00FF cn Infinite\Armor\Slippy 8017418B 00FF cn Infinite\Energy 80141587 00FF 8013E6A7 00FF cn Infinite\Lives 80163B09 0063 cn Unlimited\Smart Bombs 80179E0B 0063 cn Infinite\Armor\Falco 80174187 00FF cn Infinite\Armor\Peppy 8017418F 00FF cn Infinite\Dual Blue Lasers 80163C13 0002 cn Level Select 8017A29F ???? 0000:"Corneria",0001:"Meteo",0002:"Sector X",0003:"Area 6",0004:"Glitch",0005:"Sector Y",0006:"Venom 1",0007:"Solar",0008:"Zoness",0009:"Venom 2",000A:"Training Mode Level",000B:"Macbeth",000C:"Titania",000D:"Aquas",000E:"Fortuna",0010:"Katina",0011:"Bolse",0012:"Sector Z",0013:"Venom With Starwolf",0014:"Corneria (Multi)" cn 999 Kills 80163B03 00FF crc DD26FDA1-CB4A6BE3-C:55 gn Super Smash Bros. (A) //--------------- PAL (F) Region Cheat Codes cn Give Kirby A Wierd Blow-Up 8025E898 000A cn Story Mode\Skip Straight To Master Hand 800A5227 000D cn Story Mode\Infinite Time 810A526E 43CB cn Story Mode\Player 1\Infinite Lives 800A5283 0004 cn Story Mode\Player 2\Infinite Lives 800A52F7 0004 cn Story Mode\Player 3\Infinite Lives 800A536B 0004 cn Story Mode\Player 4\Infinite Lives 800A53DF 0004 cn Story Mode\Player 1\Low % Health 810A52C6 0000 cn Story Mode\Player 2\Low % Health 810A533A 0000 cn Story Mode\Player 3\Low % Health 810A53AE 0000 cn Story Mode\Player 4\Low % Health 810A5422 0000 cn Story Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code could also result freezing at the end of the Level. 800A527B ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A52EF ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A5363 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A53D7 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Story Mode\Player 1\Kirby B Button Move\Hyrule Castle 8026924F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Yoshi's Island 8026958F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Sector Z 80271837 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Peach's Castle 802644DF ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Saffron City 802741D7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Congo Jungle 8027120F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Kirby's Dreamland 8026E27F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Planet Zebes 802706E7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Metal Mario Stage 80263CD7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Fighting Polygon Team 80262E5F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn Story Mode\Player 1\Kirby B Button Move\Master Hand Stage 8027238F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Infinite Time 810A545E 43CB cn VS. Mode\Player 1\Low % Health 810A54B6 0000 cn VS. Mode\Player 2\Low % Health 810A552A 0000 cn VS. Mode\Player 3\Low % Health 810A559E 0000 cn VS. Mode\Player 4\Low % Health 810A5612 0000 cn VS. Mode\Player 1\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A546B ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 2\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A54DF ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 3\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A5553 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 4\Character Modifier cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 800A55C7 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn VS. Mode\Player 1\Kirby B Button Move\Hyrule Castle 8026412F ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Yoshi's Island 8026E9F7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn VS. Mode\Player 1\Kirby B Button Move\Sector Z 8026C6C7 ???? 0002:"D.K. Wind-up Punch",000A:"Jigglypuff Puff Punch" cn P1 Press Down On D-Pad To Make Items Appear In Random Spots D109F6E4 0400 8118D7E2 0001 cn Have All Characters 810A5078 0FF0 cn VS. Mode\Have Mushroom Kindom 800A5077 00FF cn Story Mode\Always Get Pacifist (60,000 Points) 810A52AE 0000 cn Bonus Stage Character Modifier (Training Mode) cd Only put this on after you have alreay Chose your Character on the Main Menu,& Do not use more then 1 Character Modifier at a time.Using this Code This could also result freezing at the end of the Level. 8018F913 ???? 0000:"Mario",0001:"Fox",0002:"DK",0003:"Samus",0004:"Luigi",0005:"Link",0006:"Yoshi",0007:"C. Falcon",0008:"Kirby",0009:"Pikachu",000A:"Jigglypuff",000B:"Ness",000C:"Master Hand",000D:"Metal Mario",000E:"Polygon Mario",0010:"Polygon DK",0013:"Polygon Link",0014:"Polygon Yoshi",0015:"Polygon Samus",0018:"Polygon Kirby",001A:"Giant Donkey Kong" cn Jump off to win 810A5282 0000 crc 2B38AEC0-6350B810-C:46 gn A Bug's Life (F) cn Infinite\Lives 801E27C0 0009 cn Infinite\Health 801E27B5 0004 cn Always Have\Super Jump 811E27B0 0020 cn Always Have\50 pieces of corn 801E27C1 0032 cn Have F-L-I-K 801E27C2 000F cn Unlock All Levels 81099E90 000F cn Have All Goldberry Tokens 811E27AE 0000 cn Start with Berry Weapon 801E27B7 ???? 0001:"Blueberry",0002:"Homing Berry",0003:"Goldberry",0004:"Super Berry ?" cn No Music 801DD966 0000 cn Subtitles On 801DDBDB ???? 0000:"Off",0001:"On" cn Levitate cd "Press R To Levitate & Let go to land (:" D0090001 0010 811E2726 1000 D0090001 0010 811E2736 1000 crc 0C41F9C2-01717A0D-C:46 gn Fighter's Destiny (F) cn Start with Stars Modifier\Player 1 D0209837 0000 80209837 ???? 0000:"No Stars",0006:"Max Stars" cn Start with Stars Modifier\Player 2 D020B6FF 0000 8020B6FF ???? 0000:"No Stars",0006:"Max Stars" cn Have 1 Star\Ryuji 8030742E 0001 cn Have 1 Star\Bob 8030742F 0001 cn Have 1 Star\Pierre 80307430 0001 cn Have 1 Star\Meiling 80307431 0001 cn Have 1 Star\Leon 80307432 0001 cn Have 1 Star\Abdul 80307433 0001 cn Have 1 Star\Ninja 80307434 0001 cn Have 1 Star\Tomahawk 80307435 0001 cn Have 1 Star\Valerie 80307436 0001 cn Infinite Health\Player 1 80209981 0000 802048A3 0000 cn Infinite Health\Player 2 802048A7 0000 8020B849 0000 cn Start on stage 100 on Survival to get Joker 802EF67B 0063 cn Stop timer for Fastest to get Robot 810ADBDC 3F80 crc 1E12883D-D3B92718-C:46 gn Duke Nukem 64 (F) cn Access all In-Game cheats 50000504 0000 80100D98 0001 cn Infinite\Ammo & All Guns cd Ena\ble and then simply pause in game play & then unpause and then press left and right. 50000C02 0000 812A5F84 02F4 cn Access\All Items cd To access simply pause in game play & then unpause. 80100D7C 0001 cn Invincibility 802AAFE8 0001 cn Access\All Keys 802A5FC7 000F cn Infinite\Holoduke 812A5FAC 0640 cn Infinite\Night Vision 812A5FDC 0664 cn Infinite\Scuba Gear 812A600C 0640 cn Crosshair 802A6074 ???? 0001:"On",0000:"Off" cn Max auto-aim On 802A6075 0002 cn Upgraded Plasma Gun 802A5FB3 0063 crc B35FEBB0-7427B204-C:46 gn Holy Magic Century (F) cn Set Agility to 999-999 8107D384 03E7 cn Set Defence to 999-999 8107D386 03E7 cn Makes your MP 999-999 8107D380 03E7 8107D382 03E7 cn Makes your HP 999-999 8107D37C 03E7 8107D37E 03E7 cn Have All Elements 8107D39C 3232 8107D39E 3232 cn Earn Spirits Faster 8007D3AD 0000 cn No Random Battles 8008DE6C 0000 8008DE6E 0000 crc 29A045CE-ABA9060E-C:46 gn =Hydro Thunder (F) cn Always 1st 812C56A6 0001 cn Infinite\Time 812B52A0 42C8 cn Infinite\Boosts\Player 1 812C56AC 4190 cn Have All\Ships 50000702 0000 812B66B2 0101 cn Have All\Races 50000702 0000 812B66A4 0101 cn Infinite\Boosts\Player 2 812C59DC 4190 crc 001A3BD0-AFB3DE1A-C:46 gn Disney's Tarzan (F) cn Infinite\Health 81192320 0120 cn Have\Coins Collected 100% 800DD547 0064 cn Have\Level & Tokens Completed 100% 800DD51F 0000 800DD520 0001 800DD521 0000 cn Access Level Select cd On the main menu Scroll down to make CHEATS visible to go into Level Select.For in-Game Cheats,Pause gameplay. 810DD50C 8001 cn Infinite\Lives 800DD542 ???? 0003:"3 Lives",0063:"99 Lives" cn Have\All TARZAN Letters 800DD515 00FF cn Have\Full Portrait 800DD514 00FF cn Infinite\Red Weapon 811921F8 0063 cn Infinite\Green Weapon 811921F6 0063 cn Infinite\Purple Weapon 811921FA 0063 cn Press GS For\Sabor Attacks\Sabor 1 Hit Kill 8924A23E 0001 cn Infinite\Bonus Timer cd This is For All Timers on Bonus Levels 801736DE 0025 crc 5C1B5FBD-7E961634-C:46 gn Hexen (F) cn Access In-Game Cheat Menu cd To Access Pause Game Play. This gives you access to In-game Cheats like God Mode,Level Select,All Items Etc 81137DB6 07FF 80137E93 0005 crc CB93DB97-7F5C63D5-C:46 gn Toy Story 2 (F) cn Have 99 coins 810BBBDE 0063 cn Have all 5 collectables 801C8542 0005 cn Infinite Lives 800BBBDA 0009 cn Infinite Battery Power 810BBBD6 000E cn Hold jump to fly 810BBBCC 0002 crc EA06F8C3-07C2DEED-C:46 gn Shadow Man (F) cn Have All\Items cd Youll not miss out any part of the game for having all parts of LEclipsers with a new game D0059047 0001 50001D20 0000 80030613 000B cn Have All\Gads & The Poign 80030E57 000F cn Have All\Levels Unlocked 5000101C 0000 80030A0E 0001 cn Have All\Cheats: Book of Shadows 81075F4E 0FFF cn Have All\Dark Souls Collected D00590B3 0001 80075F49 007C cn Infinite\Shotgun Shells 80075B2F 0063 cn Infinite\Violator Ammo 81075B32 029A cn Infinite\Cadeaux' 81075B36 029A cn Infinite\0.9mm Ammo 81075B3A 0190 cn Infinite\Max Health/Air/Shadow Charge & Voodoo Power 50000604 0000 81075B16 2710 cn Infinite\Accumulators 800306D7 0005 cn Infinite\Retractors 800308B7 0003 cn Infinite\Prisms 80030957 0003 cn Ammo always displayed on screen 50000408 0000 80075ACD 0007 cn Press L To Levitate D0059097 0020 80075578 0041 cn Always Play As Deadwing Character 80075F53 0001 crc BA6C293A-9FAFA338-C:46 gn Pokemon Snap (F) //--------------- PAL (G) Region Cheat Codes cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C2552 0006 crc DFF227D9-0D4D8169-C:44 gn A Bug's Life cn Infinite\Lives 801E2760 0009 cn Infinite\Health 801E2755 0004 cn Always Have\Super Jump 811E2750 0020 cn Always Have\50 pieces of corn 801E2761 0032 cn Have F-L-I-K 801E2762 000F cn Unlock All Levels 81099E30 000F cn Have All Goldberry Tokens 811E274E 0000 cn Start with Berry Weapon 801E2757 ???? 0001:"Blueberry",0002:"Homing Berry",0003:"Goldberry",0004:"Super Berry ?" cn No Music 801DD906 0000 cn Subtitles On 801DDB7B ???? 0000:"Off",0001:"On" cn Levitate cd "Press R To Levitate & Let go to land (:" D008FFA1 0010 811E26C6 1000 D008FFA1 0010 811E26D6 1000 crc FE94E570-E4873A9C-C:44 gn Fighter's Destiny (G) cn Start with Stars Modifier\Player 1 D0209737 0000 80209737 ???? 0000:"No Stars",0006:"Max Stars" cn Start with Stars Modifier\Player 2 D020B5FF 0000 8020B5FF ???? 0000:"No Stars",0006:"Max Stars" cn Have 1 Star\Ryuji 8030732E 0001 cn Have 1 Star\Bob 8030732F 0001 cn Have 1 Star\Pierre 80307330 0001 cn Have 1 Star\Meiling 80307331 0001 cn Have 1 Star\Leon 80307332 0001 cn Have 1 Star\Abdul 80307333 0001 cn Have 1 Star\Ninja 80307334 0001 cn Have 1 Star\Tomahawk 80307335 0001 cn Have 1 Star\Valerie 80307336 0001 cn Infinite Health\Player 1 80209881 0000 802047A3 0000 cn Infinite Health\Player 2 802047A7 0000 8020B749 0000 cn Start on stage 100 on Survival to get Joker 802EF57B 0063 cn Stop timer for Fastest to get Robot 810ADADC 3F80 crc C3CD76FF-9B9DCBDE-C:44 gn Forsaken 64 (G) cn Infinite\Primery Weapons 8008EE30 0012 cn Infinite\Secondary Weapons 8008EE31 0012 cn Infinite\Weapon Energy 8008EE32 0012 cn Infinite\Lives 8008EE33 0012 cn Stealth Mode 8008EE34 0012 cn Invulnerability 8008EE35 0012 cn Wireframe Mode 8008EE36 0012 cn Gore Mode 8008EE37 0012 cn Turbo Mode 8008EE38 0012 cn Psychedelic Mode 8008EE39 0012 cn One Shot Enemies 8008EE3A 0012 cn Freeze Enemies 8008EE3B 0012 cn Infinite\Titans cd Titans are included in code 8008EE3C 0012 cn Infinite\Solaris cd Solaris are included in code 8008EE3D 0012 cn Level Select cd Accesses all Missions & Battle mode 8008EE3E 0012 crc 75FA0E14-C9B3D105-C:44 gn Holy Magic Century (G) cn Set Agility to 999-999 8107D644 03E7 cn Set Defence to 999-999 8107D646 03E7 cn Makes your MP 999-999 8107D640 03E7 8107D642 03E7 cn Makes your HP 999-999 8107D63C 03E7 8107D63E 03E7 cn Have All Elements 8107D65C 3232 8107D65E 3232 cn Earn Spirits Faster 8007D66D 0000 cn No Random Battles 8008E12C 0000 8008E12E 0000 crc 93EB3F7E-81675E44-C:44 gn Mission Impossible (G) cn Invincibility 810864C4 0101 cn Infinite\Ammo All Guns 50000610 0000 800A9297 00FF cn Access All Levels 8008A9D6 0001 8008A9EA 0001 8008AA12 0001 8008AA62 0001 8008AA76 0001 8008AA8A 0001 8008AA9E 0001 8008AAB2 0001 8008AAC6 0011 8008AADA 0021 8008AAEE 0001 8008AB16 0011 8008AB2A 0041 8008AB3E 0021 8008AB52 0081 8008AB66 0001 8008AB7A 0081 8008AB8E 0001 8008ABB6 0001 8008ABDE 0001 8008ABF2 0011 8008AC06 0021 8008AC56 0001 8008AF3A 0001 8008AF4E 0001 8008AF62 0001 8008AF76 0001 cn Infinite\Health 810866C2 FFFF cn Freeze All Timers 81094150 0063 81094152 0063 81094154 0063 cn Weapon Select 800A92B5 ???? 800A92C5 ???? 800A92D5 ???? 0000:"9MM Hi Power",0001:"Silenced Pistol",0002:"Uzi",0003:"Fists",0032:"Gas Spray",0036:"Blow Torch",001F:"Fire Extinguisher",0024:"Spray Paint",0027:"Electrostunner",000B:"Blow Dart Gun",000C:"Dart Hand Gun",002D:"Mini Rocket Launcher" cn Walk Through Walls & Objects cd This will allow you to pass through anything & even walk on water.if you amerge somewhere in the ground just press the A button. 80094305 ???? 0080:"On",0000:"Off" crc 4C261323-4F295E1A-C:44 gn Disney's Tarzan (G) cn Infinite\Health 81192320 0120 cn Have\Coins Collected 100% 800DD547 0064 cn Have\Level & Tokens Completed 100% 800DD51F 0000 800DD520 0001 800DD521 0000 cn Access Level Select cd On the main menu Scroll down to make CHEATS visible to go into Level Select.For in-Game Cheats,Pause gameplay. 810DD50C 8001 cn Infinite\Lives 800DD542 ???? 0003:"3 Lives",0063:"99 Lives" cn Have\All TARZAN Letters 800DD515 00FF cn Have\Full Portrait 800DD514 00FF cn Infinite\Red Weapon 811921F8 0063 cn Infinite\Green Weapon 811921F6 0063 cn Infinite\Purple Weapon 811921FA 0063 cn Press GS For\Sabor Attacks\Sabor 1 Hit Kill 8924A23E 0001 cn Infinite\Bonus Timer cd This is For All Timers on Bonus Levels 801736DE 0025 crc 9AB3B50A-BC666105-C:44 gn Hexen (G) cn Access In-Game Cheat Menu cd To Access Pause Game Play. This gives you access to In-game Cheats like God Mode,Level Select,All Items Etc 81137CD6 07FF 80137DB3 0005 crc 84D5FD75-BBFD3CDF-C:44 gn Shadowman (G) cn Have All\Items cd Youll not miss out any part of the game for having all parts of LEclipsers with a new game D0059047 0001 50001D20 0000 80030613 000B cn Have All\Gads & The Poign 80030E57 000F cn Have All\Levels Unlocked 5000101C 0000 80030A0E 0001 cn Have All\Cheats: Book of Shadows 81075EFE 0FFF cn Have All\Dark Souls Collected D0059047 0001 80075EF9 007C cn Infinite\Shotgun Shells 80075ADF 0063 cn Infinite\Violator Ammo 81075AE2 029A cn Infinite\Cadeaux' 81075AE6 029A cn Infinite\0.9mm Ammo 81075AEA 0190 cn Infinite\Max Health,Air,Shadow Charge & Voodoo Power 50000604 0000 81075AC6 2710 cn Infinite\Accumulators 800306D7 0005 cn Infinite\Retractors 800308B7 0003 cn Infinite\Prisms 80030957 0003 cn Ammo always displayed on screen 50000408 0000 80075A7D 0007 cn Press L To Levitate D0058EE4 0020 80075528 0041 crc 91B66D42-16AC4E46-C:44 gn South Park cn Have Cheats Menu cd Go into the Cheats From the main Menu & put on the Ones you want 810CF716 01FF cn Infinite Energy 802FD209 0064 cn Infinite Credits 802FD215 0064 cn Infinite Sponge Darts 802FD223 0064 cn Infinite Suckers 802FD222 0064 cn Infinite Balls 802FD21F 0064 cn Start with 9999 Monster Score 812FD20E 270F crc 782A9075-E552631D-C:44 gn Toy Story 2 (G) cn Have 99 coins 810BBBDE 0063 cn Have all 5 collectables 801C8542 0005 cn Infinite Lives 800BBBDA 0009 cn Infinite Battery Power 810BBBD6 000E cn Hold jump to fly 810BBBCC 0002 crc 665FD963-B5CC6612-C:44 gn Turok - Dinosaur Hunter (G) cn Infinite\Lives 80128E9B 00FF cn Infinite\Body Armor 81128D26 5B23 80128D67 0001 cn Infinite\Air 80129070 0063 801E862A 0063 cn Infinite\Health 812C15C4 1E61 812A2534 1E61 cn Have\All Level Keys 50000604 0000 80128D73 0007 80128D8B 001F 80128DAB 00FF cn Have\All Weapons 50000B04 0000 80128D47 0001 80128D33 0001 cn Infinite\Ammo 50000404 0000 80128CF3 00FF 80128D03 00FF 80128D0F 00FF 50000504 0000 80128D13 00FF 80128E9B 00FF 80128E97 00FF cn Diffuculty Modifier 8011956F ???? 0000:"Easy",0001:"Normal",0002:"Hard" cn Have\Backpack 80128C7B 0001 80128CBB 0001 cn Open All Portals cd Press L to Access Map 8114F85A F803 81128CDE 0003 81128CE2 0003 81128CE6 0003 81128CEA 0003 81128CEE 0003 81128CF2 0003 81128CF6 0005 cn Have All\Gems 80128E97 00FF crc 5753720D-2A8A884D-C:44 gn Pokemon Snap (G) //--------------- PAL (I) Region Cheat Codes cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C24D2 0006 crc F63B89CE-4582D57D-C:49 gn A Bug's Life (I) cn Infinite\Lives 801E2760 0009 cn Infinite\Health 801E2755 0004 cn Always Have\Super Jump 811E2750 0020 cn Always Have\50 pieces of corn 801E2761 0032 cn Have F-L-I-K 801E2762 000F cn Unlock All Levels 81099E30 000F cn Have All Goldberry Tokens 811E274E 0000 cn Start with Berry Weapon 801E2757 ???? 0001:"Blueberry",0002:"Homing Berry",0003:"Goldberry",0004:"Super Berry ?" cn No Music 801DD906 0000 cn Subtitles On 801DDB7B ???? 0000:"Off",0001:"On" cn Levitate cd "Press R To Levitate & Let go to land (:" D008FFA1 0010 811E26C6 1000 D008FFA1 0010 811E26D6 1000 crc EBA949DC-39BAECBD-C:49 gn Mission Impossible (I) cn Invincibility 810864C4 0101 cn Infinite\Ammo All Guns 50000610 0000 800A9297 00FF cn Access All Levels 8008A9D6 0001 8008A9EA 0001 8008AA12 0001 8008AA62 0001 8008AA76 0001 8008AA8A 0001 8008AA9E 0001 8008AAB2 0001 8008AAC6 0011 8008AADA 0021 8008AAEE 0001 8008AB16 0011 8008AB2A 0041 8008AB3E 0021 8008AB52 0081 8008AB66 0001 8008AB7A 0081 8008AB8E 0001 8008ABB6 0001 8008ABDE 0001 8008ABF2 0011 8008AC06 0021 8008AC56 0001 8008AF3A 0001 8008AF4E 0001 8008AF62 0001 8008AF76 0001 cn Infinite\Health 810866C2 FFFF cn Freeze All Timers 81094150 0063 81094152 0063 81094154 0063 cn Weapon Select 800A92B5 ???? 800A92C5 ???? 800A92D5 ???? 0000:"9MM Hi Power",0001:"Silenced Pistol",0002:"Uzi",0003:"Fists",0032:"Gas Spray",0036:"Blow Torch",001F:"Fire Extinguisher",0024:"Spray Paint",0027:"Electrostunner",000B:"Blow Dart Gun",000C:"Dart Hand Gun",002D:"Mini Rocket Launcher" cn Walk Through Walls & Objects cd This will allow you to pass through anything & even walk on water.if you amerge somewhere in the ground just press the A button. 80094305 ???? 0080:"On",0000:"Off" crc C0C85046-61051B05-C:49 gn Pokemon Snap (I) //--------------- PAL (S) Region Cheat Codes cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C2712 0006 crc 5F6A04E2-D4FA070D-C:53 gn Mission Impossible (S) cn Invincibility 810864C4 0101 cn Infinite\Ammo All Guns 50000610 0000 800A9297 00FF cn Access All Levels 8008A9D6 0001 8008A9EA 0001 8008AA12 0001 8008AA62 0001 8008AA76 0001 8008AA8A 0001 8008AA9E 0001 8008AAB2 0001 8008AAC6 0011 8008AADA 0021 8008AAEE 0001 8008AB16 0011 8008AB2A 0041 8008AB3E 0021 8008AB52 0081 8008AB66 0001 8008AB7A 0081 8008AB8E 0001 8008ABB6 0001 8008ABDE 0001 8008ABF2 0011 8008AC06 0021 8008AC56 0001 8008AF3A 0001 8008AF4E 0001 8008AF62 0001 8008AF76 0001 cn Infinite\Health 810866C2 FFFF cn Freeze All Timers 81094150 0063 81094152 0063 81094154 0063 cn Weapon Select 800A92B5 ???? 800A92C5 ???? 800A92D5 ???? 0000:"9MM Hi Power",0001:"Silenced Pistol",0002:"Uzi",0003:"Fists",0032:"Gas Spray",0036:"Blow Torch",001F:"Fire Extinguisher",0024:"Spray Paint",0027:"Electrostunner",000B:"Blow Dart Gun",000C:"Dart Hand Gun",002D:"Mini Rocket Launcher" cn Walk Through Walls & Objects cd This will allow you to pass through anything & even walk on water.if you amerge somewhere in the ground just press the A button. 80094305 ???? 0080:"On",0000:"Off" crc 817D286A-EF417416-C:53 gn Pokemon Snap (S) //--------------- PAL (FGD) Region Cheat Codes cn [Enable All Levels] cd This is needed to be able to Play all Levels of the Game 810C2712 0006 crc 2E0E7749-B8B49D59-C:58 gn Turok 2 - Seeds of Evil (FGD) //--------------- PAL (IS) Region Cheat Codes cn Access In-Game Cheat Menu 8113568C FFFF 8113568E FFFF //--------------- Demo Cheat Codes //[3A089BBC-54AB2C06-C:0] gn Berney must die! //[A3A044B5-6DB1BF5E-C:0] gn POM-Spacer By Memir //Recent in File---------->Anything under here is still being worked on<-------------------------------- cn Infinite Health\Player 1 802E4E4A 0027 cn Collect One Item For Portal 802E4E47 ???? 0003:"Level 1",000E:"Level 2",000C:"Level 3",000D:"Level 4" cn Paly As 802E4E4C ???? 0000:"Red Helic",0001:"Green Helic",0002:"Blue Helic",0003:"Yellow Helic",0010:"Red Rocket",0011:"Green Rocket",0012:"Blue Rocket",0013:"Yellow Rocket",0020:"Red Back Bee",0021:"Green Back Bee",0022:"Blue Back Bee",0023:"Yellow Back Bee",0030:"Red Stealth",0031:"Green Stealth",0032:"Blue Stealth",0033:"Yellow Stealth" cn Freeze Timer 802E4D5F 0000 cn Infinite Health\Player 2 802E4EA2 0027 cn Infinite Health\Player 3 802E4EFA 0027 cn Infinite Health\Player 4 802E4F52 0027 crc ABA51D09-C668BAD9-C:58 gn 40 WINKS cn Infinite 99 Moons 801D2A81 0063 cn Infinite 50 Health ZZZ's 811D2A84 0032 cn Infinite 40 Cogs cd Disable when on Boss Modes as it can cause hanging! 811D2A82 0028 cn Infinite 99 Lives cd Disable when on Boss Modes as it can cause hanging! 801D2A87 0063 cn Infinite 99 Tokens cd Disable when on Boss Modes as it can cause hanging! 801D2A8D 0063 cn Infinite Max Air 811D2AA0 07C6 811DA2F6 07C1 cn Have All Dreamkeys Collected 50000802 0000 81207D70 FFFF cn Setting Options\Langauge Select 801D21AC ???? 0000:"English",0001:"Spanish",0002:"Italian" cn Setting Options\Difficulty Select 801D534F ???? 0000:"Easy",0001:"Medium",0002:"Hard" cn Setting Options\SFX Volume Select 801D5350 ???? 0000:"Off",0005:"Normal",0007:"Max" cn Setting Options\Music Volume Select 801D5351 ???? 0000:"Off",0005:"Normal",0007:"Max" cn Setting Options\Rumble Pak Strength Select 801D5353 ???? 0000:"Off (Normal)",0005:"Middle",0007:"Max" cn Setting Options\GFX Quality Select 801D5354 ???? 0000:"Normal",0001:"Medium",0002:"HighCol" cn Setting Options\Controller Select 801D5362 ???? 0000:"Preset 1 (Normal)",0001:"Preset 2",0002:"Preset 3" cn Character Select 801D535F ???? 0000:"Ruff (Boy) (Default)",0001:"Tumble (Girl)" cn Have All 40 Winks Collected cd Combined with Have All Levels Completed cheat will open the door for Have All 40 Winks 50000602 0000 81207D60 FFFF cn Have All Levels Completed 50000202 0000 81207D6C FFFF crc 04DAF07F-0D18E688-C:45 gn DUKE NUKEM ZERO HOUR cn Cheat Menu\Cheat Menu Enabled 801CE4E8 0001 cn Cheat Menu\Have All Weapons 811CE470 FFFF cn Cheat Menu\Have All Game Type & Other 810E16BE FFFF cn Cheat Menu\All Weapons Enabled 801CC8B9 0001 801CC925 0001 801CD985 0001 801CDA81 0001 801CDB15 0001 801CDB17 0001 801CDB49 0001 801CE479 0001 801CE481 0001 801CE4ED 0001 801CF635 0001 cn Infinite Ammo (All Guns) 810A1E74 A65B cn Invincibility 800DEEC3 0001 cn Time Always 00:00 801A19C6 0000 cn Enable Debug Menu 800DF990 0001 crc 32CA974B-B2C29C50-C:46 gn DUKE NUKEM ZERO HOUR (F) cn Cheat Menu\Cheat Menu Enabled 801DA748 0001 cn Cheat Menu\Have All Weapons 811DA6D0 FFFF cn Cheat Menu\Have All Game Type & Other 810E1B5E 0FFF cn Cheat Menu\All Weapons Enabled 801D8B19 0001 801D8B85 0001 801D9BE5 0001 801D9CE1 0001 801D9D75 0001 801D9D77 0001 801D9DA9 0001 801DA6D9 0001 801DA6E1 0001 801DA74D 0001 801DB895 0001 cn Infinite Ammo (All Guns) 810A21D4 A65B cn Invincibility 800DF223 0001 cn Enable Debug Menu 800DFCF0 0001 crc 22E9623F-B60E52AD-C:50 gn FLYING DRAGON cn Infinite\Health\Player 1 80209D81 00C8 cn Infinite\Special\Player 1 81209484 0190 cn 1 Win to Win\Player 1 D020A84F 0000 8020A84F 0001 cn Infinite\Health\Player 2 81209780 0190 cn Infinite\Special\Player 2 8120B1B0 0190 cn 1 Win to Win\Player 2 D020A84F 0000 8020A84F 0010 cn Infinite\Money 8121106C 2704 crc DEE596AB-AF3B7AE7-C:45 gn WCW / nWo REVENGE cn Infinite Time 800FAF87 0000 cn Extra Characters & Modes 8107F07C FFFF cn Spirit Select\Player 1 800F9D25 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Spirit Select\Player 2 800FA0D5 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Spirit Select\Player 3 800FA485 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Spirit Select\Player 4 800FA835 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Infinite Time Out Of Ring 800FACE8 0014 cn Always Special\Player 1 800F9D35 0008 cn Always Special\Player 2 800FA0E5 0008 cn Always Special\Player 3 800FA495 0008 cn Always Special\Player 4 800FA845 0008 cn Weapon Select\Player 1 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800F9D31 0003 800F98E1 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F98E2 0000 800F99A0 0000 cn Weapon Select\Player 2 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800FA0E1 0003 800F9911 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F9912 0001 800F99A1 0001 cn Weapon Select\Player 3 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800FA491 0003 800F9941 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F9942 0002 800F99A2 0002 cn Weapon Select\Player 4 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800FA841 0003 800F9971 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F9972 0003 800F99A3 0003 cn Get Title Belt In 1-Match 80038AAB 0008 cn Character Select\Player 1 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890F9D36 0240 890F9D60 42B4 8107E8B2 ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Character Select\Player 2 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890FA0E6 0240 890FA110 42B4 8107E8B6 ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Character Select\Player 3 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890FA496 0240 890FA4C0 42B4 8107E8BA ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Character Select\Player 4 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890FA846 0240 890FA870 42B4 8107E8BE ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Ultimate Code\Player 1 800F9D24 0064 cn Ultimate Code\Player 2 800FA0D4 0064 cn Ultimate Code\Player 3 800FA484 0064 cn Ultimate Code\Player 4 800FA834 0064 crc 68E8A875-0CE7A486-C:50 gn WCW / nWo REVENGE cn Infinite Time 800FAF87 0000 cn Extra Characters & Modes 8107F07C FFFF cn Spirit Select\Player 1 800F9D25 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Spirit Select\Player 2 800FA0D5 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Spirit Select\Player 3 800FA485 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Spirit Select\Player 4 800FA835 ???? 0064:"Have Max",0032:"Have Normal",0000:"Have None" cn Infinite Time Out Of Ring 800FACE8 0014 cn Always Special\Player 1 800F9D35 0008 cn Always Special\Player 2 800FA0E5 0008 cn Always Special\Player 3 800FA495 0008 cn Always Special\Player 4 800FA845 0008 cn Weapon Select\Player 1 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800F9D31 0003 800F98E1 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F98E2 0000 800F99A0 0000 cn Weapon Select\Player 2 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800FA0E1 0003 800F9911 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F9912 0001 800F99A1 0001 cn Weapon Select\Player 3 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800FA491 0003 800F9941 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F9942 0002 800F99A2 0002 cn Weapon Select\Player 4 cd With these codes, they do glitch a LOT! It will glitch when you hit certain people with certain weapons a certain way, but it is RANDOM somewhat too 800FA841 0003 800F9971 ???? 0000:"Mallot",0001:"Blue Microphone",0002:"Black Microphone",0003:"Trophy",0004:"Black Baseball Bat",0005:"Spotted Baseball Bat",0006:"Steel Chair",0007:"Table Piece",0008:"Trash Can",0009:"Suitcase",000A:"Stop Sign",00FF:"Nothing" 800F9972 0003 800F99A3 0003 cn Get Title Belt In 1-Match 80038AAB 0008 cn Character Select\Player 1 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890F9D36 0240 890F9D60 42B4 8107E8B2 ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Character Select\Player 2 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890FA0E6 0240 890FA110 42B4 8107E8B6 ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Character Select\Player 3 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890FA496 0240 890FA4C0 42B4 8107E8BA ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Character Select\Player 4 cd With this code, you will need to press the GS Button to be in the ring and have full access to getting in and out of the ring. 890FA846 0240 890FA870 42B4 8107E8BE ???? 0001:"Sting",0002:"Giant",0003:"Lex Luger",0004:"Diamon Dallas Page",0005:"Rick Steiner",0007:"Roddy Piper",0008:"Bret Hart",0009:"Chris Benoit",000A:"Goldberg",000B:"Booker T",000C:"Disco Inferno",0101:"Fit Finley",0105:"Meng",0106:"Barbarian",0107:"Larry Zbysko",0108:"Stevie Ray",010B:"British Bulldog",010D:"Yugi Nagata",010E:"Jim Neidhart",010F:"Alex Wright",0201:"Hollywood Hogan",0202:"Macho Man Randy Savage",0203:"Kevin Nash",0204:"Scott Hall",0205:"Buff Bagwell",0206:"Scott Stenier",0207:"Curt Hennig",0208:"Konnan",0209:"Scott Norton",020C:"Brian Adams",020D:"Eric Bishoff",0301:"Ultimo Dragon",0302:"Eddy Guerrero",0303:"Chris Jericho",0304:"Rey Mysterio Jr.",0305:"Juventud Guerrera",0306:"Dean Malenko",0307:"Chavo Guerrero Jr.",0308:"La Parka",0309:"Psychosis",0401:"Glacier",0403:"Wrath",0404:"Kanyon",0501:"Raven",0502:"Saturn",0503:"Kidman",0504:"Riggs",0505:"Van Hammer",0506:"Sick Boy",0507:"Lodi",0508:"Reese",0601:"AKI Man",0602:"Shogun",0603:"Executioner",0604:"Dr. Frank",0605:"Jekel",0606:"Maya Ineaby",0701:"Hawk Hana",0702:"Kimchee",0703:"Dakeken",0704:"Brickowski",0705:"Mingchee",0706:"Han Zomon",0801:"Eric Bischoff (Manager)",0802:"Onoo (Manager)",0803:"Jimmy Hart (Manager)",0804:"Rick Rude (Manager)",0805:"Dusty Rhodes (Manager)",0806:"Ted Debisas (Manager)",0807:"James Bandenderg (Manager)",0808:"Vincent (Manager)",0901:"Elizabeth (Manager)",0902:"Kimberly (Manager)",0903:"Jackreen (Manager)",0904:"Sister Sherri (Manager)",0905:"Woman (Manager)" cn Ultimate Code\Player 1 800F9D24 0064 cn Ultimate Code\Player 2 800FA0D4 0064 cn Ultimate Code\Player 3 800FA484 0064 cn Ultimate Code\Player 4 800FA834 0064 crc AA7B0658-9C96937B-C:50 gn WCW MAYHEM cn Character Creation\Max\Strength 80308D35 0009 cn Character Creation\Max\Impact 80320375 0009 cn Character Creation\Max\Speed 80322CB5 0009 cn Character Creation\Max\Quickness 80324C75 0009 cn Character Creation\Max\Aerial 80326C35 0009 cn Character Creation\Max\Mat Ability 80328BF5 0009 cn Character Creation\Max\Submission 8032ABB5 0009 cn Character Creation\Max\Brawling 8032CB75 0009 cn Character Creation\Max\Dirtiness 8032EB35 0009 cn Infinite Stamina\Player 1 810E9798 0478 cn Infinite Stamina\Player 2 810E9934 03ED cn Meter Select\Player 1 800E979D ???? 0060:"Full Meter Bar",0000:"Empty Meter Bar" cn Meter Select\Player 2 800E993D ???? 0060:"Full Meter Bar",0000:"Empty Meter Bar" cn Enable Cheat 800B6F5B ???? 0002:"Super Created Wrestlers",0004:"Stamina Meter",0008:"Momentum Meter",0020:"Play As Same Wrestler",0080:"All Wrestlers" cn Freeze Timer 800B7E02 D300 crc F82DD377-8C3FB347-C:58 gn TG RALLY 2 cn Always 1st 80031F93 0001 cn No Damage Or Failures 80031427 0001 cn 100.000 Sponsor Credits & 950 Championship Points In Support Van cd You Also Have Access To All Cars, Tracks & Extra Features 80031433 00F3 cn No Cones Hit cd In ARSG Rally School 80031FC3 0000 8003239B 0000 cn No Navigator 80031EF7 0000 cn Max Sponsor Credits 803A6702 0010 803A6704 0001 cn Infinite Cash 803A418E 4000 cn Freeze Timer 80031F9F 0000 mupen64plus-core-src-2.6.0/doc/000077500000000000000000000000001464506436200162135ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/000077500000000000000000000000001464506436200211775ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Home.mediawiki000066400000000000000000000012261464506436200237550ustar00rootroot00000000000000=User Documentation= == Configuration Parameters == === [[Mupen64Plus Core Parameters|Core Parameters]] === This section lists the names and descriptions of all of the configuration parameters used by the Core library. === [[Mupen64Plus Plugin Parameters|Plugin Parameters]] === This section lists the names and descriptions of all of the configuration parameters used by the Plugin libraries. =Developer Documentation= == [[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] == The interface between Mupen64Plus and its compatible plugins is (slightly) different from other N64 emulators. The new API is described in detail in the documentation here. mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-Core-Parameters.mediawiki000066400000000000000000000213461464506436200301630ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Core Parameters = These are standard parameters which are used by the Mupen64Plus Core library. They are stored in a configuration section called "Core" and may be altered by the front-end in order to adjust the behaviour of the emulator. These may be adjusted at any time and the effect of the change should occur immediately. {| border="1" !Parameter Name!!Type!!Usage |- |Version |M64TYPE_FLOAT |Mupen64Plus Core config parameter set version number. Please don't change. |- |OnScreenDisplay |M64TYPE_BOOL |Draw on-screen display if True, otherwise don't draw OSD |- |R4300Emulator |M64TYPE_INT |Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more |- |NoCompiledJump |M64TYPE_BOOL |Disable compiled jump commands in dynamic recompiler (should be set to False) |- |DisableExtraMem |M64TYPE_BOOL |Disable 4MB expansion RAM pack. May be necessary for some games. |- |AutoStateSlotIncrement |M64TYPE_BOOL |Increment the save state slot after each save operation. |- |EnableDebugger |M64TYPE_BOOL |Activate the R4300 debugger when ROM execution begins, if core was built with Debugger support. |- |CurrentStateSlot |M64TYPE_INT |Save state slot (0-9) to use when saving/loading the emulator state |- |ScreenshotPath |M64TYPE_STRING |Path to directory where screenshots are saved. If this is blank, the default value of "GetConfigUserDataPath()"/screenshot will be used. |- |SaveStatePath |M64TYPE_STRING |Path to directory where emulator save states (snapshots) are saved. If this is blank, the default value of "GetConfigUserDataPath()"/save will be used. |- |SaveSRAMPath |M64TYPE_STRING |Path to directory where SRAM/EEPROM data (in-game saves) are stored. If this is blank, the default value of "GetConfigUserDataPath()"/save will be used. |- |SharedDataPath |M64TYPE_STRING |Path to a directory to search when looking for shared data files in the ConfigGetSharedDataFilepath() function. |- |CountPerOp |M64TYPE_INT |Force number of cycles per emulated instruction when set greater than 0. |- |CountPerOpDenomPot |M64TYPE_INT |Reduce number of cycles per update by power of two when set greater than 0 (overclock). |- |} These configuration parameters are used in the Core's event loop to detect keyboard and joystick commands. They are stored in a configuration section called "CoreEvents" and may be altered by the front-end in order to adjust the behaviour of the emulator. These may be adjusted at any time and the effect of the change should occur immediately. The Keysym value stored is actually (SDLMod << 16) || SDLKey, so that keypresses with modifiers like shift, control, or alt may be used. {| border="1" !Parameter Name!!Type!!Usage |- |Kbd Mapping Slot 0 |M64TYPE_INT |SDL keysym for save slot 0 |- |Kbd Mapping Slot 1 |M64TYPE_INT |SDL keysym for save slot 1 |- |Kbd Mapping Slot 2 |M64TYPE_INT |SDL keysym for save slot 2 |- |Kbd Mapping Slot 3 |M64TYPE_INT |SDL keysym for save slot 3 |- |Kbd Mapping Slot 4 |M64TYPE_INT |SDL keysym for save slot 4 |- |Kbd Mapping Slot 5 |M64TYPE_INT |SDL keysym for save slot 5 |- |Kbd Mapping Slot 6 |M64TYPE_INT |SDL keysym for save slot 6 |- |Kbd Mapping Slot 7 |M64TYPE_INT |SDL keysym for save slot 7 |- |Kbd Mapping Slot 8 |M64TYPE_INT |SDL keysym for save slot 8 |- |Kbd Mapping Slot 9 |M64TYPE_INT |SDL keysym for save slot 9 |- |Kbd Mapping Stop |M64TYPE_INT |SDL keysym for stopping the emulator |- |Kbd Mapping Fullscreen |M64TYPE_INT |SDL keysym for switching between fullscreen/windowed modes |- |Kbd Mapping Save State |M64TYPE_INT |SDL keysym for saving the emulator state |- |Kbd Mapping Load State |M64TYPE_INT |SDL keysym for loading the emulator state |- |Kbd Mapping Increment Slot |M64TYPE_INT |SDL keysym for advancing the save state slot |- |Kbd Mapping Reset |M64TYPE_INT |SDL keysym for resetting the emulator |- |Kbd Mapping Speed Down |M64TYPE_INT |SDL keysym for slowing down the emulator |- |Kbd Mapping Speed Up |M64TYPE_INT |SDL keysym for speeding up the emulator |- |Kbd Mapping Screenshot |M64TYPE_INT |SDL keysym for taking a screenshot |- |Kbd Mapping Pause |M64TYPE_INT |SDL keysym for pausing the emulator |- |Kbd Mapping Mute |M64TYPE_INT |SDL keysym for muting/unmuting the sound |- |Kbd Mapping Increase Volume |M64TYPE_INT |SDL keysym for increasing the volume |- |Kbd Mapping Decrease Volume |M64TYPE_INT |SDL keysym for decreasing the volume |- |Kbd Mapping Fast Forward |M64TYPE_INT |SDL keysym for temporarily going really fast |- |Kbd Mapping Frame Advance |M64TYPE_INT |SDL keysym for advancing by one frame when paused |- |Kbd Mapping Gameshark |M64TYPE_INT |SDL keysym for pressing the game shark button |- |} These configuration parameters are used in the Core's event loop to detect joystick commands. The command strings use a simple format described here. Note that you cannot have any spaces in the command string. For commands activated by pressing a joystick axis, the format is "J'''x'''A'''y'''+" or "J'''x'''A'''y'''-", where '''x''' is the SDL joystick number (must be between 0 and 9) and '''y''' is the axis number. For the last character, '''+''' represents movement in the positive direction, while '''-''' represents movement in the negative direction. For commands activated by pressing a button, the format is "J'''x'''B'''y'''", where '''x''' is the SDL joystick number (must be between 0 and 9) and '''y''' is the button number. For commands activated by pressing a ''hat'' (a directional switch) on the joystick, the format is "J'''x'''H'''y'''V'''z'''", where '''x''' is the SDL joystick number (must be between 0 and 9), '''y''' is the hat number, and '''z''' is the hat value. The hat value corresponds with the SDL_HAT_ enumerated types: Up is 1, Right is 2, Down is 4, and Left is 8. For diagonal directions, these values may be ''or''d together. After the 2.5 release, several new features were added to these Joystick Mapping command strings. You can now specify more than one joystick action which will activate a given command. To specify several actions, use a comma-separated string containing multiple action phrases as given above ("J'''x'''A'''y'''+" or "J'''x'''B'''y'''" or "J'''x'''H'''y'''V'''z'''"). Make sure there are no spaces in your command string. Another new feature is that the "*" character can be used as a wildcard in the '''x''' joystick number field in order to activate this command for any joystick. Finally, you can also use a hotkey specifier to require that two distinct joystick actions must be pressed simultaneously in order to activate a command. The format for the hoykey feature is like "J'''x'''''Action''/''Action''" where ''Action'' is either "A'''y'''+", "A'''y'''-", "B'''y'''", or "H'''y'''V'''z'''". Here's an example of a joystick command parameter which uses all three of these new features:
Joy Mapping Stop = "J0B6,J*B9,J1B5/A0-"
With this joystick event string, the emulator will shut down when joystick 0 button 6 is pressed, or when button 9 is pressed on any joystick, or when button 5 is pressed on joystick 1 at the same time as axis 0 is moved left. {| border="1" !Parameter Name!!Type!!Usage |- |Version |M64TYPE_FLOAT |Mupen64Plus CoreEvents config parameter set version number. Please don't change. |- |Joy Mapping Stop |M64TYPE_STRING |Joystick event string for stopping the emulator |- |Joy Mapping Fullscreen |M64TYPE_STRING |Joystick event string for switching between fullscreen/windowed modes |- |Joy Mapping Save State |M64TYPE_STRING |Joystick event string for saving the emulator state |- |Joy Mapping Load State |M64TYPE_STRING |Joystick event string for loading the emulator state |- |Joy Mapping Increment Slot |M64TYPE_STRING |Joystick event string for advancing the save state slot |- |Joy Mapping Reset |M64TYPE_STRING |Joystick event string for resetting the emulator |- |Joy Mapping Speed Down |M64TYPE_STRING |Joystick event string for slowing down the emulator |- |Joy Mapping Speed Up |M64TYPE_STRING |Joystick event string for speeding up the emulator |- |Joy Mapping Screenshot |M64TYPE_STRING |Joystick event string for taking a screenshot |- |Joy Mapping Pause |M64TYPE_STRING |Joystick event string for pausing or resuming the emulator |- |Joy Mapping Mute |M64TYPE_STRING |Joystick event string for muting/unmuting the sound |- |Joy Mapping Increase Volume |M64TYPE_STRING |Joystick event string for increasing the volume |- |Joy Mapping Decrease Volume |M64TYPE_STRING |Joystick event string for decreasing the volume |- |Joy Mapping Fast Forward |M64TYPE_STRING |Joystick event string for temporarily going really fast |- |Joy Mapping Frame Advance |M64TYPE_STRING |Joystick event string for advancing by one frame when paused |- |Joy Mapping Gameshark |M64TYPE_STRING |Joystick event string for pressing the game shark button |- |} mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-Plugin-Parameters.mediawiki000066400000000000000000000333371464506436200305340ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Plugin Parameters = These are standard parameters which are used by the Mupen64Plus plugins. The behavior of the plugin library when these parameters are changed while the emulator is running is not defined here. Some plugins will load the parameters when starting and store internal copies of the parameters for use during emulation. Other plugins may read the value of the parameters while running. === Audio-SDL === {| border="1" !Parameter Name!!Type!!Usage |- |Version |M64TYPE_FLOAT |Mupen64Plus Audio SDL config parameter set version number. Please don't change. |- |DEFAULT_FREQUENCY |M64TYPE_INT |Frequency which is used if rom doesn't want to change it |- |SWAP_CHANNELS |M64TYPE_BOOL |Swaps left and right channels |- |PRIMARY_BUFFER_SIZE |M64TYPE_INT |Size of primary buffer in output samples. This is where audio is loaded after it's extracted from n64's memory. |- |PRIMARY_BUFFER_TARGET |M64TYPE_INT |Fullness level target for Primary audio buffer, in equivalent output samples. |- |SECONDARY_BUFFER_SIZE |M64TYPE_INT |Size of secondary buffer in samples. This is SDL's hardware buffer. |- |RESAMPLE |M64TYPE_STRING |Audio resampling algorithm. "trivial" for fastest, lowest-quality algorithm. If compiled with SPEEX support, this can be "speex-fixed-0" to "speex-fixed-10". If compiled with libsrc support, this can be "src-sinc-best-quality", "src-sinc-medium-quality", "src-sinc-fastest", "src-zero-order-hold", or "src-linear". |- |VOLUME_CONTROL_TYPE |M64TYPE_INT |Volume control type: 1 = SDL (only affects Mupen64Plus output) 2 = OSS mixer (adjusts master PC volume) |- |VOLUME_ADJUST |M64TYPE_INT |Percentage change each time the volume is increased or decreased |- |VOLUME_DEFAULT |M64TYPE_INT |Default volume when a game is started. Only used if VOLUME_CONTROL_TYPE is 1 |- |} === Video-General === {| border="1" !Parameter Name!!Type!!Usage |- |Fullscreen |M64TYPE_BOOL |Use fullscreen mode if True, or windowed mode if False |- |ScreenWidth |M64TYPE_INT |Width of output window or fullscreen width |- |ScreenHeight |M64TYPE_INT |Height of output window or fullscreen height |- |} === Video-Rice === {| border="1" !Parameter Name!!Type!!Usage |- |FrameBufferSetting |M64TYPE_INT |Frame Buffer Emulation (0=ROM default, 1=disable) |- |FrameBufferWriteBackControl |M64TYPE_INT |Frequency to write back the frame buffer (0=every frame, 1=every other frame, etc) |- |RenderToTexture |M64TYPE_INT |Render-to-texture emulation (0=none, 1=ignore, 2=normal, 3=write back, 4=write back and reload) |- |ScreenUpdateSetting |M64TYPE_INT |Control when the screen will be updated (0=ROM default, 1=VI origin update, 2=VI origin change, 3=CI change, 4=first CI change, 5=first primitive draw, 6=before screen clear, 7=after screen drawn) |- |NormalAlphaBlender |M64TYPE_BOOL |Force to use normal alpha blender |- |FastTextureLoading |M64TYPE_BOOL |Use a faster algorithm to speed up texture loading and CRC computation (may break hi-res texture loading) |- |AccurateTextureMapping |M64TYPE_BOOL |Use different texture coordinate clamping code |- |InN64Resolution |M64TYPE_BOOL |Force emulated frame buffers to be in N64 native resolution |- |SaveVRAM |M64TYPE_BOOL |Try to reduce Video RAM usage (should never be used) |- |DoubleSizeForSmallTxtrBuf |M64TYPE_BOOL |Enable this option to have better render-to-texture quality |- |DefaultCombinerDisable |M64TYPE_BOOL |Force to use normal color combiner |- |EnableHacks |M64TYPE_BOOL |Enable game-specific settings from INI file |- |EnableFog |M64TYPE_BOOL |Enable or disable fog generation |- |WinFrameMode |M64TYPE_BOOL |If enabled, graphics will be drawn in WinFrame mode instead of solid and texture mode |- |FullTMEMEmulation |M64TYPE_BOOL |N64 Texture Memory Full Emulation (may fix some games, may break others) |- |OpenGLVertexClipper |M64TYPE_BOOL |Enable vertex clipper for fog operations |- |EnableSSE |M64TYPE_BOOL |Enable SSE optimizations for capable CPUs |- |EnableVertexShader |M64TYPE_BOOL |Use GPU vertex shader |- |SkipFrame |M64TYPE_BOOL |If this option is enabled, the plugin will skip every other frame |- |TexRectOnly |M64TYPE_BOOL |If enabled, texture enhancement will be done only for TxtRect ucode |- |SmallTextureOnly |M64TYPE_BOOL |If enabled, texture enhancement will be done only for textures width+height<=128 |- |LoadHiResTextures |M64TYPE_BOOL |Enable hi-resolution texture file loading |- |LoadHiResCRCOnly |M64TYPE_BOOL |Filter hi-resolution texture filenames based only on the CRC and ignore format+size tags (Glide64 compatibility) |- |DumpTexturesToFiles |M64TYPE_BOOL |Enable texture dumping |- |ShowFPS |M64TYPE_BOOL |Display On-screen FPS |- |FogMethod |M64TYPE_INT |Enable, Disable or Force fog generation (0=Disable, 1=Enable n64 choose, 2=Force Fog) |- |Mipmapping |M64TYPE_INT |Use Mipmapping? 0=no, 1=nearest, 2=bilinear, 3=trilinear |- |MultiSampling |M64TYPE_INT |Enable/Disable MultiSampling (0=off, 2,4,8,16=quality) |- |TextureEnhancement |M64TYPE_INT |Primary texture filter (0=None, 1=2X, 2=2XSAI, 3=HQ2X, 4=LQ2X, 5=HQ4X, 6=Sharpen, 7=Sharpen More, 8=External, 9=Mirrored) |- |TextureEnhancementControl |M64TYPE_INT |Secondary texture filter (0 = none, 1-4 = filtered) |- |ForceTextureFilter |M64TYPE_INT |Force to use texture filtering or not (0=auto: n64 choose, 1=force no filtering, 2=force filtering) |- |TextureQuality |M64TYPE_INT |Color bit depth to use for textures (0=default, 1=32 bits, 2=16 bits |- |OpenGLDepthBufferSetting |M64TYPE_INT |Z-buffer depth (only 16 or 32) |- |ColorQuality |M64TYPE_INT |Color bit depth for rendering window (0=32 bits, 1=16 bits) |- |OpenGLRenderSetting |M64TYPE_INT |OpenGL rendering level to support (0=auto, 1=OGL_1.1, 2=OGL_1.2, 3=OGL_1.3, 4=OGL_1.4, 5=OGL_1.4_V2, 6=OGL_TNT2, 7=NVIDIA_OGL, 8=OGL_FRAGMENT_PROGRAM) |- |AnisotropicFiltering |M64TYPE_INT |Enable/Disable Anisotropic Filtering for Mipmapping (0=no filtering, 2-16=quality). This is uneffective if EnableMipmapping is false. If the given value is to high to be supported by your graphic card, the value will be the highest value your graphic card can support. Better result with Trilinear filtering |- |ForcePolygonOffset |M64TYPE_BOOL |If true, use polygon offset values specified below (default=False). This can be used to eliminate stitching artifacts in textures and shadows, which are typically only a problem in mobile/embedded platforms (e.g. Android), where chipsets are inconsistent in their implementation of glPolygonOffset. |- |PolygonOffsetFactor |M64TYPE_FLOAT |Specifies a scale factor that is used to create a variable depth offset for each polygon. Ignored if ForcePolygonOffset is False, and typically only relevant for mobile/embedded platforms. This value is typically equal to PolygonOffsetUnits, and is found through trial and error. Mario's shadow in Super Mario 64 is a good test case when tuning this value. If the shadow flickers, use a larger magnitude for the float settings. Do not use a larger value than necessary to eliminate artifacts. As a guideline, typical values for mobile chipsets circa 2012-2014 are positive or negative values in the range 0.001 to 2. |- |PolygonOffsetUnits |M64TYPE_FLOAT |Is multiplied by an implementation-specific value to create a constant depth offset. Ignored if ForcePolygonOffset is False, and typically only relevant for mobile/embedded platforms. This value is typically equal to PolygonOffsetFactor, and is found through trial and error. Mario's shadow in Super Mario 64 is a good test case when tuning this value. If the shadow flickers, use a larger magnitude for the float settings. Do not use a larger value than necessary to eliminate artifacts. As a guideline, typical values for mobile chipsets circa 2012-2014 are positive or negative values in the range 0.001 to 2. |} === Input-SDL === The Mupen64Plus-Input-SDL plugin uses a separate config section for each simulated N64 controller. The sections are named: Input-SDL-Control1, Input-SDL-Control2, Input-SDL-Control3, and Input-SDL-Control4. The 4 sections all contain the same parameters. General-purpose Controller Configuration Parameters {| border="1" !Parameter Name!!Type!!Usage |- |version |M64TYPE_FLOAT |Mupen64Plus Input-SDL config parameter set version number. Please don't change. |- |mode |M64TYPE_INT |Controller configuration mode: 0=Fully Manual, 1=Auto with named SDL Device, 2=Fully automatic |- |device |M64TYPE_INT |Specifies which joystick is bound to this controller: -1=No joystick, 0 or more= SDL Joystick number |- |name |M64TYPE_STRING |SDL joystick name (or Keyboard) |- |plugged |M64TYPE_BOOL |Specifies whether this controller is 'plugged in' to the simulated N64 |- |plugin |M64TYPE_INT |Specifies which type of expansion pak is in the controller: 1=None, 2=Mem pak, 5=Rumble pak |- |mouse |M64TYPE_BOOL |If True, then mouse buttons may be used with this controller, and mouse movement will map to X/Y analog stick |- |MouseSensitivity |M64TYPE_STRING |The sensitivity coefficients for the mouse to move the N64 controller axis value from 0. For X, Y axes. Values must be positive. |- |AnalogDeadzone |M64TYPE_STRING |The minimum absolute value of the SDL analog joystick axis to move the N64 controller axis value from 0. For X, Y axes. |- |AnalogPeak |M64TYPE_STRING |An absolute value of the SDL joystick axis >= AnalogPeak will saturate the N64 controller axis value (at 80). For X, Y axes. For each axis, this must be greater than the corresponding AnalogDeadzone value |- |} Digital Controller Configuration These parameters are used to bind input events with N64 Controller button presses. There are 14 simulated buttons and 2 special buttons for switching between the Mem Pak and Rumble Pak expansion units. Each configuration parameter is a string which specifies input events which will map to the given N64 button. The configuration strings consist of zero or more input event words. A list of available input event words is given here: {| border="1" !Input Event Word!!Usage |- |key(<keysym>) |<keysym> = SDLK_* key symbol enumerated type |- |button(<num>) |<num> = SDL Joystick Button Number (0 or greater) |- |axis(<num><dir>) |<num> = SDL Joystick Axis Number, <dir> = axis direction (+ = positive, - = negative) |- |axis(<num><dir>,<deadzone>) |<num> = SDL Joystick Axis Number, <dir> = axis direction (+ = positive, - = negative), <deadzone> = minimum axis value (max 32767) to activate button; default 6000 |- |hat(<num> <dir>) |<num> = SDL Joystick Hat Number, <dir> = hat direction (Up, Down, Left, or Right) |- |mouse(<num>) |<num> = mouse button number (1 = left button, 2 = middle, 3 = right, etc) |- |}
{| border="1" !Parameter Name!!Type!!Usage |- |DPad R |M64TYPE_STRING |Input event string for mapping the Right button on the D-pad |- |DPad L |M64TYPE_STRING |Input event string for mapping the Left button on the D-pad |- |DPad D |M64TYPE_STRING |Input event string for mapping the Down button on the D-pad |- |DPad U |M64TYPE_STRING |Input event string for mapping the Up button on the D-pad |- |Start |M64TYPE_STRING |Input event string for mapping the Start button |- |Z Trig |M64TYPE_STRING |Input event string for mapping the Z trigger |- |B Button |M64TYPE_STRING |Input event string for mapping the "B" button |- |A Button |M64TYPE_STRING |Input event string for mapping the "A" button |- |C Button R |M64TYPE_STRING |Input event string for mapping the Right "C" button |- |C Button L |M64TYPE_STRING |Input event string for mapping the Left "C" button |- |C Button D |M64TYPE_STRING |Input event string for mapping the Down "C" button |- |C Button U |M64TYPE_STRING |Input event string for mapping the Up "C" button |- |R Trig |M64TYPE_STRING |Input event string for mapping the Right trigger |- |L Trig |M64TYPE_STRING |Input event string for mapping the Left trigger |- |Mempak switch |M64TYPE_STRING |Input event string for toggling the Memory Pak unit |- |Rumblepak switch |M64TYPE_STRING |Input event string for toggling the Rumble Pak unit |- |} Analog Controller Configuration These parameters are used to bind input events with N64 Controller analog stick movements. There are only 2 analog stick axes, X and Y. Each configuration parameter is a string which specifies input events which will map to the given N64 controller axis movement. The configuration strings consist of zero or more input event words. A list of available input event words is given here: {| border="1" !Input Event Word!!Usage |- |key(<key_a>,<key_b>) |<key_a> = SDLK_* key symbol for up/left movement. <key_b> = SDLK_* key symbol for down/right movement. The strength of these movements can be modulated with the Left-Shift and Left-Control keys. |- |button(<num_a>,<num_b>) |<num_a> = SDL Joystick Button Number for up/left movement. <num_b> = SDL Joystick Button Number for down/right movement. |- |axis(<num_a><dir_a>,<num_b><dir_b>) |<num_a> = SDL Joystick Axis Number for up/left movement, <dir_a> = axis direction for up/left movement (+ = positive, - = negative). <num_b> = SDL Joystick Axis Number for down/right movement, <dir_b> = axis direction for down/right movement. |- |hat(<num> <dir_a> <dir_b>) |<num> = SDL Joystick Hat Number, <dir_a> = hat direction for up/left movement (Up, Down, Left, or Right), <dir_b> = hat direction for right/down movement |- |}
{| border="1" !Parameter Name!!Type!!Usage |- |Y Axis |M64TYPE_STRING |Input event string for mapping the Y axis (up/down) of the analog stick |- |X Axis |M64TYPE_STRING |Input event string for mapping the X axis (left/right) of the analog stick |- |} mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-API-Versioning.mediawiki000066400000000000000000000330041464506436200304010ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus v2.0 API Versioning = == Goal == The Mupen64Plus API versioning scheme was invented to give a more friendly and less confusing experience for users as the various components evolve over time. There are 6 basic components to the Mupen64Plus system, which may be independently built and installed: # The Front-end UI application # The Core emulator library # The Video plugin # The Audio plugin # The Input plugin # The RSP plugin These components interact with each other in several different ways. The design goal of the versioning scheme is to gracefully handle all situations in which two components support different versions of their common API (due to one component being newer than the other). In particular, each pair of components sharing a common API must discover whether or not they are compatible with each other. They must make this determination early enough in the startup process to inform the user of an incompatibility and gracefully exit the software if necessary without crashing. There are 2 different decisions that pertain to the compatibility determination: # Major API version. The various API version numbers are 32-bit. The major version number is stored in the upper 16 bits, and the minor version number is in the lower 16 bits. If two components have different major API version numbers, then they are definitely incompatible. # Minor API version. If two components with a common API have different minor version numbers, then the newer component may decide whether or not it can interact with the older component based upon the older component's version number. The newer component may optionally disable new features and still retain backwards compatibility, or it may refuse to operate with the older component. This decision is left to the component author when new features are added. == Basic Design == In mupen64plus-core/src/plugin/plugin.h, the following macros are defined: #define RSP_API_MAJOR_VERSION 0x20000 #define GFX_API_MAJOR_VERSION 0x20000 #define AUDIO_API_MAJOR_VERSION 0x20000 #define INPUT_API_MAJOR_VERSION 0x20000 In mupen64plus-core/src/main/version.h, the following macros are defined: #define FRONTEND_API_VERSION 0x020000 #define CONFIG_API_VERSION 0x020000 #define DEBUG_API_VERSION 0x020000 #define VIDEXT_API_VERSION 0x020000 # When the front-end application calls the CoreStartup() function, it passes it's Core<-->Front-end API version to the core. If the API major version numbers for the core and front-end don't match, the core will return from this function with a failure code of M64ERR_INCOMPATIBLE. # The Console-UI front-end also checks for API compatibility, during the AttachCoreLib() function call. It is not strictly necessary for a front-end application to verify the API compatibility with the core, since the core will also check during CoreStartup(). However, by doing so, an updated front-end may detect a core library using a newer (but backwards-compatible) API, and enable some extra features as a result of the expanded API. # At the time each plugin is attached to the core (during CoreAttachPlugin function call), the core checks the version number of the plugin API by calling the PluginGetVersion function. If the major version number of the plugin's reported API (APIVersion & 0xffff0000) does not match the corresponding version number for that plugin type in the core (defined in plugin.h), then the plugin is incompatible and cannot be attached to the core. Currently the plugins have no way to request the major version number required for a particular plugin type in the core library. # The emulator core exports several different API groups which may be used by the front-end and plugin modules. Currently, these groups are: Front-end, Config, Debug, and Video Extension. A front-end application or any plugin may call the CoreGetAPIVersions() function to retrieve the API version numbers for these groups. Any plugin or front-end which can use any updated (not present in the original "2.0" API) functions in one of these groups should call the core's CoreGetAPIVersions() function (during PluginStartup for a plugin or at core attach time for a front-end) to check the version # of the API supported by the core, and react accordingly. # All front-ends and plugins should verify API version compatibility for the Config API. == Handling Future Changes == === New feature added to a plugin library === If the feature is backwards-compatible with older cores, then plugin API minor version will be bumped. Otherwise, major version number will be bumped. If change is backwards-compatible, then newest core can test the plugin's API version and only enable the feature if present. === New feature added to Core<-->Front-end API === Typically this will happen when a new function or a new feature of an existing function is added to the core. If the older front-ends will still be compatible with newer cores, then the minor version number of the front-end API will be bumped. Otherwise the major version number will be bumped. A newer front-end can check the version of the API supported by the core and choose whether to retain backwards-compatibility with older cores or refuse to interoperate. === New feature added to Core Config API === If older plugins can still use the Core Config API with the new feature, then Config API minor version will be bumped. Otherwise, major version number will be bumped. Newer plugins should check the Core's Config API version and maintain backwards compatibility with older cores if possible. === New feature added to Core Debug API === If older front-ends can still use the Core Debug API with the new feature, then Debug API minor version number will be bumped. Otherwise, major version number will be bumped. Newer front-end applications should check the Core's Debug API version and maintain backwards compatibility with older cores if possible. === New feature added to Video Extension API === This is the most complicated interface, because it involves 3 components: the video plugin, the core, and the front-end application. If older video plugins can still use the newer Video Extension API with the core, *and* newer front-end applications can work with older cores, then the Video Extension API minor version number will be bumped. Otherwise, the major version number will be bumped. Newer video plugins can check the Core's Video Extension API version and maintain backwards compatibility with older cores if possible, otherwise they can refuse and give a compatibility error. Front-end applications (such as the default console-ui) which do not hook into the Video Extension do not need to check the Core's Video Extension API version. However, front-end applications which do hook into the Video Extension must check the API version. If the Core and Front-end have different API major version numbers, then they are incompatible. Also if the Core has a *newer* minor version than the front-end, then they are incompatible. This is a unique restriction, and it must be checked and verified by the front-end; the Core has no way to check this. == Changelog == * Version 2.0.0 is the base for all APIs * '''FRONTEND_API_VERSION''' version 2.0.1: ** added "m64p_command" type "M64CMD_CORE_STATE_SET", handled by CoreDoCommand() ** added "m64p_core_param" type "M64CORE_SPEED_LIMITER", handled by "M64CMD_CORE_STATE_QUERY" and "M64CMD_CORE_STATE_SET" commands * '''FRONTEND_API_VERSION''' version 2.0.2: ** added "m64p_command" types: *** M64CMD_GET_SCREEN_WIDTH *** M64CMD_GET_SCREEN_HEIGHT *** M64CMD_READ_SCREEN *** M64CMD_VOLUME_UP *** M64CMD_VOLUME_DOWN *** M64CMD_VOLUME_GET_LEVEL *** M64CMD_VOLUME_SET_LEVEL *** M64CMD_VOLUME_MUTE *** M64CMD_RESET *** M64CMD_ADVANCE_FRAME ** extend command M64CMD_STATE_SAVE to support saving uncompressed PJ64 savestate files as well as zip compressed * '''FRONTEND_API_VERSION''' version 2.1.0: ** removed "m64p_command" types: *** M64CMD_GET_SCREEN_WIDTH *** M64CMD_GET_SCREEN_HEIGHT *** M64CMD_VOLUME_UP *** M64CMD_VOLUME_DOWN *** M64CMD_VOLUME_GET_LEVEL *** M64CMD_VOLUME_SET_LEVEL *** M64CMD_VOLUME_MUTE ** added new "m64p_core_param" types: *** M64CORE_VIDEO_SIZE *** M64CORE_AUDIO_VOLUME *** M64CORE_AUDIO_MUTE *** M64CORE_INPUT_GAMESHARK *** M64CORE_STATE_LOADCOMPLETE *** M64CORE_STATE_SAVECOMPLETE * '''FRONTEND_API_VERSION''' version 2.1.1: ** Core command M64CMD_CORE_STATE_SET will now accept M64CORE_VIDEO_SIZE parameter *** will call the video plugin function ResizeVideoOutput() * '''FRONTEND_API_VERSION''' version 2.1.2: ** added "M64CMD_SET_MEDIA_LOADER" command to allow frontend to specify several media files (such as GB cartridge ROM and RAM files). * '''CONFIG_API_VERSION''' version 2.1.0: ** add new function "ConfigSaveSection()" to save only a single config section to disk * '''CONFIG_API_VERSION''' version 2.2.0: ** add new function "ConfigHasUnsavedChanges()" to determine if a given Section (or all sections) of the Mupen64Plus Core configuration file has been modified since it was last saved or loaded. ** add new function "ConfigRevertChanges()" to revert changes previously made to one section of the configuration file, so that it will match with the configuration at the last time that it was loaded from or saved to disk. * '''CONFIG_API_VERSION''' version 2.3.0: ** add new function "ConfigSetParameterHelp()" sets the value of one of the emulator's configuration parameters. * '''CONFIG_API_VERSION''' version 2.3.1: ** add new functions "ConfigExternalOpen()" "ConfigExternalClose()" "ConfigExternalGetParameter()" that allows plugins to leverage the core INI parser to read config files. * '''DEBUG_API_VERSION''' version 2.0.1: ** add new function "DebugBreakpointTriggeredBy()" which allows a front-end application to determine which memory address and action (read, write, execute) caused a breakpoint to fire. ** add new function "DebugVirtualToPhysical()" which allows a front-end application to find the physical address which corresponds to a given virtual address. * '''VIDEO_API_VERSION''' version 2.1.0: ** video render callback function now takes a boolean (int) parameter, which specifies whether the video frame has been re-drawn since the last time the render callback was called. This allows us to take screenshots without the On-Screen-Display text * '''VIDEO_API_VERSION''' version 2.2.0: ** add (optional) ResizeVideoOutput function in video plugin. If this function is not present in video plugin, then resizing the output video window will not work. * '''VIDEXT_API_VERSION''' version 3.0.0: ** add VidExt_ResizeWindow() function in video extension. This function is called by the video plugin to notify the window manager (SDL if no video extension is registered by the front-end) that the OpenGL render window size should change. ** add m64p_video_flags parameter to the VidExt_SetVideoMode() function. Currently the flags are only used to notify the window manager that resizing is supported by the video plugin, and it should create a resizable window if possible. This may be extended in the future to support other features. * '''VIDEXT_API_VERSION''' version 3.1.0: ** add VidExt_GL_GetDefaultFramebuffer() function in video extension. This function should be called to get the name of the default FBO. * '''VIDEXT_API_VERSION''' version 3.2.0: ** add the VidExt_ListFullscreenRates and VidExt_SetVideoModeWithRate functions, which allow setting and getting the fullscreen refresh rate * '''INPUT_API_VERSION''' version 2.0.1: ** add (optional) RenderCallback function to input plugin. This function is called by the core after rendering on screen text (OSD) and before the graphics plugin swaps the buffers. The purpose of this function is to enable the input plugin to draw on screen content, for example buttons in a touch input plugin. If this function is not present the core will ignore it and on screen rendering by the input plugin will be disabled. * '''INPUT_API_VERSION''' version 2.1.0: ** This is not an API change, but reflects an internal behavior change. On March 23, 2018, the SDL_PumpEvents() call was moved from being in the core to only being in the input plugin. After this point, newer builds of the core would not register keyboard input when used with older builds of the input plugin, which did not call SDL_PumpEvents. As such, core libraries with INPUT_API_VERSION of 2.1.0 will refuse to work with older input plugins. * '''FRONTEND_API_VERSION''' version 2.1.3: ** added "M64CMD_PIF_OPEN" command to allow using a binary PIF Boot ROM (instead of the included HLE implementation). * '''FRONTEND_API_VERSION''' version 2.1.4: ** added "M64CMD_ROM_SET_SETTINGS" command to allow setting ROM settings for the currently opened ROM until the ROM is closed. * '''CONFIG_API_VERSION''' version 2.3.2: ** add ConfigOverrideUserPaths() function to allow front-ends to override user paths. * '''INPUT_API_VERSION''' version 2.1.1: ** add optional functions: SendVRUWord(), SetMicState(), ReadVRUResults(), ClearVRUWords(), SetVRUWordMask(). These functions add support for the VRU (Voice Recognition Unit). Also added a new int to the CONTROL struct: Type. Type can be CONT_TYPE_STANDARD (0) or CONT_TYPE_VRU (1). * '''FRONTEND_API_VERSION''' version 2.1.5: ** added "M64CMD_DISK_OPEN" and "M64CMD_DISK_CLOSE" commands to allow booting 64DD disks without requiring a cartridge. * '''FRONTEND_API_VERSION''' version 2.1.6: ** added "m64p_core_param" type: *** M64CORE_SCREENSHOT_CAPTURED * '''VIDEXT_API_VERSION''' version 3.3.0: ** add the VidExt_InitWithRenderMode, VidExt_VK_GetSurface and VidExt_VK_GetInstanceExtensions functions, which allows a plugin to use Vulkan and a front-end to support Vulkan mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Core-API-v1.0.mediawiki000066400000000000000000000153761464506436200276440ustar00rootroot00000000000000Please note: as of January 2011, this API is a work in progress.
The core Mupen64Plus v2.0 modules are complete, but work on GUI front-end applications is ongoing. To view the design proposal which preceded this API definition, go to [[Mupen64Plus v2.0 Design Proposal 3|Design Proposal 3]]. == New Architecture == Earlier versions of Mupen64Plus (and other plugin-based N64 emulators) used a single monolithic application (containing the emulator core) and four plugins. The plugins were dynamically-loaded libraries, and the application used one plugin of each type: Video, Audio, Input, and RSP. Each plugin and the application contained its own GUI code for user interface, and each plugin and the application were individually responsible for finding their own data files and finding, loading, parsing, and storing their own configuration data files. This was an acceptable architecture for emulators which were only designed to run on a single platform (such as Windows), but causes a lot of developer and user headaches when applied to a cross-platform emulator such as Mupen64Plus. For this reason, we are re-designing the layout of the emulator to solve some of the problems caused by the old architecture. Under the new architecture, the old monolithic emulator application is split into two parts: a core emulator library and a main application, called the front-end. The front-end is primarily responsible for the user interface. All GUI code will be removed from the core and plugin libraries. The primary function of the core library is to emulate the R4300 CPU and memory system, attaching the plugins to form a full N64 system emulator. The core library also contains some utility functions which may be used by the front-end and plugins, such as a configuration parameter handler. == High-level Usage == The expected sequence of operations which will be taken by the front-end application are as follows: # Load core library (libmupen64plus.so) and set function pointers # Call CoreGetVersion, check core version and capabilities # Call CoreStartup to initialize the core library # Load front-end configuration from core config API or through own mechanism # Find plugins, open dynamic libraries, call PluginStartup for each # Enter message loop for user interaction # If user selects ROM and presses Play: #* Load and de-compress the ROM #* Use CoreDoCommand to open the ROM #* Call CoreAttachPlugin to attach selected plugins to core #* Use CoreDoCommand to start emulation #* When emulation is finished, call CoreDetachPlugin on all plugins, then close the ROM == Versioning == === [[Mupen64Plus v2.0 API Versioning|API Versioning Scheme]] === Since the Mupen64Plus emulator comprises 6 different software modules which can be mixed and matched (the front-end app, the core library, and 4 plugins), and the interfaces between these modules change over time, there are many hard-to-diagnose bugs which could show up due to incompatibilities between these different modules. For this reason, we use a comprehensive versioning scheme which allows any 2 components to determine whether or not they are compatible, and to support forward and backward compatibility as necessary. This scheme is described in detail in this document. == Core API == === [[Mupen64Plus v2.0 Core Basic|Basic Core Functions]] === These two functions (PluginGetVersion and CoreErrorMessage) are utility functions and may be called at any time (even before core startup). These functions are used by both the front-end and the plugins. === [[Mupen64Plus v2.0 Core Front-End|Front-End Functions]] === There are several types of functions here, which are exported from the Core library to be used by the front-end. There are 'housekeeping' functions, for startup and shutdown, and attaching and detaching plugins. There is also a Command API which is used for many simple functions such as loading, executing, or stopping a ROM. Finally the Cheat API is here, for adding and removing cheat functions. === [[Mupen64Plus v2.0 Core Video Extension|Video Extension API]] === These functions are exported from the Core library for use by the video plugin. These functions are used for high-level video setup tasks such as enumerating available screen resolutions, setting the video mode, window caption, OpenGL attributes, and fullscreen mode. The video extension API allows for the abstraction of these functions away from the hard-coded SDL function calls currently in the video plugins, so that a front-end may override these functions and provide its own video API. === [[Mupen64Plus v2.0 Core Debugger|Debugger Functions]] === These are the debugger functions, which are also called only from the front-end. Most of these functions will return with an error if the core library was not compiled with the debugger enabled. A front-end may examine the Capabilities value returned by the CoreGetVersion function to determine if the core library was built with the debugger enabled. === [[Mupen64Plus v2.0 Core Config|Configuration API]] === These configuration functions are exported from the core library and are used by the core and the plugins to store all of their persistent configuration parameters. The front-end application may also use these functions to store its configuration options, or it may use a different mechanism. This section also contains two Operating System Abstraction functions. These functions are used by the core, plugins, and the front-end to find full filepaths to shared data files and user-specific data files. == Plugin API == === [[Mupen64Plus v2.0 Plugin API|Plugin API]] === This section lists all of the functions which are exported by the plugins. The front-end application should only use the PluginStartup, PluginShutdown, and PluginGetVersion functions. All other functions will only be called from the core. == Netplay == Starting with version 2.6, Mupen64Plus has support for playing games with multiple players over a network. To support this, a few new command types were added to the CoreDoCommand function, as documented in [[Mupen64Plus v2.0 Core Front-End|front-end functions]]. The core handles the network I/O on its own, and the interface for handling netplay from the perspective of the front-end is very high level. The design of the netplay feature is such that a separate piece of server software (not part of Mupen64Plus) is also required. An example of such a server program is available [https://github.com/loganmc10/m64p-netplay-server here] from [https://github.com/loganmc10 loganmc10] on github. A description of the network protocol which is used for communication between the client emulators and the netplay server is available [[Mupen64Plus v2.0 Core Netplay Protocol|here]]. mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Core-Basic.mediawiki000066400000000000000000000063201464506436200275570ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus v2.0 Basic Core API = Most libmupen64plus functions return an m64p_error return code, which is an enumerated type defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. Front-end code should check the return value of each call to a libmupen64plus function. {| border="1" |Prototype |'''m64p_error PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)''' |- |Input Parameters |'''PluginType''' Pointer to an enumerated type to store the plugin type. The value M64PLUGIN_CORE will always be stored.
'''PluginVersion''' Pointer to an integer to store the version number of the Mupen64Plus core. Version number 2.1.3 would be stored as 0x00020103.
'''APIVersion''' Pointer to an integer to store the version number of the Core--Front-end API used by the Mupen64plus core library.
'''PluginNamePtr''' Pointer to a const character pointer to receive the name of the core library. The const char * which is returned must point to a persistent string (ie, not stored on the stack).
'''Capabilities''' Pointer to an integer to store a logically-or'd set of flags which specify the capabilities of the core which were built into the library during compilation. These are defined in the m64p_core_caps enumerated type, defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. |- |Usage |This function retrieves version information from the core library. This function is the same for the core library and the plugins, so that a front-end may examine all shared libraries in a directory and determine their types. Any of the input parameters may be set to NULL and this function will succeed but won't return the corresponding information. |}
{| border="1" |Prototype |'''m64p_error CoreGetAPIVersions(int *ConfigVersion, int *DebugVersion, int *VidextVersion, int *ExtraVersion)''' |- |Input Parameters |'''ConfigVersion''' Pointer to an integer to store the version number of the Config API exported by the Mupen64plus core library.
'''DebugVersion''' Pointer to an integer to store the version number of the Debug API exported by the Mupen64plus core library.
'''VidextVersion''' Pointer to an integer to store the version number of the Video Extension API exported by the Mupen64plus core library.
'''ExtraVersion''' Pointer to an integer to store an API version number for future use. Currently set to 0.
|- |Usage |This function retrieves API version information from the core library. This function may be used by either the front-end application or any plugin modules. Any of the input parameters may be set to NULL and this function will succeed but won't return the corresponding information. |}
{| border="1" |Prototype |'''const char * CoreErrorMessage(m64p_error ReturnCode)''' |- |Input Parameters |'''ReturnCode''' Enumerated type containing an error code. |- |Usage |This function returns a pointer to a NULL-terminated string giving a human-readable description of the error. |}
mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Core-Config.mediawiki000066400000000000000000000576351464506436200277620ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus v2.0 Configuration API = Most libmupen64plus functions return an m64p_error return code, which is an enumerated type defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. Front-end code should check the return value of each call to a libmupen64plus function. == Selector Functions == These functions are used by the front-end to discover the sections in the configuration file, open a section, discover parameters within a section, and find out if a section has been changed. {| border="1" |Prototype |'''m64p_error ConfigListSections(void *context, void (*SectionListCallback)(void * context, const char * SectionName))''' |- |Input Parameters |'''context''' Void pointer to be passed to the SectionListCallback function
'''SectionListCallback''' Pointer to function in front-end for receiving the name of every section in the Mupen64Plus Core configuration data. This function will be called once for each section in the core configuration data structure, and then the ConfigListSections() function will return. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''SectionListCallback''' pointer cannot be NULL. |- |Usage |This function is called to enumerate the list of Sections in the Mupen64Plus Core configuration file. It is expected that there will be a section named "Core" for core-specific configuration data, "Graphics" for common graphics options, and one section for each plugin library. |}
{| border="1" |Prototype |'''m64p_error ConfigOpenSection(const char *SectionName, m64p_handle *ConfigSectionHandle)''' |- |Input Parameters |'''SectionName''' Name of the Mupen64Plus configuration section to open. This name is case-insensitive. If no section exists with the given name, a new one will be created with no parameters. This name may consist of any ASCII characters between 32 and 127 except brackets "[]".
'''ConfigSectionHandle''' This is a handle (defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]) which is required to be used for subsequent calls to core configuration functions to list, retrieve, or set configuration parameters. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''SectionName''' and '''ConfigSectionHandle''' pointers cannot be NULL. |- |Usage |This function is used to give a configuration section handle to the front-end which may be used to read or write configuration parameter values in a given section of the configuration file. |}
{| border="1" |Prototype |'''m64p_error ConfigListParameters(m64p_handle ConfigSectionHandle, void *context, void (*ParameterListCallback)(void * context, const char *ParamName, m64p_type ParamType))''' |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''context''' Void pointer to be passed to the ParameterListCallback function
'''ParameterListCallback''' Pointer to function in front-end for receiving the name of every parameter in the given section of the Mupen64Plus Core configuration data. This function will be called once for each parameter in the section, and then the ConfigListParameters() function will return. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''' and '''ParameterListCallback''' pointers cannot be NULL. |- |Usage |This function is called to enumerate the list of Parameters in a given Section of the Mupen64Plus Core configuration file. |}
{| border="1" |Prototype |'''int ConfigHasUnsavedChanges(const char *SectionName)''' |- |Input Parameters |'''SectionName''' Name of the Mupen64Plus configuration section to check for unsaved changes. This name is case-insensitive. If this pointer is NULL or points to an empty string, then all sections are checked. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function.
This function was added in the Config API version 2.2.0. |- |Usage |This function is called to determine if a given Section (or all sections) of the Mupen64Plus Core configuration file has been modified since it was last saved. A return value of 0 means there are no unsaved changes, while a 1 will be returned if there are unsaved changes. |} == Modifier Functions == These functions are used for deleting parts of the configuration list or saving the configuration data to disk. {| border="1" |Prototype |'''m64p_error ConfigDeleteSection(const char *SectionName)''' |- |Input Parameters |'''SectionName''' Name of the Mupen64Plus configuration section to delete. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except brackets "[]".
|- |Requirements |The Mupen64Plus library must already be initialized before calling this function. |- |Usage |This function deletes a section from the Mupen64Plus configuration data. |}
{| border="1" |Prototype |'''m64p_error ConfigSaveFile(void)''' |- |Input Parameters |N/A |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. |- |Usage |This function saves the Mupen64Plus configuration file to disk. |}
{| border="1" |Prototype |'''m64p_error ConfigSaveSection(const char *SectionName)''' |- |Input Parameters |'''SectionName''' Name of the Mupen64Plus configuration section to save. This name is case-insensitive. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The named section must exist in the current configuration.
This function was added in the Config API version 2.1.0. |- |Usage |This function saves one section of the current Mupen64Plus configuration to disk, while leaving the other sections unmodified. |}
{| border="1" |Prototype |'''m64p_error ConfigRevertChanges(const char *SectionName)''' |- |Input Parameters |'''SectionName''' Name of the Mupen64Plus configuration section to modify. This name is case-insensitive. This pointer cannot be NULL. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The named section must exist in the current configuration.
This function was added in the Config API version 2.2.0. |- |Usage |This function reverts changes previously made to one section of the current Mupen64Plus configuration file, so that it will match with the configuration at the last time that it was loaded from or saved to disk. |} == Generic Get/Set Functions == These functions should be used for reading or writing configuration values in most cases. {| border="1" |Prototype |'''m64p_error ConfigSetParameter(m64p_handle ConfigSectionHandle, const char *ParamName, m64p_type ParamType, const void *ParamValue)''' |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''ParamName''' NULL-terminated string containing the name of the parameter whose value is being set. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except the equals and hash signs, and may not end in a space.
'''ParamType''' An m64p_type value giving the type of the data object that '''ParamValue''' points to. If this is different from the native data representation used by the core, it will be converted into the type used by the core.
'''ParamValue''' Pointer to data object containing the value of the parameter to be set.
|- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''', '''ParamName''' and '''ParamValue''' pointers cannot be NULL. |- |Usage |This function sets the value of one of the emulator's configuration parameters in the section which is represented by '''ConfigSectionHandle'''. |}
{| border="1" |Prototype |'''m64p_error ConfigSetParameterHelp(m64p_handle ConfigSectionHandle, const char *ParamName, const char *ParamHelp)''' |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''ParamName''' NULL-terminated string containing the name of the parameter whose help string is being set. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except the equals and hash signs, and may not end in a space.
'''ParamHelp''' NULL-terminated string containing some human-readable information about the usage of this parameter. Can be NULL.
|- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''' and '''ParamName''' pointers cannot be NULL. |- |Usage |This function sets the help string of one of the emulator's configuration parameters in the section which is represented by '''ConfigSectionHandle'''. |}
{| border="1" |Prototype |'''m64p_error ConfigGetParameter(m64p_handle ConfigSectionHandle, const char *ParamName, m64p_type ParamType, void *ParamValue, int MaxSize)''' |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''ParamName''' NULL-terminated string containing the name of the parameter whose value is being retrieved. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except the equals and hash signs, and may not end in a space.
'''ParamType''' An m64p_type value giving the type of the data object that '''ParamValue''' points to. If this is different from the native data representation used by the core, it will be converted into the type given by '''ParamType'''.
'''ParamValue''' Pointer to data object to receive the value of the parameter being retrieved.
'''MaxSize''' Size (in bytes) of the data object that '''ParamValue''' points to. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''', '''ParamName''' and '''ParamValue''' pointers cannot be NULL. |- |Usage |This function retrieves the value of one of the emulator's parameters in the section which is represented by '''ConfigSectionHandle'''. |}
{| border="1" |Prototype |'''m64p_error ConfigExternalOpen(const char *FileName, m64p_handle *Handle)''' |- |Return Value |M64ERR_SUCCESS if the config file was successfully opened. |- |Input Parameters |'''FileName''' The path to the config file.
'''Handle''' A pointer to a m64p_handle. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. '''FileName''' cannot be NULL. |- |Usage |This function opens an external config file and reads the contents into memory. |}
{| border="1" |Prototype |'''m64p_error ConfigExternalClose(m64p_handle Handle)''' |- |Return Value |M64ERR_SUCCESS if the config file was successfully closed. |- |Input Parameters |'''Handle''' A m64p_handle that was previously passed to ConfigExternalOpen(). |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. '''Handle''' should have already been passed to ConfigExternalOpen(). |- |Usage |This function opens an external config file and reads the contents into memory. |}
{| border="1" |Prototype |'''m64p_error ConfigExternalGetParameter(m64p_handle Handle, const char *SectionName, const char *ParamName, char* ParamPtr, int ParamMaxLength)''' |- |Return Value |M64ERR_SUCCESS if ParamName was found and ParamPtr is populated with the result. |- |Input Parameters |'''Handle''' A m64p_handle that was previously passed to ConfigExternalOpen().
'''SectionName''' NULL-terminated string containing the name of the section to retrieve the parameter from.
'''ParamName''' NULL-terminated string containing the name of the parameter whose value is being retrieved.
'''ParamPtr''' An allocated char array that is at least as large as ParamMaxLength. The result, if found will be copied into this array.
'''ParamMaxLength''' The maximum number of bytes to be copied into ParamPtr. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. '''Handle''' should have already been passed to ConfigExternalOpen. The '''SectionName''' and '''ParamName''' pointers cannot be NULL. ParamPtr must be a pre-allocated char array that is at least as large as ParamMaxLength. |- |Usage |This functions allows a plugin to leverage the built-in ini parser to read any cfg/ini file. |}
{| border="1" |Prototype |'''m64p_error ConfigGetParameterType(m64p_handle ConfigSectionHandle, const char *ParamName, m64p_type *ParamType)''' |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''ParamName''' Pointer to a NULL-terminated string containing the name of the parameter whose type is being retrieved. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except the equals and hash signs, and may not end in a space.
'''ParamType''' Pointer to an m64p_type value to receive the type of the parameter indicated by '''ParamName'''. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''', '''ParamName''', and '''ParamType''' pointers cannot be NULL. |- |Usage |This function retrieves the type of one of the emulator's parameters in the section which is represented by '''ConfigSectionHandle'''. If there is no parameter with the given '''ParamName''', the error M64ERR_INPUT_NOT_FOUND will be returned. |}
{| border="1" |Prototype |'''const char * ConfigGetParameterHelp(m64p_handle ConfigSectionHandle, const char *ParamName)''' |- |Return Value |Pointer to a NULL-terminated string containing usage information for the '''ParamName''' parameter. May be NULL. |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''ParamName''' NULL-terminated string containing the name of the parameter for which usage information is being retrieved. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except the equals and hash signs, and may not end in a space. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''', and '''ParamName''' pointers cannot be NULL. |- |Usage |This function retrieves the help information about one of the emulator's parameters in the section which is represented by '''ConfigSectionHandle'''. |} == Special Get/Set Functions == These parameterized Get/SetDefault functions are provided for simplifying the task of handling default values within a single module. Each code module using the Core's configuration API should set the default values for all configuration parameters used by that module during its Startup() function. This allows the software to set up the default values automatically rather than storing them in a separate "default config file" which has proven problematic in the past. This also solves the problem which occurs when an upgraded module contains a new config parameter not present in the previous release. The special Get functions return the configuration value directly rather than writing them through a pointer and returning an error code. For this reason, these parameterized Get functions should only be used within a module which 'owns' the configuration section and set up its default values in the Startup() function. Because these functions cannot signal an error to the caller, a front-end should not use these functions to retrieve configuration values for the core or the plugins, unless the names of the parameters have been enumerated with ConfigListParameters and are therefore guaranteed to exist.
{| border="1" |Prototype |'''m64p_error ConfigSetDefaultInt(m64p_handle ConfigSectionHandle, const char *ParamName, int ParamValue, const char *ParamHelp)'''
'''m64p_error ConfigSetDefaultFloat(m64p_handle ConfigSectionHandle, const char *ParamName, float ParamValue, const char *ParamHelp)'''
'''m64p_error ConfigSetDefaultBool(m64p_handle ConfigSectionHandle, const char *ParamName, int ParamValue, const char *ParamHelp)'''
'''m64p_error ConfigSetDefaultString(m64p_handle ConfigSectionHandle, const char *ParamName, const char * ParamValue, const char *ParamHelp)''' |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''ParamName''' NULL-terminated string containing the name of the parameter whose value is being set. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except the equals and hash signs, and may not end in a space.
'''ParamValue''' Integer or null-terminated string pointer containing the value of the parameter to be set.
'''ParamHelp''' NULL-terminated string containing some human-readable information about the usage of this parameter. Can be NULL. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''' and '''ParamName''' pointers cannot be NULL. |- |Usage |This function is used to set the value of a configuration parameter if it is not already present in the configuration file. This may happen if a new user runs the emulator, or an upgraded module uses a new parameter, or the user deletes his or her configuration file. If a parameter named '''ParamName''' is already present in the given section of the configuration file, then no action will be taken and this function will return successfully. Otherwise, a new parameter will be created its value will be assigned to '''ParamValue'''. |}
{| border="1" |Prototype | {| |- |'''int''' || '''ConfigGetParamInt(m64p_handle ConfigSectionHandle, const char *ParamName)''' |- |'''float''' || '''ConfigGetParamFloat(m64p_handle ConfigSectionHandle, const char *ParamName)''' |- |'''int''' || '''ConfigGetParamBool(m64p_handle ConfigSectionHandle, const char *ParamName)''' |- |'''const char *''' || '''ConfigGetParamString(m64p_handle ConfigSectionHandle, const char *ParamName)''' |} |- |Input Parameters |'''ConfigSectionHandle''' An m64p_handle given by the '''ConfigOpenSection''' function.
'''ParamName''' NULL-terminated string containing the name of the parameter whose value is being retrieved. This name is case-insensitive. This name may consist of any ASCII characters between 32 and 127 except the equals and hash signs, and may not end in a space. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. The '''ConfigSectionHandle''' and '''ParamName''' pointers cannot be NULL. |- |Usage |This function retrieves the value of one of the emulator's parameters in the section which is represented by '''ConfigSectionHandle''', and returns the value directly to the calling function. If an errors occurs (such as if '''ConfigSectionHandle''' is invalid, or there is no configuration parameter named '''ParamName'''), then an error will be sent to the front-end via the DebugCallback() function, and either a 0 (zero) or an empty string will be returned. |}
{| border="1" |Prototype |'''m64p_error ConfigOverrideUserPaths(const char *DataPath, const char *CachePath)''' |- |Return Value |M64ERR_SUCCESS if overriding was successful. |- |Input Parameters |'''DataPath''' The path to path where user data is stored. if NULL, fallback to user data path.
'''CachePath''' The path to path where user cache data is stored. if NULL, fallback to user cache path.
|- |Requirements |The Mupen64Plus library must already be initialized before calling this function. |- |Usage |This function overrides user paths returned by ConfigGetUserDataPath() and ConfigGetUserCachePath() |} == OS-Abstraction Functions == {| border="1" |Prototype |'''const char * ConfigGetSharedDataFilepath(const char *filename)''' |- |Return Value |Pointer to a NULL-terminated string containing a full directory path and filename to a given shared data file, or NULL if this file was not found. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. |- |Usage |It is common for shared data files on Unix systems to be installed in different places on different systems. Therefore, this core function is provided to allow a plugin to retrieve a full pathname to a given shared data file. This type of file is intended to be shared among multiple users on a system, so it is likely to be read-only. Examples of these types of files include: the .ini files for Rice Video and Glide64, the font and Mupen64Plus.ini files for the core, and the cheat code files for the front-end. This function will first search in a directory given via the DataPath parameter to the '''CoreStartup''' function, then in a directory given by the SharedDataPath core configuration parameter, then in a directory which may be supplied at compile time through a Makefile or configure script option, and finally in some common system locations (such as /usr/share/mupen64plus and /usr/local/share/mupen64plus on Unix systems). |}
{| border="1" |Prototype |'''const char * ConfigGetUserConfigPath(void)''' |- |Return Value |Pointer to a NULL-terminated string containing the directory path to user-specific configuration files. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. |- |Usage |This function may be used by the plugins or front-end to get a path to the directory for storing user-specific configuration files. This will be the directory where the configuration file "mupen64plus.cfg" is located. |}
{| border="1" |Prototype |'''const char * ConfigGetUserDataPath(void)''' |- |Return Value |Pointer to a NULL-terminated string containing the directory path to user-specific data files. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. |- |Usage |This function may be used by the plugins or front-end to get a path to the directory for storing user-specific data files. This may be used to store files such as screenshots, saved game states, or hi-res textures. |}
{| border="1" |Prototype |'''const char * ConfigGetUserCachePath(void)''' |- |Return Value |Pointer to a NULL-terminated string containing the directory path to user-specific caching data files. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. |- |Usage |This function may be used by the plugins or front-end to get a path to the directory for storing user-specific caching data files. Files in this directory may be deleted by the user to save space, so critical information should not be stored here. This directory may be used to store files such as the ROM browser cache. |} mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Core-Debugger.mediawiki000066400000000000000000000371771464506436200303000ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus v2.0 Core Debugger API = Most libmupen64plus functions return an m64p_error return code, which is an enumerated type defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. Front-end code should check the return value of each call to a libmupen64plus function. == General Debugger Functions == {| border="1" |Prototype |'''m64p_error DebugSetCallbacks(void (*dbg_frontend_init)(void), void (*dbg_frontend_update)(unsigned int pc), void (*dbg_frontend_vi)(void))''' |- |Input Parameters |'''dbg_frontend_init''' Pointer to function which is called when debugger is initialized.
'''dbg_frontend_update''' Pointer to function which is called after debugger hits a breakpoint or executes one instruction in stepping mode.
'''dbg_frontend_vi''' Pointer to function which is called during each vertical interrupt. |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |This function is called by the front-end to supply debugger callback function pointers. If debugger is enabled and then later disabled within the GUI, this function may be called with NULL pointers in order to disable the callbacks. |}
{| border="1" |Prototype |'''m64p_error DebugSetCoreCompare(void (*dbg_core_compare)(unsigned int), void (*dbg_core_data_sync)(int, void *))''' |- |Input Parameters |'''dbg_core_compare''' Pointer to function which is called after each R4300 instruction, for comparing the operation of one R4300 emulator core against another.
'''dbg_core_data_sync''' Pointer to function which is used to transfer data from the sending emulator core to the receiving core, such as controller button press or movement data. |- |Requirements |The Mupen64Plus library must be initialized before calling this function. |- |Usage |This function is called by the front-end to supply callback function pointers for the Core Comparison feature. This feature is designed to work as follows. The front-end application will set up some channel for communicating data between two separately running instances of mupen64plus. For example, the unix console front-end will use named FIFOs. The front-end will register callback functions for comparing the 2 cores' states via this DebugSetCoreCompare API call. When the dbg_core_compare callback fires, the front-end will use the DebugGetCPUDataPtr function (and DebugMemGetPointer function if desired) to transmit emulator core state data from the 'sending' instance to the 'receiving' instance. The receiving instance may then check the core state data against it's own internal state and report any discrepancies. When the dbg_core_data_sync callback fires, the front-end should transmit a block of data from the sending instance to the receiving instance. This is for the purposes of synchronizing events such as controller inputs or state loading commands, so that the 2 cores may stay synchronized. This feature does not require the M64CAPS_DEBUGGER capability to built into the core, but it does require the M64CAPS_CORE_COMPARE capability. |}
{| border="1" |Prototype |'''m64p_error DebugSetRunState(m64p_dbg_runstate runstate)''' |- |Input Parameters |'''runstate''' An m64p_dbg_runstate enumerated type specifying the debugging state of the emulator. M64P_DBG_RUNSTATE_RUNNING continues execution until a breakpoint is hit or a different state is chosen. M64P_DBG_RUNSTATE_STEPPING enters a single step running mode that sends callbacks as each step is performed. M64P_DBG_RUNSTATE_PAUSED pauses execution to allow manual stepping. |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |This function sets the run state of the R4300 CPU emulator. |}
{| border="1" |Prototype |'''int DebugGetState(m64p_dbg_state statenum)''' |- |Input Parameters |'''statenum''' An m64p_dbg_state enumerated type specifying which debugger state variable to read. |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |This function reads and returns a debugger state variable, which are enumerated in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. |}
{| border="1" |Prototype |'''m64p_error DebugStep(void)''' |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized, the emulator core must be executing a ROM, and the debugger must be active before calling this function. |- |Usage |This function signals the debugger to advance one instruction when in the stepping mode. |}
{| border="1" |Prototype |'''void DebugDecodeOp(unsigned int instruction, char *op, char *args, int pc)''' |- |Input Parameters |'''instruction''' 32-bit R4300 instruction opcode
'''op''' Pointer to character array to store decoded instruction mnemonic
'''args''' Pointer to character array to store instruction arguments
'''pc''' Program Counter address at which '''instruction''' is stored |- |Requirements |The Mupen64Plus library must be built with debugger support. |- |Usage |This is a helper function for the debugger front-end. This instruction takes a PC value and an R4300 instruction opcode and writes the disassembled instruction mnemonic and arguments into character buffers. This is intended to be used to display disassembled code. |} == Memory Functions == {| border="1" |Prototype |'''void * DebugMemGetRecompInfo(m64p_dbg_mem_info recomp_type, unsigned int address, int index)''' |- |Input Parameters |'''recomp_type''' Type of information to retrieve about a recompiled machine instruction. Must be a M64P_DBG_RECOMP_* type.
'''address''' Program Counter value (in N64 memory space) of R4300 instruction about which to retrieve the recompiled x86 instructions.
'''index''' Index of recompiled instruction about which to receive information. |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. This function may not be available on all platforms. |- |Usage |This function is used by the front-end to retrieve disassembly information about recompiled code. For example, the dynamic recompiler may take a single R4300 instruction and compile it into 10 x86 instructions. This function may then be used to retrieve the disassembled code of the 10 x86 instructions. For '''recomp_type''' of M64P_DBG_RECOMP_OPCODE or M64P_DBG_RECOMP_ARGS, a character pointer will be returned which gives the disassembled instruction code. For '''recomp_type''' of M64P_DBG_RECOMP_ADDR, a pointer to the recompiled x86 instruction will be given. |}
{| border="1" |Prototype |'''int DebugMemGetMemInfo(m64p_dbg_mem_info mem_info_type, unsigned int address)''' |- |Input Parameters |'''mem_info_type''' Type of information to retrieve about an N64 memory location. Must be a M64P_DBG_MEM_* type.
'''address''' Memory location (in N64 memory space) about which to retrieve some information. |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |This function returns an integer value regarding the memory location '''address''', corresponding to the information requested by '''mem_info_type''', which is a type enumerated in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. For example, if '''address''' contains R4300 program code, the front-end may request the number of x86 instructions emitted by the dynamic recompiler by requesting M64P_DBG_MEM_NUM_RECOMPILED. |}
{| border="1" |Prototype |'''void * DebugMemGetPointer(m64p_dbg_memptr_type mem_ptr_type)''' |- |Input Parameters |'''mem_ptr_type''' Memory type to which a pointer is requested. |- |Requirements |The Mupen64Plus library must be initialized before calling this function. |- |Usage |This function returns a memory pointer (in x86 memory space) to a block of emulated N64 memory. This may be used to retrieve a pointer to a special N64 block (such as the serial, video, or audio registers) or the RDRAM. The '''m64p_dbg_memptr_type''' type is enumerated in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]] |}
{| border="1" |Prototype | {| |- |'''unsigned long long''' || '''DebugMemRead64(unsigned int address)''' |- |'''unsigned int''' || '''DebugMemRead32(unsigned int address)''' |- |'''unsigned short''' || '''DebugMemRead16(unsigned int address)''' |- |'''unsigned char''' || '''DebugMemRead8(unsigned int address)''' |} |- |Input Parameters |'''address''' Memory location (in N64 memory space) from which to retrieve a value.
|- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |These functions retrieve a value from the emulated N64 memory. The returned value will be correctly byte-swapped for the host architecture. |}
{| border="1" |Prototype |'''void DebugMemWrite64(unsigned int address, unsigned long long value)'''
'''void DebugMemWrite32(unsigned int address, unsigned int value)'''
'''void DebugMemWrite16(unsigned int address, unsigned short value)'''
'''void DebugMemWrite8(unsigned int address, unsigned char value)''' |- |Input Parameters |'''address''' Memory location (in N64 memory space) to which to write a value.
'''value''' Value to write into emulated memory. |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |These functions write a value into the emulated N64 memory. The given value will be correctly byte-swapped before storage. |} == R4300 CPU Functions == {| border="1" |Prototype |'''void *DebugGetCPUDataPtr(m64p_dbg_cpu_data cpu_data_type)''' |- |Input Parameters |'''cpu_data_type''' CPU register type to which a pointer is requested.
|- |Requirements |The Mupen64Plus library must be initialized before calling this function. |- |Usage |This function returns a memory pointer (in x86 memory space) to a specific register in the emulated R4300 CPU. The '''m64p_dbg_cpu_data''' type is enumerated in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. It is important to note that when the R4300 CPU core is in the Cached Interpreter or Dynamic Recompiler modes, the address of the PC register is not constant; it will change after each instruction is executed. The pointers to all other registers will never change, as the other registers are global variables. |} == Breakpoint Functions == {| border="1" |Prototype |'''int DebugBreakpointLookup(unsigned int address, unsigned int size, unsigned int flags)''' |- |Input Parameters |'''address''' Starting address (in R4300 memory space) to search
'''size''' Size of address space in bytes to search
'''flags''' Breakpoint flags |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |This function searches through all current breakpoints in the debugger to find one that matches the given input parameters. If a matching breakpoint is found, the index number is returned. If no breakpoints are found, -1 is returned. |}
{| border="1" |Prototype |'''int DebugBreakpointCommand(m64p_dbg_bkp_command command, unsigned int index, m64p_breakpoint *bkp)''' |- |Input Parameters |'''command''' Enumerated value specifying the breakpoint command to execute
'''index''' Purpose varies by command, see table below
'''bkp''' Pointer to breakpoint for certain commands, see table below |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized before calling this function. |- |Usage |This function is used to process common breakpoint commands, such as adding, removing, or searching the breakpoints. The meanings of the '''index''' and '''bkp''' input parameters vary by command, and are given in the table below. The '''m64p_dbg_bkp_command''' type is enumerated in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. |}
{| border="1" |Prototype |'''void DebugBreakpointTriggeredBy(uint32_t *flags, uint32_t *accessed)''' |- |Input Parameters |'''flags''' Pointer to store the breakpoint flag trigger reason for the most recent breakpoint
'''accessed''' Pointer to store the trigger address for the most recent breakpoint |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized, the emulator core must be executing a ROM, and the debugger must be active before calling this function. |- |Usage |This function is used to programmatically access the trigger reason and address for the most recently triggered breakpoint. The meaning of the '''flags''' value are the same as the '''m64p_dbg_bkp_flags''' enumerated in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. For memory read/write breakpoints, the value of '''accessed''' will be set to the ''physical'' address accessed; exec breakpoints will not populate this value as the necessary information is already encoded in the program counter. |}
{| border="1" |Prototype |'''uint32_t DebugVirtualToPhysical(uint32_t address)''' |- |Input Parameters |'''address''' A ''virtual'' address in R4300 memory |- |Requirements |The Mupen64Plus library must be built with debugger support and must be initialized, the emulator core must be executing a ROM, and the debugger must be active before calling this function. |- |Usage |This function resolves the ''physical'' address in R4300 memory corresponding to the provided ''virtual'' address. Memory read and write breakpoints only operate in terms of physical addresses, thus this function is provided to assist in the necessary virtual to physical translations. |}
{| border="1" !Command!!Return Value!!Function!!index Parameter!!ptr Parameter |- |M64P_BKP_CMD_ADD_ADDR |Index of new breakpoint |Add an execution breakpoint at a given R4300 address. |R4300 address |unused |- |M64P_BKP_CMD_ADD_STRUCT |Index of new breakpoint |Add a custom breakpoint specified in a breakpoint structure. |unused |Pointer to breakpoint struct of new breakpoint |- |M64P_BKP_CMD_REPLACE |unused |Replace an existing breakpoint with one specified by a breakpoint structure. |Index of breakpoint to replace |Pointer to breakpoint struct of new breakpoint |- |M64P_BKP_CMD_REMOVE_ADDR |unused |Remove an existing breakpoint |R4300 address of breakpoint to remove |unused |- |M64P_BKP_CMD_REMOVE_IDX |unused |Remove an existing breakpoint |Index of breakpoint to remove |unused |- |M64P_BKP_CMD_ENABLE |unused |Enable a specified breakpoint |Index of breakpoint to enable |unused |- |M64P_BKP_CMD_DISABLE |unused |Disable a specified breakpoint |Index of breakpoint to disable |unused |- |M64P_BKP_CMD_CHECK |Index of breakpoint if found, otherwise -1 |Search for an execution breakpoint at a given address |R4300 address at which to search |unused |} mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Core-Front-End.mediawiki000066400000000000000000000535611464506436200303430ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus v2.0 Core<-->Front-End API = Most libmupen64plus functions return an m64p_error return code, which is an enumerated type defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. Front-end code should check the return value of each call to a libmupen64plus function. == Startup/Shutdown Functions == {| border="1" |Prototype |'''m64p_error CoreStartup(int APIVersion, const char *ConfigPath, const char *DataPath, void *Context, void (*DebugCallback)(void *Context, int level, const char *message), void *Context2, void (*StateCallback)(void *Context2, m64p_core_param ParamChanged, int NewValue))''' |- |Input Parameters |'''APIVersion''' Integer containing the version number of the Core API used by the front-end.
'''ConfigPath''' File path to folder containing Mupen64Plus.cfg. Can be NULL.
'''DataPath''' Folder to search first when looking for shared data files. Can be NULL.
'''Context''' Pointer which will be passed back to the '''DebugCallback''' function. Can be NULL.
'''DebugCallback''' Pointer to function in front-end for receiving debug information and warnings from the core. This function must be thread-safe. Can be NULL. The value of level is 1 for an error, 2 for a warning, 3 for info, and 4 for verbose info.
'''Context2''' Pointer which will be passed back to the '''StateCallback''' function. Can be NULL.
'''StateCallback''' Pointer to function in front-end for receiving core state change notifications. This function must be thread-safe. Can be NULL. |- |Requirements |This function must be called before any other libmupen64plus functions. |- |Usage |This function initializes libmupen64plus for use by allocating memory, creating data structures, and loading the configuration file. If '''ConfigPath''' is NULL, libmupen64plus will search for the configuration file in its usual place (On Linux, in ~/.config/mupen64plus/). This function may return M64ERR_INCOMPATIBLE if older front-end is used with newer core. |}
{| border="1" |Prototype |'''m64p_error CoreShutdown(void)''' |- |Input Parameters |N/A |- |Usage |This function saves the configuration file, then destroys data structures and releases memory allocated by the core library. |}
{| border="1" |Prototype |'''m64p_error CoreAttachPlugin(m64p_plugin_type PluginType, m64p_dynlib_handle PluginLibHandle)''' |- |Input Parameters |'''PluginType''' Enumerated type specifying the plugin type to attach to the core. If this type of plugin is currently attached to the core, an error will be returned.
'''PluginLibHandle''' Dynamic library handle (defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]) corresponding with the plugin object to attach. |- |Requirements |Both the core library and the plugin library must already be initialized with the CoreStartup()/PluginStartup() functions, and a ROM must be open. This function cannot be called while the emulator is running. The plugins must be attached in the following order: Video, Audio, Input, RSP. |- |Usage |This function attaches the given plugin to the emulator core. There can only be one plugin of each type attached to the core at any given time. |}
{| border="1" |Prototype |'''m64p_error CoreDetachPlugin(m64p_plugin_type PluginType)''' |- |Input Parameters |'''PluginType''' Enumerated type specifying the plugin type to detach from the core. If no plugin of this type is currently attached to the core, this function will exit with a return value of M64ERR_SUCCESS. |- |Requirements |Both the core library and the plugin library must already be initialized with the CoreStartup()/PluginStartup() functions. This function cannot be called while the emulator is running. |- |Usage |This function detaches the given plugin from the emulator core, and re-attaches the 'dummy' plugin functions. |} == Command Functions == {| border="1" |Prototype |'''m64p_error CoreDoCommand(m64p_command Command, int ParamInt, void *ParamPtr)''' |- |Input Parameters |'''Command''' Enumerated type specifying which command should be executed.
'''ParamInt''' An integer value which may be used as an input to the command.
'''ParamPtr''' A pointer which may be used as an input to the command.
|- |Requirements |The core library must already be initialized with the CoreStartup() function. Each command may have its own requirements as well. |- |Usage |This function sends a command to the emulator core. A table of all commands is given below. |}
{| border="1" !Command!!Function!!Input Parameters!!Requirements |- |M64CMD_ROM_OPEN |This will cause the core to read in a binary ROM image provided by the front-end. |'''ParamPtr''' Pointer to the uncompressed ROM image in memory.
'''ParamInt''' The size in bytes of the ROM image. |The emulator cannot be currently running. A ROM image or disk must not be currently opened. |- |M64CMD_ROM_CLOSE |This will close any currently open ROM. The current cheat code list will also be deleted. |N/A |The emulator cannot be currently running. A ROM image must have been previously opened. There should be no plugins currently attached. |- |M64CMD_DISK_OPEN |This will cause the core to read in a disk using the medialoader API provided by the front-end. |N/A |The emulator cannot be currently running. A disk or ROM image must not be currently opened. |- |M64CMD_DISK_CLOSE |This will close any currently open disk. The current cheat code list will also be deleted. |N/A |The emulator cannot be currently running. A disk must have been previously opened. There should be no plugins currently attached. |- |M64CMD_ROM_GET_HEADER |This will retrieve the header data of the currently open ROM. |'''ParamPtr''' Pointer to a rom_header struct to receive the data.
'''ParamInt''' The size in bytes of the rom_header struct. |A ROM image must be open. |- |M64CMD_ROM_GET_SETTINGS |This will retrieve the settings data of the currently open ROM. |'''ParamPtr''' Pointer to a rom_settings struct to receive the data.
'''ParamInt''' The size in bytes of the rom_settings struct. |A ROM image must be open. |- |M64CMD_ROM_SET_SETTINGS |This will apply the settings data to the currently open ROM until the ROM is closed. |'''ParamPtr''' Pointer to a rom_settings struct to receive the data.
'''ParamInt''' The size in bytes of the rom_settings struct. |A ROM image must be open and emulation must not be running. |- |M64CMD_EXECUTE |This command will start the emulator and begin executing the ROM image. This function call will not return until the game has been stopped. |N/A |The emulator cannot be currently running. A ROM image must have been previously opened. |- |M64CMD_STOP |This will stop the emulator, if it is currently running. |N/A |This command will execute asynchronously. |- |M64CMD_PAUSE |This command will pause the emulator if it is running. |N/A |This function will return a non-successful error code if the emulator is in the stopped state. This command may execute asynchronously. |- |M64CMD_RESUME |This command will resume execution of the emulator if it is paused. |N/A |This function will return a non-successful error code if the emulator is in the stopped state. This command may execute asynchronously. |- |M64CMD_CORE_STATE_QUERY |This command will query the emulator core for the value of a state parameter |'''ParamInt''' An m64p_core_param enumerated type specifying the desired state variable'''
ParamPtr''' Pointer to an integer to receive the value of the requested state variable. |None |- |M64CMD_CORE_STATE_SET |This command will set the value of a state parameter in the emulator core |'''ParamInt''' An m64p_core_param enumerated type specifying the desired state variable'''
ParamPtr''' Pointer to an integer to containing the value of the requested state variable. |The initial requirements vary depending upon the variable being set. Setting some variables requires the emulator to be running. |- |M64CMD_STATE_LOAD |This command will attempt to load a saved state file. If '''ParamPtr''' is not NULL, this function will load a state file from a full pathname specified by this pointer. Otherwise ('''ParamPtr''' is NULL), it will load from the current slot. |'''ParamInt''' Ignored'''
ParamPtr''' Pointer to string containing state file path and name, or NULL |The emulator must be currently running or paused. This command will execute asynchronously. |- |M64CMD_STATE_SAVE |This command will save a state file. If '''ParamPtr''' is not NULL, this function will save a state file to a full pathname specified by this pointer. Otherwise ('''ParamPtr''' is NULL), it will save to the current slot. |'''ParamInt''' This parameter will only be used if '''ParamPtr''' is not NULL. If 1, a Mupen64Plus state file will be saved. If 2, a Project64 compressed state file will be saved. If 3, a Project64 uncompressed state file will be saved. '''
ParamPtr''' Pointer to string containing state file path and name, or NULL
|The emulator must be currently running or paused. This command will execute asynchronously. |- |M64CMD_STATE_SET_SLOT |This command will set the currently selected save slot index |'''ParamInt''' Value to set for the current slot index. Must be between 0 and 9'''
ParamPtr''' Ignored
|None |- |M64CMD_SEND_SDL_KEYDOWN |This command will inject an SDL_KEYDOWN event into the emulator's core event loop. Keys not handled by the core will be passed to the input plugin. |'''ParamInt''' Key value of the keypress event to inject, with SDLMod in the upper 16 bits and SDLKey in the lower 16 bits. |The emulator must be currently running or paused. |- |M64CMD_SEND_SDL_KEYUP |This command will inject an SDL_KEYUP event into the emulator's core event loop. |'''ParamInt''' Key value of the keypress event to inject, with SDLMod in the upper 16 bits and SDLKey in the lower 16 bits. |The emulator must be currently running or paused. |- |M64CMD_SET_FRAME_CALLBACK |This command either registers or removes (if '''ParamPtr''' is NULL) a frame callback function. This function will be called after each video frame is rendered. The front-end callback function may call the video plugin's ReadScreen2() function to retrieve the frame if desired. |'''ParamPtr''' Can be either NULL or a m64p_frame_callback object. |None |- |M64CMD_TAKE_NEXT_SCREENSHOT |This will cause the core to save a screenshot at the next possible opportunity. |N/A |The emulator must be currently running or paused. This command will execute asynchronously. |- |M64CMD_READ_SCREEN |This command will copy the current contents of the video display to the buffer pointer by '''ParamPtr'''. |'''ParamInt''' 1 to copy the buffer that is currently displayed (front buffer), 0 to copy the buffer that is being drawn (back buffer).'''
ParamPtr'''A pointer to a buffer of at least width*height*3 bytes. The buffer will be filled with the current display. The format is RGB888 with the origin in the lower left corner. |The emulator must be currently running or paused. |- |M64CMD_RESET |Reset the emulated machine. |'''ParamInt''' 0 to do a soft reset, 1 to do a hard reset.'''
ParamPtr''' Ignored |The emulator must be currently running or paused. |- |M64CMD_ADVANCE_FRAME |Advance one frame (the emulator will run until the next frame, then pause). |'''ParamInt''' Ignored'''
ParamPtr''' Ignored |The emulator must be currently running or paused. |- |M64CMD_SET_MEDIA_LOADER |This command allow frontends to register their media (such as GameBoy cartridge or 64DD disk) loading functions. These functions will be called appropriately by the core at startup and when a new media is inserted. |'''ParamInt''' must be sizeof(m64p_media_loader).'''
ParamPtr''' A pointer to the m64p_media_loader to register, cannot be NULL. |None |- |M64CMD_NETPLAY_INIT |This command will initialize the netplay subsystem. It will also attempt to make an initial connection to the netplay server. Returns M64ERR_SYSTEM_FAIL on failure, M64ERR_SUCCESS on success. |'''ParamInt''' This is the port number the netplay server is listening on.'''
ParamPtr''' This is a string containing the IP or hostname of the netplay server. |Emulator should be stopped. |- |M64CMD_NETPLAY_CONTROL_PLAYER |This function is used for the client to request control of certain players. This function can be called more than once if a client would like to control multiple players. Local controllers are assigned in order. Returns M64ERR_INPUT_ASSERT if the server rejects the request. If this function is never called, the client is assumed to be a spectator. |'''ParamInt''' This is the player number (from 1-4) the client would like to control.'''
ParamPtr''' This is a pointer to a uint32_t that contains a unique registration ID (for instance a random number) for the client. This number should be the same each time if this function is called multiple times. The registration ID cannot be 0. |Emulator should be stopped. The input plugin should be started. |- |M64CMD_NETPLAY_GET_VERSION |This function is used to check API and core versions, the server can use this information to make sure everyone is using the same version of the software. The function returns M64ERR_INCOMPATIBLE if the API versions don't match, and M64ERR_SUCCESS if they do. |'''ParamInt''' This is the Netplay API version that the frontend supports.'''
ParamPtr''' This is a pointer to a uint32_t, the core fills this pointer with a core netplay version. This version number is incremented when changes are made to the core that would affect netplay sync. |None |- |M64CMD_NETPLAY_CLOSE |Closes the netplay subsystem, as well as any connections to the netplay server. |N/A |None |- |M64CMD_PIF_OPEN |This will cause the core to read in a binary PIF image provided by the front-end. |'''ParamInt''' must be 2048.'''
ParamPtr''' Pointer to the uncompressed PIF image in memory. |The emulator cannot be currently running. |}
== Core State Parameters == These core parameters may be read and/or written using the M64CMD_CORE_STATE_QUERY and M64CMD_CORE_STATE_SET commands. The front-end application will receive a callback (via the StateCallback function pointer given to the '''CoreStartup''' function) when these parameters change value. This callback will be sent even if the function which caused the state change was called by the front-end application itself. Not all of these parameters are readable or writable. Each parameter's value is held in a single 32-bit integer. The meaning of this integer is given in the Parameter Encoding column. See the table below for details on these core parameters.
{| border="1" !Name!!Readable!!Writable!!int Parameter Encoding!!Notes |- |M64CORE_EMU_STATE |Yes |Yes |enum m64p_emu_state |1=Stopped, 2=Running, 3=Paused |- |M64CORE_VIDEO_MODE |Yes |Yes |enum m64p_video_mode |1=None (video not running), 2=Windowed, 3=Fullscreen |- |M64CORE_SAVESTATE_SLOT |Yes |Yes | |Valid values are 0 through 9. |- |M64CORE_SPEED_FACTOR |Yes |Yes |Emulator playback speed in percent |Valid values are 1 to 1000. |- |M64CORE_SPEED_LIMITER |Yes |Yes |1 to enable speed limiter, or 0 to disable speed limiter. |When speed limiter is disabled, emulator will run as fast as possible (useful for benchmarking). |- |M64CORE_VIDEO_SIZE |Yes |Yes |(ScreenWidth << 16) + ScreenHeight |This parameter can only be read or written when the emulator is running or paused. This parameter may be written by the front-end application in response to a window resizing event. Upon receiving this command, the core will pass the new width and height to the ResizeVideoOutput function in the video plugin (video API v2.2.0). If the video plugin supports resizing, it will update its viewport and then call the video extension function VidExt_ResizeWindow to update the window manager. |- |M64CORE_AUDIO_VOLUME |Yes |Yes |Volume level in percent, 0 - 100 | |- |M64CORE_AUDIO_MUTE |Yes |Yes |1 if muted, otherwise 0 | |- |M64CORE_INPUT_GAMESHARK |Yes |Yes |1 when Gameshark button pressed, 0 when button released. |Callback function will be invoked on both button press and release. |- |M64CORE_STATE_LOADCOMPLETE |No |No |1 if state loading was successful, 0 if state loading failed. |This parameter cannot be read or written. It is only used for callbacks, because the state load/save operations are asynchronous. |- |M64CORE_STATE_SAVECOMPLETE |No |No |1 if state saving was successful, 0 if state saving failed. |This parameter cannot be read or written. It is only used for callbacks, because the state load/save operations are asynchronous. |} |M64CORE_SCREENSHOT_CAPTURED |No |No |1 if capturing screenshot was successful, 0 if capturing screenshot failed. |This parameter cannot be read or written. It is only used for callbacks. |}
== ROM Handling Functions == {| border="1" |Prototype |'''m64p_error CoreGetRomSettings(m64p_rom_settings *RomSettings, int RomSettingsLength, int Crc1, int Crc2)''' |- |Input Parameters |'''RomSettings''' Pointer to m64p_rom_settings object to be filled in with data.
'''RomSettingsLength''' Size of the object pointed to by '''RomSettings''' in bytes.
'''Crc1''' A 32-bit integer value containing the first CRC (taken from the ROM header) to identify the ROM.
'''Crc2''' A 32-bit integer value containing the second CRC (taken from the ROM header) to identify the ROM. |- |Requirements |The core library must already be initialized with the CoreStartup() function. The '''RomSettings''' pointer must not be NULL. The '''RomSettingsLength''' value must be greater than or equal to the size of the m64p_rom_settings structure. This function does not require any ROM image to be currently open. |- |Usage |This function searches through the data in the Mupen64Plus.ini file to find an entry which matches the given '''Crc1''' and '''Crc2''' hashes, and if found, fills in the '''RomSettings''' structure with the data from the Mupen64Plus.ini file. |}
== Video Extension Functions == {| border="1" |Prototype |'''m64p_error CoreOverrideVidExt(m64p_video_extension_functions *VideoFunctionStruct);''' |- |Input Parameters |'''VideoFunctionStruct''' Pointer to a structure (defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]) containing pointers to the Front-end's custom Video Extension functions to override the default SDL functions |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. This function cannot be called while the emulator is running. |- |Usage |This function overrides the core's internal SDL-based OpenGL functions which are called from the video plugin to perform various basic tasks like opening the video window, toggling between windowed and fullscreen modes, and swapping frame buffers after a frame has been rendered. This override functionality allows a front-end to define its own video extension functions to be used instead of the SDL functions, such as for the purpose of embedding the emulator display window inside of a Qt GUI window. If any of the function pointers in the structure are NULL, the override function will be disabled and the core's internal SDL functions will be used. The core library with a Video Extension API v3.0 expects the Functions struct member to be equal to 11 or more. |}
== Cheat Functions == {| border="1" |Prototype |'''m64p_error CoreAddCheat(const char *CheatName, m64p_cheat_code *CodeList, int NumCodes)''' |- |Input Parameters |'''CheatName''' Pointer to NULL-terminated string containing a unique name for this Cheat Function.
'''CodeList''' Pointer to an array of m64p_cheat_code objects.
'''NumCodes''' Number of m64p_cheat_code elements in the cheat code array. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. A ROM image must be currently opened. |- |Usage |This function will add a Cheat Function to a list of currently active cheats which are applied to the open ROM, and set its state to Enabled. This function may be called before a ROM begins execution or while a ROM is currently running. Some cheat codes must be applied before the ROM begins executing, and may not work correctly if added after the ROM begins execution. A Cheat Function consists of a list of one or more m64p_cheat_code elements. If a Cheat Function with the given '''CheatName''' already exists, it will be removed and the new Cheat Function will be added in its place. |}
{| border="1" |Prototype |'''m64p_error CoreCheatEnabled(const char *CheatName, int Enabled)''' |- |Input Parameters |'''CheatName''' Pointer to NULL-terminated string containing the name of an existing Cheat Function.
'''Enabled''' Boolean value to which to set the enabled state of the specified Cheat Function. |- |Requirements |The Mupen64Plus library must already be initialized before calling this function. A ROM image must be currently opened. |- |Usage |This function enables or disables a specified Cheat Function. |} mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Core-Video-Extension.mediawiki000066400000000000000000000312631464506436200315620ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus v2.0 Video Extension API = Most libmupen64plus functions return an m64p_error return code, which is an enumerated type defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]. Plugin code should check the return value of each call to a libmupen64plus function. All of these functions should only be called from within the video plugin; they should not be called from the front-end. == Startup/Shutdown Functions == {| border="1" |Prototype |'''m64p_error VidExt_Init(void)''' |- |Input Parameters |N/A |- |Requirements |This function should be called before any other Video Extension functions. |- |Usage |This function should be called from within the RomOpen() video plugin function call. The default SDL implementation of this function simply calls SDL_InitSubSystem(SDL_INIT_VIDEO). It does not open a rendering window or switch video modes. |}
{| border="1" |Prototype |'''m64p_error VidExt_InitWithRenderMode(m64p_render_mode RenderMode)''' |- |Input Parameters |'''RenderMode''' Render mode, either M64P_RENDER_OPENGL or M64P_RENDER_VULKAN, defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]
|- |Requirements |This function should be called before any other Video Extension functions. |- |Usage |This function should be called from within the RomOpen() video plugin function call. The default SDL implementation of this function simply calls SDL_InitSubSystem(SDL_INIT_VIDEO). It does not open a rendering window or switch video modes. |}
{| border="1" |Prototype |'''m64p_error VidExt_Quit(void)''' |- |Input Parameters |N/A |- |Usage |This function closes any open rendering window and shuts down the video system. The default SDL implementation of this function calls SDL_QuitSubSystem(SDL_INIT_VIDEO). This function should be called from within the RomClosed() video plugin function. |}
== Screen Handling Functions == {| border="1" |Prototype |'''m64p_error VidExt_ListFullscreenModes(m64p_2d_size *SizeArray, int *NumSizes)''' |- |Input Parameters |'''SizeArray''' Pointer to an array of m64p_2d_size objects, defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]
'''NumSizes''' Pointer to an integer which contains the size of '''SizeArray''' for input, and the number of size objects stored for output. |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function is used to enumerate the available resolutions for fullscreen video modes. An array '''SizeArray''' is passed into the function, which is then filled (up to *'''NumSizes''' objects) with resolution sizes. The number of sizes actually written is stored in the integer which is pointed to by '''NumSizes'''. |}
{| border="1" |Prototype |'''m64p_error VidExt_ListFullscreenRates(m64p_2d_size Size, int *NumRates, int *Rates)''' |- |Input Parameters |'''Size''' m64p_2d_size object, defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]] of the resolution you want to retrieve the fullscreen refresh rates from.
'''NumRates''' Pointer to an integer which contains the size of '''Rates''' for input, and the number of size objects stored for output.
'''Rates''' Pointer to an array of integers which will contain the refresh rates. |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function is used to enumerate the available refresh rates for a given resolution. An '''m64p_2d_size''' object is passed into the function, which will contain the resolution of the refresh rates you want to retrieve, an array '''Rates''' is passed into the function, which is then filled (up to *'''NumRates''' objects) with resolution sizes. The number of sizes actually written is stored in the integer which is pointed to by '''NumSizes'''. |}
{| border="1" |Prototype |'''m64p_error VidExt_SetVideoMode(int Width, int Height, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)''' |- |Input Parameters |'''Width''' Horizontal resolution in pixels of desired video window
'''Height''' Vertical resolution in pixels of desired video window
'''BitsPerPixel''' Pixel color resolution of desired video window. This value must be 16, 24, or 32
'''ScreenMode''' Either M64VIDEO_WINDOWED or M64VIDEO_FULLSCREEN
'''Flags''' Logical-OR combination of flags which describes the video plugin's capabilities. |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function creates a rendering window or switches into a fullscreen video mode. Any desired OpenGL attributes should be set before calling this function. |}
{| border="1" |Prototype |'''m64p_error VidExt_SetVideoModeWithRate(int Width, int Height, int RefreshRate, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags)''' |- |Input Parameters |'''Width''' Horizontal resolution in pixels of desired video window
'''Height''' Vertical resolution in pixels of desired video window
'''RefreshRate''' Fullscreen refresh rate
'''BitsPerPixel''' Pixel color resolution of desired video window. This value must be 16, 24, or 32
'''ScreenMode''' Either M64VIDEO_WINDOWED or M64VIDEO_FULLSCREEN
'''Flags''' Logical-OR combination of flags which describes the video plugin's capabilities. |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function creates a rendering window or switches into a fullscreen video mode. Any desired OpenGL attributes should be set before calling this function. |}
{| border="1" |Prototype |'''m64p_error VidExt_SetCaption(const char *Title)''' |- |Input Parameters |'''Title''' Pointer to a NULL-terminated string containing the desired title text of the emulator rendering window |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function sets the caption text of the emulator rendering window. |}
{| border="1" |Prototype |'''m64p_error VidExt_ToggleFullScreen(void)''' |- |Input Parameters |N/A |- |Requirements |The video extension must be initialized before calling this function. The rendering window should already be created. |- |Usage |This function toggles between fullscreen and windowed rendering modes. |}
{| border="1" |Prototype |'''m64p_error VidExt_ResizeWindow(int Width, int Height)''' |- |Input Parameters |'''Width''' Horizontal resolution of resized window in pixels
'''Height''' Vertical resolution of resized window in pixels |- |Requirements |The video extension must be initialized before calling this function. The rendering window should already be created. |- |Usage |This function is called when the video plugin has resized its OpenGL output viewport in response to a ResizeVideoOutput() call, and requests that the window manager update the OpenGL rendering window size to match. If a front-end application does not support resizable windows and never sets the M64CORE_VIDEO_SIZE core variable with the M64CMD_CORE_STATE_SET command, then this function should not be called. |}
===Window Resizing=== The window resizing functionality is particularly complicated, so here is a high-level description of the events which make it happen: ====Without video extension:==== # In VidExt_SetVideoMode(), check if M64VIDEOFLAG_SUPPORT_RESIZING is set #* if True, create SDL window with RESIZABLE attribute # Core receives SDL_RESIZE messages in SDL event loop # If present, Core calls ResizeVideoOutput function in video plugin # Video Plugin calls ResizeWindow function in Video Extension #* Core calls SDL_SetVideoMode() # Core emits M64CORE_VIDEO_SIZE state changed callback ====With video extension:==== # in Front-end SetVideoMode() callback #* if M64VIDEOFLAG_SUPPORT_RESIZING is set, create resizable window frame # Front-end GUI gets window resize notification # Front-end calls CoreDoCommand w/ M64CMD_CORE_STATE_SET, w/ M64CORE_VIDEO_SIZE # If present, Core calls ResizeVideoOutput function in video plugin # Video Plugin calls ResizeWindow function in Video Extension # Core emits M64CORE_VIDEO_SIZE state changed callback In the Core Video Extension function ResizeWindow, the SDL function SetVideoMode() is called. This function will destroy the current OpenGL context and create a new one. For this reason, any video plugin which supports resizable windows must completely reset its OpenGL state including uploading any textures, FBOs, programs, etc after calling the VidExt_ResizeWindow function. == OpenGL Functions == {| border="1" |Prototype |'''void * VidExt_GL_GetProcAddress(const char* Proc)''' |- |Input Parameters |'''Proc''' Pointer to a NULL-terminated string containing the name of the desired OpenGL extension function. |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function is used to get a pointer to an OpenGL extension function. This is only necessary on the Windows platform, because the OpenGL implementation shipped with Windows only supports OpenGL version 1.1. |}
{| border="1" |Prototype |'''m64p_error VidExt_GL_SetAttribute(m64p_GLattr Attr, int Value)''' |- |Input Parameters |'''Attr''' Enumerated type (defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]) specifying which OpenGL attribute to set
'''Value''' Value to set for the attribute |- |Requirements |The video extension must be initialized before calling this function. The desired attributes should be set before calling '''VidExt_SetVideoMode''' |- |Usage |This function is used to set certain OpenGL attributes which must be specified before creating the rendering window with '''VidExt_SetVideoMode'''. |}
{| border="1" |Prototype |'''m64p_error VidExt_GL_GetAttribute(m64p_GLattr Attr, int *pValue)''' |- |Input Parameters |'''Attr''' Enumerated type (defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]) specifying OpenGL attribute of which to get value
'''pValue''' Pointer to integer Value which will be set to attribute's value |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function may be used to check that OpenGL attributes where successfully set to the rendering window after the '''VidExt_SetVideoMode''' function call. |}
{| border="1" |Prototype |'''m64p_error VidExt_GL_SwapBuffers(void)''' |- |Input Parameters |N/A |- |Requirements |The video extension must be initialized before calling this function. The rendering window should already be created. |- |Usage |This function is used to swap the front/back buffers after rendering an output video frame. |}
{| border="1" |Prototype |'''uint32_t VidExt_GL_GetDefaultFramebuffer(void)''' |- |Input Parameters |N/A |- |Requirements |The video extension must be initialized before calling this function. The rendering window should already be created. |- |Usage |On some platforms (for instance, iOS) the default framebuffer object depends on the surface being rendered to, and might be different from 0. This function should be called to retrieve the name of the default FBO. Calling this function may have performance implications and it should not be called every time the default FBO is bound. |}
== Vulkan Functions == {| border="1" |Prototype |'''m64p_error VidExt_VK_GetSurface(void** Surface, void* Instance)''' |- |Input Parameters |'''Surface''' Pointer to a VkSurfaceKHR which will be returned when function succeeds
'''Instance''' VkInstance which can be used as the front-end's Vulkan instance |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function is used to retrieve the Vulkan surface |}
{| border="1" |Prototype |'''m64p_error VidExt_VK_GetInstanceExtensions(const char** Extensions[], uint32_t* NumExtensions)''' |- |Input Parameters |'''Extensions''' Pointer to an array of strings
'''NumExtensions''' Pointer to an integer which contains the size of the number of objects stored for output. |- |Requirements |The video extension must be initialized before calling this function. |- |Usage |This function is used to retrieve the supported Vulkan extensions. |}
mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Design-Proposal-3.mediawiki000066400000000000000000000116371464506436200310250ustar00rootroot00000000000000== Primary Goal == The primary goal of this re-architecture is to split this large project into smaller projects which may proceed to be developed independently of each other. The advantages of the new architecture are: * The build system can be greatly simplified * Each module can use its own build system. For example, the Qt GUI might switch to cmake for better Qt integration. * Porting the emulator core to other platforms (namely Win32) will be greatly simplified by removing the most platform-specific pieces. * Making releases for each package will be simpler and faster * Mupen64Plus may be included into the Debian/Ubuntu repositories since glN64 (with its 'unknown' license) will be a separate project == Topography == This re-architecture will force us to lay boundaries with well-defined APIs between different parts of the emulator. Here are some initial suggestions for the new layout of the modules: # Mupen64plus-core #* To simplify porting to other platforms, the core needs to be as lean as possible #* For this reason, the GUI interfaces, the ROM cache, and the zip/lzma/7zip decompressors will be removed #* The core will contain the code for: #** Emulating the R4300 main CPU and memory systems #** Loading and configuring plugins #** Reading, parsing, and writing all configuration files for the core + plugins #** Parsing and returning information about ROM images #** Core user interface for keyboard and LIRC input #** Savestates and screenshots #** An on-screen display #** Cheat and debugger core functions #** 'Dummy' plugins # Mupen64plus-console, Mupen64plus-gtk, Mupen64plus-qt #* Command-line only, GTK, and Qt front-end interfaces #* Each front-end for the core library will be a separate project #* The ROM cache code will be forked and included into both GUIs #* The front-ends will be responsible for finding and loading the core library and the plugins #* The dynamic library handle of the core will be passed to all the plugins, and the dynamic library handle of the plugins will be passed to the core #* The front-ends will be responsible for loading and decompressing the ROM image, and passing a pointer to the core # Plugins (RiceVideo, glN64, glide64, Blight Input, JTTL Audio) #* The plugins will be spun off into separate projects #* The plugin API will change, and will be incompatible with the old Zilmar spec == Project Owners == Richard42 will retain ownership of the Mupen64plus-core and Mupen64plus-console modules. I will recommend that Slougi take ownership of the Qt GUI. The plugins and GTK GUI are up for grabs. == Work To Do == Tasks which have been completed will be marked with the strikethrough format. === Prior to starting on the code === # Write design document for Core API #* Front-end + debugger + cheat #* Configuration interface #* Video plugin #* Audio plugin #* Input plugin #* RSP plugin # Set up new Mercurial repository for project === Coding tasks === # First steps #* Split & fork the source files into new structure # Core #* Refactor/simplify makefiles #* Remove #include statements from header files #* Write new configuration load/parse/save functionality #* Separate event loop out of main.c into new source file #* Fix broken WM_KeyDown/WM_KeyUp commands sent to input plugin #* Remove main() function #* Remove main/winlnxdefs.h #* Add new shared library interface (Must be thread-safe and re-entrant where necessary) #** api/callbacks.c #** api/common.c #** api/config.c #** api/debugger.c #** api/frontend.c #** api/vidext.c #* Refactor core code for new debug info interface (instead of printf(), send back to front-end) #* Modify plugin-handling code to use new plugin API #* Fix 64-bit dynamic recompiler for dynamic lib #* Update translate.c file handling and translations #* Update cheat.c cheat code handling #* Remove compare_core.c, add core comparison feature to console-ui #* Generate versioned core library #* Simplify makefile / pre.mk #* Refactor install.sh #* Go through google code issue list, apply patches and close issue reports # Front-ends #* Refactor/simplify makefiles ## CLI ##* Write from scratch, based on main.c ##* Update man page ## GUI-Qt ##* Adapt from previous mupen64puls Qt GUI code, pulling code from CLI front-end (Slougi) ## GUI-GTK ##* Adapt from previous mupen64puls GTK GUI code, pulling code from CLI front-end (TBD) # Plug-ins #* For each plug-in: #** m64p-rsp-hle #** m64p-audio-sdl #** m64p-video-rice #** m64p-input-sdl #* Remove existing configuration read/write code #* Add Deadzone and Scaling parameters to Blight Input plugin #* Refactor to use new configuration interface through core library #* Refactor for changes in core plugin API #* Refactor for new debug info interface (instead of printf(), send back to front-end) mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Netplay-API.mediawiki000066400000000000000000000100501464506436200276660ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus Netplay Protocol = The Mupen64Plus netplay protocol is based on a client/server architecture. It supports syncing core settings and save files. It also supports raw input (tested with Raphnet input plugin). TCP is used to deal with player registration, and syncing settings and saves. UDP is used to transfer key input data. Data is sent in Network Byte Order (Big Endian). The server is responsible for maintaining healthy buffers and also for detecting desyncs. The server is the source of truth for input data (for instance, when player 1 pushes "A", it sends that information to the server via UDP. That "A" is not registered as input for player 1 until the client receives a packet from the server indicating what input frame to register that "A" in) == UDP Packet formats == * Request input for a player (sent by client): ** 12 bytes ** byte[0] = 2 ** byte[1] = player number (this is the player we need key inputs for) ** byte[2-5] = client registration ID ** byte[6-9] = current event count ** byte[10] = whether client is a spectator ** byte[11] = local buffer size of the client * Key input data (sent by server): ** Variable length, payload cannot be larger than 512 bytes ** byte[0] = 1 ** byte[1] = player number the key inputs pertain to ** byte[2] = current status. Bit 0 indicates whether the game has desynced (1 means desync). Bits 1-4 indicate whether a player has disconnected (for instance, if bit 2 is set, that means player 2 has disconnected). Bits 5-7 are currently unused. ** byte[3] = how far we lag behind the lead player ** byte[4] = number of events in this packet ** The following items will repeat/loop for the number of events in the packet *** byte[5-8] = event count *** byte[9-12] = key input data *** byte[13] = current plugin * Key input data (sent by client): ** 11 bytes ** byte[0] = 0 ** byte[1] = player number ** byte[2-5] = current event count ** byte[6-9] = key input data ** byte[10] = current plugin * Client sync data (sent by client): ** 133 bytes ** byte[0] = 4 ** byte[1-4] = current VI count ** byte[5-132] = CP0 registers == TCP Packet formats == * Player disconnection notice (sent by client): ** 5 bytes ** byte[0] = 7 ** byte[1-4] = client registration ID * Player registration request (sent by client): ** 8 bytes ** byte[0] = 5 ** byte[1] = player the client is trying to register ** byte[2] = plugin for this player ** byte[3] = whether to use a raw input plugin ** byte[4-7] = client registration ID * Player registration response (sent by server): ** 2 bytes ** byte[0] = response (1 if registration was successful, 0 otherwise) ** byte[1] = local buffer target for the client * Send save file data (sent by client): ** Variable length ** byte[0] = 1 ** byte[1 - next '\0'] = file name ** byte[4 bytes] = size of save file in bytes ** byte[size of file] = save file data * Request save file data (sent by client): ** Variable length ** byte[0] = 2 ** byte[1 - next '\0'] = file name * Receive save file data (sent by server): ** Server responds with this data right after the above request ** Variable length ** byte[file size] = save file data * Send settings (sent by client): ** 25 bytes ** byte[0] = 3 ** byte[1-4] = count_per_op ** byte[5-8] = count_per_op_denom_pot ** byte[9-12] = disable_extra_mem ** byte[13-16] = si_dma_duration ** byte[17-20] = emumode ** byte[21-24] = no_compiled_jump * Request settings (sent by client): ** 1 byte ** byte[0] = 4 * Send settings (sent by server): ** Server responds with this data right after the above request ** 24 bytes ** byte[0-3] = count_per_op ** byte[4-7] = count_per_op_denom_pot ** byte[8-11] = disable_extra_mem ** byte[12-15] = si_dma_duration ** byte[16-19] = emumode ** byte[20-23] = no_compiled_jump * Request player registration data (sent by client): ** 1 byte ** byte[0] = 6 * Send player registration data (sent by server): ** 24 bytes ** The following bytes loop 4 times (once for each player) *** byte[0-3] = player registration ID *** byte[4] = player plugin *** byte[5] = whether the player is using raw data input mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-Plugin-API.mediawiki000066400000000000000000000303721464506436200275210ustar00rootroot00000000000000[[Mupen64Plus v2.0 Core API v1.0|Mupen64Plus v2.0 API]] = Mupen64Plus v2.0 Plugin API = This section lists all of the functions which are exported by the plugins. The front-end application should only use the PluginStartup, PluginShutdown, and PluginGetVersion functions. All other functions will only be called from the core. == Common Plugin API == These functions are present in all of the plugins. {| border="1" |Prototype |'''m64p_error PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, void (*DebugCallback)(void *Context, int level, const char *Message))''' |- |Input Parameters |'''CoreLibHandle''' Dynamic library handle (defined in [[Mupen64Plus v2.0 headers#m64p_types.h|m64p_types.h]]) corresponding with the core mupen64plus library.
'''Context''' Pointer which will be passed back to the '''DebugCallback''' function. Can be NULL.
'''DebugCallback''' Pointer to function in front-end for receiving debug information and warnings from the plugin. This function must be thread-safe. Can be NULL. |- |Requirements |This function must be called before any other plugin functions. The Core library must already be started before calling this function. This function must be called before attaching the plugin to the core. |- |Usage |This function initializes plugin for use by allocating memory, creating data structures, and loading the configuration data. This function may return M64ERR_INCOMPATIBLE if an older core library is used with a newer plugin. |}
{| border="1" |Prototype |'''m64p_error PluginShutdown(void)''' |- |Requirements |This plugin should be detached from the core before calling this function. |- |Usage |This function destroys data structures and releases memory allocated by the plugin library. |}
{| border="1" |Prototype |'''m64p_error PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)''' |- |Input Parameters |'''PluginType''' Pointer to an enumerated type to store the plugin type of this plugin.
'''PluginVersion''' Pointer to an integer to store the version number of this plugin. Version number 2.1.3 would be stored as 0x00020103.
'''APIVersion''' Pointer to an integer to store the version number of the Core-Plugin API for this type of plugin used by this plugin.
'''PluginNamePtr''' Pointer to a const character pointer to receive the name of this plugin. The const char * which is returned must point to a persistent string (ie, not stored on the stack).
'''Capabilities''' Pointer to an integer to store a logically-or'd set of flags which specify the capabilities of the plugin which were built into the library during compilation. These are currently only defined for the core, so this will always return 0 for a plugin. |- |Usage |This function retrieves version information from the plugin. This function is the same for the core library and the plugins, so that a front-end may examine all shared libraries in a directory and determine their types. Any of the input parameters may be set to NULL and this function will succeed but won't return the corresponding information. |} == Video Plugin API == === Mupen64Plus v2.0 Video Plugin API === {| |void ChangeWindow(void); |Toggle Fullscreen/Windowed mode |- |BOOL InitiateGFX(GFX_INFO Gfx_Info); |Called during CoreAttachPlugin to send info about the emulator core to the graphics plugin and start up the graphics sub-system. This should create the rendering window and the OpenGL context. |- |void MoveScreen(int xpos, int ypos); |This function is called in response to the emulator receiving a WM_MOVE, passing the xpos and ypos from that message. |- |void ProcessDList(void); |Process high-level graphics D-list. (not currently used) |- |void ProcessRDPList(void); |Process low-level graphics D-list. |- |void RomClosed(void); |Called after the emulator is stopped. |- |int RomOpen(void); |Called just before the emulator begins executing a ROM. '''***changed*** - this function now returns an int (boolean)''' |- |void ShowCFB (void); |Called from the RSP plugin to signal a condition to the video plugin. |- |void UpdateScreen(void); |This function is called in response to a VSync condition if the VI bit in MI_INTR_REG is set |- |void ViStatusChanged(void); |This function is called to notify the video plugin that the ViStatus registers value has been changed. |- |void ViWidthChanged(void); |This function is called to notify the video plugin that the ViWidth registers value has been changed. |- |void ReadScreen2(void *dest, int *width, int *height, int front); |This function reads the pixels of the frame buffer that is either currently displayed (front != 0) or being drawn (front == 0) |- |void SetRenderingCallback(void (*callback)(int bScreenRedrawn)); |Allows the core to register a callback function that will be called by the graphics plugin just before the the frame buffers are swapped. '''***changed*** - as of video api v2.1.0, the callback function must take a single int (boolean) parameter, which tells the core whether or not the screen has been redrawn since the last time the callback was called. This is used to prevent screenshots from containing OSD text.''' |- |void ResizeVideoOutput(int width, int height); |'''***new*** function added in video api v2.2.0''' This function notifies the video plugin that the output video window has changed size. If resizing is supported, the video plugin should update its internal state to reflect the new window size, and then call the ResizeWindow function in the Video Extension API. |- |void FBRead(unsigned int addr) |Read data from frame buffer into emulated RAM space |- |void FBWrite(unsigned int addr, unsigned int size) |Write data from emulated RAM space into frame buffer |- |void FBGetFrameBufferInfo(void *p) |Get some information about the frame buffer |} === Remove From Older Video API === {| |- |void CaptureScreen (char * Directory); |- |void CloseDLL(void); |- |void DllAbout(HWND hParent); |- |void DllConfig(HWND hParent); |- |void DllTest(HWND hParent); |- |void DrawScreen(void); |- |void GetDllInfo(PLUGIN_INFO *PluginInfo); |- |void ReadScreen(void **dest, int *width, int *height); |- |void SetConfigDir(char *configDir); |- |
typedef struct {...} PLUGIN_INFO |} == Audio Plugin API == === Mupen64Plus v2.0 Audio Plugin API === {| |void AiDacrateChanged(int SystemType); |This function is called to notify the audio plugin that the AiDacrate register's value has been changed. |- |void AiLenChanged(void); |This function is called to notify the audio plugin that the AiLen register's value has been changed. |- |BOOL InitiateAudio(AUDIO_INFO Audio_Info); |Called during CoreAttachPlugin to send info about the emulator core to the audio plugin. |- |void ProcessAList(void); |Signal that there is an A-list to be processed. (not currently used) |- |int RomOpen(void); |Called just before the emulator begins executing a ROM. '''***changed*** - this function now returns an int (boolean)''' |- |void RomClosed(void); |Called after the emulator is stopped. |- |void SetSpeedFactor(int percent); |Called when the emulator playback speed changes. |- |void VolumeUp(void);
void VolumeDown(void); |Increase or decrease volume level |- |int VolumeGetLevel(void); |Get current volume level in percentage, between 0 and 100. '''***NEW***''' |- |void VolumeSetLevel(int level); |Set current volume level. level must be between 0 and 100. '''***NEW***''' |- |void VolumeMute(void); |Toggle between audio muted and un-muted |- |const char * VolumeGetString(void); |Return a string describing the current volume level |} === Remove From Older Audio API === {| |- |DWORD AiReadLength(void); |- |void AiUpdate(BOOL Wait); |- |void CloseDLL(void); |- |void DllAbout(HWND hParent); |- |void DllConfig(HWND hParent); |- |void DllTest(HWND hParent); |- |void GetDllInfo(PLUGIN_INFO *PluginInfo); |- |BOOL PauseAudio(BOOL Pause); |- |void SetConfigDir(char *configDir); |- |
typedef struct {...} PLUGIN_INFO |} == Input Plugin API == === Mupen64Plus v2.0 Input Plugin API === {| |void ControllerCommand(int Control, BYTE * Command); |Process the raw data that has just been sent to a specific controller. |- |void GetKeys(int Control, BUTTONS * Keys); |Get the current state of the controller's buttons |- |void InitiateControllers(CONTROL_INFO ControlInfo); |Setup controller data structures |- |void ReadController(int Control, BYTE *Command); |Process the raw data in the pif ram that is about to be read. (not currently used) |- |int RomOpen(void); |Called just before the emulator begins executing a ROM. '''***changed*** - this function now returns an int (boolean)''' |- |void RomClosed(void); |Called after the emulator is stopped. |- |void SDL_KeyDown(int keymod, int keysym); |Pass a SDL_KEYDOWN-style message to the input plugin |- |void SDL_KeyUp(int keymod, int keysym); |Pass a SDL_KEYUP-style message to the input plugin |- |void SendVRUWord(uint16_t length, uint16_t *word, uint8_t lang); |Load a word/phrase into the VRU dictionary. length specifies the length of the buffer. lang is 0 for English and 1 for Japanese. Japanese words are encoding using S-JIS. English words are encoded using a phonetic alphabet explained here: https://pastebin.com/ajLzRLze |- |void SetMicState(int state); |A state of 1 tells the input plugin to enable the microphone. A state of 0 tells the input plugin to disable the microphone |- |void ReadVRUResults(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches); |Refer to https://pastebin.com/6UiErk5h and https://ultra64.ca/files/documentation/online-manuals/man/pro-man/pro26/index26.8.html for an explanation of these variables. This function is called after the player has finished speaking. The purpose is for the VRU/input plugin to tell the core if any matches were found against the dictionary that was provided earlier |- |void ClearVRUWords(uint8_t length); |Clears and initializes the word/phrase dictionary with a max length as provided by the variable |- |void SetVRUWordMask(uint8_t length, uint8_t *mask); |Assign a mask to the words in the dictionary. A bit of 1 means to recognize the word, 0 means to ignore the word. See https://ultra64.ca/files/documentation/online-manuals/man/pro-man/pro26/index26.8.html |} === Remove From Older Input API === {| |- |void CloseDLL(void); |- |void DllAbout(HWND hParent); |- |void DllConfig(HWND hParent); |- |void DllTest(HWND hParent); |- |void GetDllInfo(PLUGIN_INFO *PluginInfo); |- |void SetConfigDir(char *configDir); |- |void WM_KeyDown(WPARAM wParam, LPARAM lParam); |- |void WM_KeyUp(WPARAM wParam, LPARAM lParam); |- |
typedef struct {...} PLUGIN_INFO |} == RSP Plugin API == === Mupen64Plus v2.0 RSP Plugin API === {| |DWORD DoRspCycles(DWORD Cycles); |Process pending RSP tasks. |- |void InitiateRSP(RSP_INFO Rsp_Info, DWORD *CycleCount); |Called during CoreAttachPlugin to send info about the emulator core to the audio plugin. |- |void RomClosed(void); |Called after the emulator is stopped. |} === Remove From Older RSP API === {| |- |void CloseDLL(void); |- |void DllAbout(HWND hParent); |- |void DllConfig(HWND hParent); |- |void DllTest(HWND hParent); |- |void GetDllInfo(PLUGIN_INFO *PluginInfo); |- |void GetRspDebugInfo(RSPDEBUG_INFO * RSPDebugInfo); |- |void InitiateRSPDebugger(DEBUG_INFO DebugInfo); |- |
typedef struct {...} PLUGIN_INFO
typedef struct {...} RSPDEBUG_INFO
typedef struct {...} DEBUG_INFO |} mupen64plus-core-src-2.6.0/doc/emuwiki-api-doc/Mupen64Plus-v2.0-headers.mediawiki000066400000000000000000000266741464506436200273010ustar00rootroot00000000000000== m64p_types.h == /* ----------------------------------------- */ /* Platform-specific stuff */ /* ----------------------------------------- */ /* necessary headers */ #if defined(WIN32) #include #endif /* DLL handles and function declaration specifiers */ #if defined(WIN32) #define IMPORT extern "C" __declspec(dllimport) #define EXPORT __declspec(dllexport) #define CALL __cdecl typedef HMODULE m64p_dynlib_handle; #else #define IMPORT extern "C" #define EXPORT __attribute__((visibility("default"))) #define CALL typedef void * m64p_dynlib_handle; #endif /* ----------------------------------------- */ /* Structures and Types for Core library API */ /* ----------------------------------------- */ typedef void * m64p_handle; typedef void (*m64p_frame_callback)(unsigned int FrameIndex); typedef void (*m64p_input_callback)(void); typedef void (*m64p_audio_callback)(void); typedef void (*m64p_vi_callback)(void); typedef enum { M64TYPE_INT = 1, M64TYPE_FLOAT, M64TYPE_BOOL, M64TYPE_STRING } m64p_type; typedef enum { M64MSG_ERROR = 1, M64MSG_WARNING, M64MSG_INFO, M64MSG_STATUS, M64MSG_VERBOSE } m64p_msg_level; typedef enum { M64ERR_SUCCESS = 0, M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */ M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */ M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */ M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */ M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */ M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */ M64ERR_NO_MEMORY, /* Memory allocation failed */ M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */ M64ERR_INTERNAL, /* Internal error (bug) */ M64ERR_INVALID_STATE, /* Current program state does not allow operation */ M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */ M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */ M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */ M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */ } m64p_error; typedef enum { M64CAPS_DYNAREC = 1, M64CAPS_DEBUGGER = 2, M64CAPS_CORE_COMPARE = 4 } m64p_core_caps; typedef enum { M64PLUGIN_NULL = 0, M64PLUGIN_RSP = 1, M64PLUGIN_GFX, M64PLUGIN_AUDIO, M64PLUGIN_INPUT, M64PLUGIN_CORE } m64p_plugin_type; typedef enum { M64EMU_STOPPED = 1, M64EMU_RUNNING, M64EMU_PAUSED } m64p_emu_state; typedef enum { M64VIDEO_NONE = 1, M64VIDEO_WINDOWED, M64VIDEO_FULLSCREEN } m64p_video_mode; typedef enum { M64VIDEOFLAG_SUPPORT_RESIZING = 1 } m64p_video_flags; typedef enum { M64CORE_EMU_STATE = 1, M64CORE_VIDEO_MODE, M64CORE_SAVESTATE_SLOT, M64CORE_SPEED_FACTOR, M64CORE_SPEED_LIMITER, M64CORE_VIDEO_SIZE, M64CORE_AUDIO_VOLUME, M64CORE_AUDIO_MUTE, M64CORE_INPUT_GAMESHARK, M64CORE_STATE_LOADCOMPLETE, M64CORE_STATE_SAVECOMPLETE } m64p_core_param; typedef enum { M64CMD_NOP = 0, M64CMD_ROM_OPEN, M64CMD_ROM_CLOSE, M64CMD_ROM_GET_HEADER, M64CMD_ROM_GET_SETTINGS, M64CMD_EXECUTE, M64CMD_STOP, M64CMD_PAUSE, M64CMD_RESUME, M64CMD_CORE_STATE_QUERY, M64CMD_STATE_LOAD, M64CMD_STATE_SAVE, M64CMD_STATE_SET_SLOT, M64CMD_SEND_SDL_KEYDOWN, M64CMD_SEND_SDL_KEYUP, M64CMD_SET_FRAME_CALLBACK, M64CMD_TAKE_NEXT_SCREENSHOT, M64CMD_CORE_STATE_SET, M64CMD_READ_SCREEN, M64CMD_RESET, M64CMD_ADVANCE_FRAME, M64CMD_SET_MEDIA_LOADER, M64CMD_PIF_OPEN } m64p_command; typedef struct { unsigned int address; int value; } m64p_cheat_code; typedef struct { /* Frontend-defined callback data. */ void* cb_data; /* Allow the frontend to specify the GB cart ROM file to load * cb_data: points to frontend-defined callback data. * controller_num: (0-3) tell the frontend which controller is about to load a GB cart * Returns a NULL-terminated string owned by the core specifying the GB cart ROM filename to load. * Empty or NULL string results in no GB cart being loaded (eg. empty transferpak). */ char* (*get_gb_cart_rom)(void* cb_data, int controller_num); /* Allow the frontend to specify the GB cart RAM file to load * cb_data: points to frontend-defined callback data. * controller_num: (0-3) tell the frontend which controller is about to load a GB cart * Returns a NULL-terminated string owned by the core specifying the GB cart RAM filename to load * Empty or NULL string results in the core generating a default save file with empty content. */ char* (*get_gb_cart_ram)(void* cb_data, int controller_num); /* Allow the frontend to know what DD IPL ROM region file to load * cb_data: points to frontend-defined callback data. * region: a region from m64p_system_type */ void (*set_dd_rom_region)(void* cb_data, uint8_t region); /* Allow the frontend to specify the DD IPL ROM file to load * cb_data: points to frontend-defined callback data. * Returns a NULL-terminated string owned by the core specifying the DD IPL ROM filename to load * Empty or NULL string results in disabled 64DD. */ char* (*get_dd_rom)(void* cb_data); /* Allow the frontend to specify the DD disk file to load * cb_data: points to frontend-defined callback data. * Returns a NULL-terminated string owned by the core specifying the DD disk filename to load * Empty or NULL string results in no DD disk being loaded (eg. empty disk drive). */ char* (*get_dd_disk)(void* cb_data); } m64p_media_loader; /* ----------------------------------------- */ /* Structures to hold ROM image information */ /* ----------------------------------------- */ typedef enum { SYSTEM_NTSC = 0, SYSTEM_PAL, SYSTEM_MPAL } m64p_system_type; typedef struct { unsigned char init_PI_BSB_DOM1_LAT_REG; /* 0x00 */ unsigned char init_PI_BSB_DOM1_PGS_REG; /* 0x01 */ unsigned char init_PI_BSB_DOM1_PWD_REG; /* 0x02 */ unsigned char init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */ unsigned int ClockRate; /* 0x04 */ unsigned int PC; /* 0x08 */ unsigned int Release; /* 0x0C */ unsigned int CRC1; /* 0x10 */ unsigned int CRC2; /* 0x14 */ unsigned int Unknown[2]; /* 0x18 */ unsigned char Name[20]; /* 0x20 */ unsigned int unknown; /* 0x34 */ unsigned int Manufacturer_ID; /* 0x38 */ unsigned short Cartridge_ID; /* 0x3C - Game serial number */ unsigned short Country_code; /* 0x3E */ } m64p_rom_header; typedef struct { char goodname[256]; char MD5[33]; unsigned char savetype; unsigned char status; /* Rom status on a scale from 0-5. */ unsigned char players; /* Local players 0-4, 2/3/4 way Netplay indicated by 5/6/7. */ unsigned char rumble; /* 0 - No, 1 - Yes boolean for rumble support. */ } m64p_rom_settings; /* ----------------------------------------- */ /* Structures and Types for the Debugger */ /* ----------------------------------------- */ typedef enum { M64P_DBG_RUN_STATE = 1, M64P_DBG_PREVIOUS_PC, M64P_DBG_NUM_BREAKPOINTS, M64P_DBG_CPU_DYNACORE, M64P_DBG_CPU_NEXT_INTERRUPT } m64p_dbg_state; typedef enum { M64P_DBG_RUNSTATE_PAUSED = 0, M64P_DBG_RUNSTATE_STEPPING, M64P_DBG_RUNSTATE_RUNNING } m64p_dbg_runstate; typedef enum { M64P_DBG_MEM_TYPE = 1, M64P_DBG_MEM_FLAGS, M64P_DBG_MEM_HAS_RECOMPILED, M64P_DBG_MEM_NUM_RECOMPILED, M64P_DBG_RECOMP_OPCODE = 16, M64P_DBG_RECOMP_ARGS, M64P_DBG_RECOMP_ADDR } m64p_dbg_mem_info; typedef enum { M64P_MEM_NOMEM = 0, M64P_MEM_NOTHING, M64P_MEM_RDRAM, M64P_MEM_RDRAMREG, M64P_MEM_RSPMEM, M64P_MEM_RSPREG, M64P_MEM_RSP, M64P_MEM_DP, M64P_MEM_DPS, M64P_MEM_VI, M64P_MEM_AI, M64P_MEM_PI, M64P_MEM_RI, M64P_MEM_SI, M64P_MEM_FLASHRAMSTAT, M64P_MEM_ROM, M64P_MEM_PIF, M64P_MEM_MI, M64P_MEM_BREAKPOINT } m64p_dbg_mem_type; typedef enum { M64P_MEM_FLAG_READABLE = 0x01, M64P_MEM_FLAG_WRITABLE = 0x02, M64P_MEM_FLAG_READABLE_EMUONLY = 0x04, // the EMUONLY flags signify that emulated code can read/write here, but debugger cannot M64P_MEM_FLAG_WRITABLE_EMUONLY = 0x08 } m64p_dbg_mem_flags; typedef enum { M64P_DBG_PTR_RDRAM = 1, M64P_DBG_PTR_PI_REG, M64P_DBG_PTR_SI_REG, M64P_DBG_PTR_VI_REG, M64P_DBG_PTR_RI_REG, M64P_DBG_PTR_AI_REG } m64p_dbg_memptr_type; typedef enum { M64P_CPU_PC = 1, M64P_CPU_REG_REG, M64P_CPU_REG_HI, M64P_CPU_REG_LO, M64P_CPU_REG_COP0, M64P_CPU_REG_COP1_DOUBLE_PTR, M64P_CPU_REG_COP1_SIMPLE_PTR, M64P_CPU_REG_COP1_FGR_64, M64P_CPU_TLB } m64p_dbg_cpu_data; typedef enum { M64P_BKP_CMD_ADD_ADDR = 1, M64P_BKP_CMD_ADD_STRUCT, M64P_BKP_CMD_REPLACE, M64P_BKP_CMD_REMOVE_ADDR, M64P_BKP_CMD_REMOVE_IDX, M64P_BKP_CMD_ENABLE, M64P_BKP_CMD_DISABLE, M64P_BKP_CMD_CHECK } m64p_dbg_bkp_command; #define M64P_MEM_INVALID 0xFFFFFFFF // invalid memory read will return this #define BREAKPOINTS_MAX_NUMBER 128 typedef enum { M64P_BKP_FLAG_ENABLED = 0x01, M64P_BKP_FLAG_READ = 0x02, M64P_BKP_FLAG_WRITE = 0x04, M64P_BKP_FLAG_EXEC = 0x08, M64P_BKP_FLAG_LOG = 0x10 /* Log to the console when this breakpoint hits. */ } m64p_dbg_bkp_flags; #define BPT_CHECK_FLAG(a, b) ((a.flags & b) == b) #define BPT_SET_FLAG(a, b) a.flags = (a.flags | b); #define BPT_CLEAR_FLAG(a, b) a.flags = (a.flags & (~b)); #define BPT_TOGGLE_FLAG(a, b) a.flags = (a.flags ^ b); typedef struct { unsigned int address; unsigned int endaddr; unsigned int flags; } m64p_breakpoint; /* ------------------------------------------------- */ /* Structures and Types for Core Video Extension API */ /* ------------------------------------------------- */ typedef struct { unsigned int uiWidth; unsigned int uiHeight; } m64p_2d_size; typedef enum { M64P_GL_DOUBLEBUFFER = 1, M64P_GL_BUFFER_SIZE, M64P_GL_DEPTH_SIZE, M64P_GL_RED_SIZE, M64P_GL_GREEN_SIZE, M64P_GL_BLUE_SIZE, M64P_GL_ALPHA_SIZE, M64P_GL_SWAP_CONTROL, M64P_GL_MULTISAMPLEBUFFERS, M64P_GL_MULTISAMPLESAMPLES, M64P_GL_CONTEXT_MAJOR_VERSION, M64P_GL_CONTEXT_MINOR_VERSION, M64P_GL_CONTEXT_PROFILE_MASK } m64p_GLattr; typedef enum { M64P_GL_CONTEXT_PROFILE_CORE, M64P_GL_CONTEXT_PROFILE_COMPATIBILITY, M64P_GL_CONTEXT_PROFILE_ES } m64p_GLContextType; typedef struct { unsigned int Functions; m64p_error (*VidExtFuncInit)(void); m64p_error (*VidExtFuncQuit)(void); m64p_error (*VidExtFuncListModes)(m64p_2d_size *, int *); m64p_error (*VidExtFuncSetMode)(int, int, int, int, int); void * (*VidExtFuncGLGetProc)(const char*); m64p_error (*VidExtFuncGLSetAttr)(m64p_GLattr, int); m64p_error (*VidExtFuncGLGetAttr)(m64p_GLattr, int *); m64p_error (*VidExtFuncGLSwapBuf)(void); m64p_error (*VidExtFuncSetCaption)(const char *); m64p_error (*VidExtFuncToggleFS)(void); m64p_error (*VidExtFuncResizeWindow)(int, int); } m64p_video_extension_functions; mupen64plus-core-src-2.6.0/doc/font-license000066400000000000000000000046271464506436200205350ustar00rootroot00000000000000Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera Sans Bitstream Vera Sans - Roman Release 1.10 Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com mupen64plus-core-src-2.6.0/doc/gpl-license000066400000000000000000000443171464506436200203510ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mupen64plus-core-src-2.6.0/doc/lgpl-license000066400000000000000000000635051464506436200205250ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! mupen64plus-core-src-2.6.0/doc/new_dynarec.mediawiki000066400000000000000000000644741464506436200224150ustar00rootroot00000000000000This page describes the dynamic recompiler in [[Mupen64Plus]], and the changes made for the ARM port. ==The original dynamic recompiler by Hacktarux== The dynamic recompiler used in Mupen64plus v1.5 is based on the original written by Hacktarux in 2002. It recompiles contiguous blocks of MIPS instructions. First, each instruction is decoded into a dynamically-allocated 132-byte data structure. typedef struct _precomp_instr { void (*ops)(); union { struct { long long int *rs; long long int *rt; short immediate; } i; struct { unsigned int inst_index; } j; struct { long long int *rs; long long int *rt; long long int *rd; unsigned char sa; unsigned char nrd; } r; struct { unsigned char base; unsigned char ft; short offset; } lf; struct { unsigned char ft; unsigned char fs; unsigned char fd; } cf; } f; unsigned int addr; /* word-aligned instruction address in r4300 address space */ unsigned int local_addr; /* byte offset to start of corresponding x86_64 instructions, from start of code block */ reg_cache_struct reg_cache_infos; } precomp_instr; The decoded instructions are then compiled, generating x86 instructions for each MIPS instruction. A 32K block is allocated with malloc() to hold the x86 code. If this size proves insufficient, it is incrementally resized with realloc(). MIPS registers are allocated to x86 registers with a least-recently-used replacement policy. All cached registers are written back prior to a branch, or a memory read or write. To facilitate invalidation and replacement of modified code blocks, each 4K page is compiled separately. If a sequence of instructions crosses a 4K page boundary, the current block is ended, and the next instructions will be compiled as a separate block. Branch instructions within a 4K page are compiled as branches directly to the target address. Branches which cross a 4K page go through an indirect address lookup. Compiled code blocks are invalidated on write. On an actual MIPS CPU, the instruction cache is invalidated using the CACHE instruction, however a few N64 games clear the cache using other methods. Trapping writes appears to be the most reliable method of ensuring cache coherency in the emulated system. The cache instruction is ignored. ==Problems with the original design== The most significant performance problem with this design is its excessive memory usage. The decoded instruction data is retained (132 bytes for each MIPS instruction) and occasionally referenced during execution. Memory accesses frequently miss the L2 cache, resulting in poor performance. Additionally, the register cache is relatively inefficient, since all registers are flushed before any read or write operation. ==A new approach== To reduce memory usage, the new design allocates a single large block of memory (generally 32 MiB, but the size is configurable) which is used for recompiled code. This memory is allocated using mmap with the PROT_EXEC bit set, to ensure operation on CPUs with no-execute (NX) page permissions. Contiguous blocks of MIPS instructions are compiled (that is, it does not attempt to follow branches or 'hot-paths'). The recompiler consists of eight stages, plus a linker, and a memory manager. Compiled blocks are invalidated on write, as before, however as the compiler will cross a 4K page, writes may invalidate adjacent pages as well. Currently the dynarec generates x86, x86-64, ARMv5, and ARMv7 (little-endian). Most of the code is shared between the architectures, but a different code generator is included at compile time, using different #include statements depending on the CPU type. ==Pass 1: Disassembly== When an instruction address is encountered which has not been compiled, the function new_recompile_block is called, with the (virtual) address of the target instruction as its sole parameter. If the address is invalid, the function returns a nonzero value and the caller is responsible for handling the pagefault. Instructions are decoded until an unconditional jump, usually a return, is encountered. Disassembly is ordinarilly continued past a JAL (subroutine call) instruction, however this strategy is abandoned if invalid instructions are encountered. Up to 4096 instructions (16K of MIPS code) may be disassembled at once. Surprisingly, some games do actually reach this limit. ==Pass 2: Liveness analysis== After disassembly, liveness analysis is performed on the registers. This determines when a particular register will no longer be used, and thus can be removed from the register cache. A separate analysis is done on the upper 32 bits of 64-bit registers. This can determine when only the lower 32 bits of a register are significant, thus allowing use of a 32-bit register. This enables more efficient code generation on 32-bit processors. ==Pass 3: Register allocation== The 31 MIPS registers must be mapped onto seven available registers on x86, or twelve available registers on ARM. Instructions with 64-bit results require two registers on 32-bit host processors. 32-bit instructions require only one. A flag is set for registers containing 32-bit values, and these registers will be sign-extended before they are written to the register file. Registers are made available using a least-soon-needed replacement policy. When the register cache is full, and no registers can be eliminated using the liveness analysis, a ten-instruction lookahead is used to determine which registers will not be needed soon and these registers are evicted from the cache. ==Pass 4: Free unused registers== After the initial register allocation, the allocations are reviewed to determine if any registers remain allocated longer than necessary. These are then removed from the register cache. This avoids having to write back a large number of registers just before a branch, and makes more registers available for the next pass. ==Pass 5: Pre-allocate registers== If a register will be used soon and needs to be loaded, try to load it early if the register is available. This improves execution on CPUs with a load-use penalty. ==Pass 6: Optimize clean/dirty state== If a cached register is 'dirty' and needs to be written out, try to do so as soon as the register will no longer be modified. This avoids having to write the same register on multiple code paths due to conditional branches. Additionally, try to avoid writing out dirty registers inside of loops. ==Pass 7: Identify where registers are assumed to be 32-bit== When a 64-bit register is mapped to a 32-bit register with the assumption that the value will be sign-extended before being used, it is necessary to ensure that no register contains a 64-bit value when branching to such a location. These instructions are flagged to identify them as requiring 32-bit inputs. This information is used by the linker, and the exception return (ERET) handler. ==Pass 8: Assembly== This generates and outputs the recompiled code. Following the main code block, handlers for certain exceptions as well as alternate entry points are added. If a recompiled instruction relies on a certain MIPS register being cached in a certain native register, then a short 'stub' of code is generated to load the necessary registers. When an instruction outside of this block needs to jump to that location, it will instead jump to the stub. The necessary registers will be loaded, and then it will jump into the main code sequence. On architectures which require literal pools (ARMv5) these are inserted as necessary. ==Linker== The linker fills in all unresolved branches. Branches within the block are linked to their target address. Branches which jump outside of the block are linked to their target if that address has been compiled already. These inter-block branches are recorded in the jump_out array. This information will be used to remove the links in the event that the target of the branch is invalidated. Unresolved branches point to a stub which loads the address of the branch instruction and the virtual address of its target into registers, and calls the dynamic linker. When this code is executed, the dynamic linker will compile the target if necessary, and then patch the branch instruction with the new address. ==Memory manager== The last step in new_recompile_block is to ensure that there will be sufficient memory available to compile the next block. If there is not, then the oldest blocks are purged. The dynarec cache can be described as a 32MB circular buffer divided into eight segments. Memory is allocated in order from beginning to end. When there are less than 2 empty segments, the next segment in sequence is cleared, wrapping around to the beginning of the buffer. This continues as memory is needed, wrapping around from end to beginning. ==Invalidation and restoration== Normally, code blocks are looked up via a hash table, using the virtual address of the target instruction. However, for purposes of invalidation, blocks are grouped by physical address. This can be described as a virtually-indexed, physically-tagged (VIPT) cache. References to compiled blocks are stored in one of 4096 linked lists in the jump_in array. Each list covers a 4K block of memory, and 2048 such lists are sufficient to cover the 8MB of RAM in the Nintendo 64. The remaining lists are for code in ROM, and the bootloader in SP memory. When a write hits a memory page marked as cached, all entries in the corresponding list are invalidated. If any code is found to cross a 4K boundary, the adjacent lists are invalidated also. Sometimes blocks may be invalidated even when none of the code is actually modified. This can happen if data is written to memory in the same 4K page, or if code is reloaded without actually modifying it. If blocks which were previously invalidated are subsequently found to be unmodified, those blocks are marked in the restore_candidate array. If the block remains unmodified, it will be restored as a valid block, to avoid recompiling blocks which do not need to be recompiled. This is performed by the clean_blocks function which is called periodically. The jump_in array, which lists unmodified blocks, is physically indexed, however the jump_dirty array, which lists potentially-modified blocks, is virtually indexed. This allows blocks which have changed physical addresses, but are still at the same virtual address, to be recognized as being the same as before, and not in need of recompilation. ==Dynamic linker== Branches with unresolved addresses jump to the dynamic linker. This will look through the jump_in list corresponding to the physical page containing the virtual target address. If found, the branch instruction will be patched with the address, and then it will jump to this address. If not found, the jump_dirty list will be searched for blocks which were previously compiled but may have been modified. If a potential match is found, the code will be compared against a cached copy to determine if any changes have been made. If not, then it will jump to the block. Because the memory could be modified again, branch instructions referencing these blocks are not altered, and continue to point to the dynamic linker. These blocks will continue to be verified each time they are called, until restored to the jump_in list by the clean_blocks function described above. If no compiled block is found, or the existing block was modified, the target is recompiled. ==Address lookup== When a JR (jump register) instruction is encountered, the address of the recompiled code must be looked up using the address of the MIPS code. The majority of such instructions jump to the link register (r31) to return to the location following a JAL (call) instruction. When a JAL or JALR is executed, the address of the following instruction is inserted into a small 32-entry hash table, which is checked when a JR r31 instruction is executed. This allows for a quick return from subroutine calls. If the JR instruction uses a register other than r31, or the small hash table lookup fails to find a match, a larger 131072-entry hash table is checked. This table contains 65536 bins with up to 2 addresses per bin. If this also fails to find a match (which occurs less than 1% of the time) an exhaustive search of all compiled addresses within that 4K memory page is performed. If no match is found by any of these methods, the target address is compiled, and the new address is inserted into the hash table. ==Cycle counting== Cycles are counted before each branch by adding the cycles from the preceding instructions to a specific register. The cycle count is in R10 on ARM and ESI on x86. The value in this register is normally a negative number. When this number exceeds zero, a conditional branch is taken which jumps to an interrupt handler. For example, the following x86 code adds eight cycles: add $8,%esi jns interrupt_handler The conditional branch jumps to a small bit of code located after the main compiled block, which saves the cached registers to the register file, sets the instruction pointer which will be used upon return from the interrupt, and then calls cc_interrupt. As in the original mupen64plus, the emulated clock runs at 37.5 MHz, and each instruction takes 2 clock cycles. ==Interrupt handler== When the cycle count register reaches its limit, cc_interrupt is called, which in turn calls gen_interrupt. If interrupts are not enabled, cc_interrupt returns. If interrupts are enabled, and an interrupt is to be taken, the pending_exception flag will be set. In this case, cc_interrupt does not return, and instead pops the stack and causes an unconditional jump to the address in pcaddr (usually 0x80000180). There is one additional case where the interrupt handler may be called. If interrupts were disabled, and are enabled by writing to coprocessor 0 register 12, any pending interrupts are handled immediately. ==Delay slots== MIPS has 'delay slots', where the instruction after the branch is executed before the branch is taken. Instructions in delay slots are issued out-of-order in the recompiled code. [[Image:Recompiler delay slot reordering.png]] When a branch jumps into the delay slot of another branch, this case must be handled slightly differently: [[Image:Recompiler delay slot reordering 2.png]] The branch test and delay slot are executed in-order if a dependency exists, or for 'likely' branches where the delay slot is nullified when the branch condition is false. These cases are infrequent (typically less than 10% of branches). ==Constant propagation== When an instruction loads a constant into a register, the register is tagged as a constant. The constant tag will be retained if subsequent instructions modify the constant using other constants. During assembly, such a sequence of instructions is combined into a single load. For example: LUI r8,12340000 --> mov $0x12345678,%eax ORI r8,r8,5678 This optimization is not performed where a branch target intervenes, eg ... LUI r8,12340000 --> mov $0x12340000,%eax L1: ORI r8,r8,5678 --> or $0x5678,%eax ... BEQ r0,r0,L1 Registers containing constants are identified by bits in the isconst and wasconst fields of the regstat structure. The wasconst bit is set for a register if the register contained a known constant before the instruction, and the isconst bit is set for a register if the register will contain a known constant after the instruction executes. ==Translation lookaside buffer emulation== Most Nintendo 64 games do not use virtual memory, but some do. At startup, main memory is directly mapped at addresses from 0x80000000 to 0x803FFFFF, or up to 0x807FFFFF if the memory expansion is used. Normally, read or write operations are checked against this range, and if outside this range, control is passed to the appropriate I/O handler. This is done as follows: MIPS instruction: LW r1,8(r2) ARM code: add r1, r2, #8 cmp r1, #8388608 bvc handler ldr r1, [r1] If there are valid entries in the TLB, this would instead be compiled as follows: add r1, r2, #8 mov r0, #264 add r0, r0, r1, lsr #12 ldr r0, [r11, r0, lsl #2] tst r0, r0 bmi handler ldr r1, [r1, r0, lsl #2] This looks up the offset in the memory_map table (which, in this example, is located at r11+264*4). The high bit is tested to determine whether a valid mapping exists for this page. ==Page fault emulation== If a memory address references an invalid page, a conditional branch is taken to a bit of code placed after the main block. This will save any modified cached registers, and call an appropriate handler function for the address. The handler will either perform I/O, or generate an exception (pagefault). ==Mapping executable pages== If the dynamic recompiler encounters code which is not in contiguous physical memory, it will end the block at the page boundary, so that the block can be removed cleanly if the mapping is changed. There is a special case of this, where a branch and delay slot span two pages. If a branch instruction is the last instruction in a virtual memory page, it is compiled in a different manner than other branches. The branch condition is evaluated, and the target address is placed in a register (%ebp on x86, and r8 on ARM). A special form of the dynamic linker (dyna_linker_ds) is used to link the branch to its corresponding delay slot in another block. If no page fault occurs, the delay slot executes and then jumps to the address in the register. For conditional branches that are not taken, the target address is the next instruction. This code is generated by the pagespan_assemble function. == Self-modifying code detection == Pages not containing code which has been compiled or where the code may have been modified since compilation are marked in the invalid_code array. Writes are checked against this array, and if a write hits a valid (compiled and unmodified) page, invalidate_block is called: MIPS instruction: SW r1,8(r2) ARM code: ldr r3, [r11, #88] // pointer to invalid_code add r4, r2, #8 cmp r4, #8388608 bvc handler str r1, [r4] ldrb r14, [r3, r4 lsr #12] cmp r14, #1 bne invstub In TLB mode, the invalid_code array is not checked directly. Instead, pages are marked non-writable in memory_map. == Long jumps == Branch instructions are limited to a +/-32MB range on ARM. In some cases, the dynamic recompiler needs to generate calls to locations beyond this range. This is accomplished via a jump table located at the end of the code generation area, and the full address is loaded via a pointer. The jump table is generated in arch_init(). As these indirect jumps cause some delay, it is best to avoid this situation if possible, by locating this area close to the other executable code. == Compile options == === ARMv5_ONLY === If this is defined, the UXTH instruction is not used, and the dynamic recompiler will generate literal pools instead of using movw/movt. This provides compatibility with older processors, but generates somewhat less efficient code. === RAM_OFFSET === When compiling for ARM, this allocates an additional register which is used to add an offset to all pointers to memory addresses between 0x80000000 and 0x807FFFFF. This allows the N64's memory to be mapped at an alternate address. This incurs a small performance penalty, but is required for certain operating systems (eg Google Android, which places shared libraries at 0x80000000). This option is not used for x86. The x86 instruction set allows for a full 32-bit offset in the instruction encoding, making it unnecessary to allocate an additional register for this purpose. === CORTEX_A8_BRANCH_PREDICTION_HACK === If this is defined, the dynamic recompiler will avoid generating consecutive branch instructions without another instruction in between. This avoids a possible branch misprediction on the Cortex-A8 due to this processor having dual instruction decoders, but only one branch-prediction unit. See [[Assembly Code Optimization]] for details. === USE_MINI_HT === If this is defined, attempt to look up return addresses in a small hash table before checking the larger hash table. Usually improves performance. === IMM_PREFETCH === If this is defined, the x86 PREFETCH instruction is used to prefetch entries from the hash table. The increase in code size often outweighs the benefit of this. === REG_PREFETCH === Similar to the above, but loads the address into a register first, then uses the ARM PLD instruction. The increase in code size almost always outweighs the benefit of this. === R29_HACK === Assume that the stack pointer (r29) is always a valid memory address and do not check it. It is similar to the optimization described [http://strmnnrmn.blogspot.com/2007/08/interesting-dynarec-hack.html here]. This can crash the emulator and is not enabled by default. == Debugging == Debugging information can be obtained by defining the assem_debug macro as printf. This will cause the dynamic recompiler to print debugging information to stdout. For each disassembled MIPS instruction, an entry similar to the following will be printed: U: r1 r8 r11 r16 r31 UU: r29 32: r0 r9 pre: eax=-1 ecx=9 edx=-1 ebx=-1 ebp=29 esi=36 edi=-1 needs: ecx ebp esi r: r9 entry: eax=-1 ecx=9 edx=-1 ebx=-1 ebp=29 esi=36 edi=-1 dirty: ecx ebp esi 800001d8: LW r16,r29+14 eax=16 ecx=9 edx=-1 ebx=-1 ebp=29 esi=36 edi=-1 dirty: eax ecx ebp esi 32: r0 r9 r16 U: A list of MIPS registers which will not be used before they are overwritten (liveness analysis) UU: A list of MIPS registers for which the upper 32 bits will not be used before they are overwritten 32: Registers that contain 32-bit sign-extended values pre: The state of the register mapping prior to execution of this instruction. (-1 = no mapping; 36 = cycle count; The complete list of values with special meanings can be found in the source code) needs: a list of register mappings that were considered necessary and which could not be eliminated to make room for other mappings r: Registers that are known to contain 32-bit values and where optimizations rely on the assumption that the register does not contain a value outside of the range -231 to 231-1 entry: The minimum set of register mappings required to jump to this point dirty: Cached registers that have been modified and will need to be written back address: instruction - The decoded opcode, followed by the register mapping in effect after this instruction executes An asterisk (*) designates locations which are the target of a branch instruction. Constant propagation will not be performed across these points. After the complete disassembly, the recompiled native code is shown. Note that the output can be quite voluminous; 20-30 MB is typical. ==Potential improvements== ===Copy propagation/offset propagation=== A common instruction sequence is of the form: LUI r9,12340000 ADD r9,r9,r8 LW r9,5678(r9) It would be helpful to recognize this as a load from r8+12345678. The current constant propagation code does not do so. ===Constant propagation and register assignment=== Constant propagation is currently done after register assignment. Registers are assigned even if the register will always contain a known value. In certain cases, such as where the constant is used only to generate a memory address, this could be avoided and no register would need to be allocated. ===Unaligned memory access=== A small improvement could be made by combining adjacent LWL/LWR instructions. The potential gain from doing so is very limited because these instructions typically represent less than 1% of all memory accesses. ===SLT/branch merging=== A frequent occurrence in MIPS code is an SLT or SLTI instruction followed by a branch. This is generated relatively inefficiently on x86 and ARM, first doing a compare and set, then testing this value and doing a conditional branch. Doing only one comparison would save at least one instruction, and could potentially save up to three instructions if the liveness analysis reveals that the result of the SLT instruction is used nowhere else. While a potentially useful optimization, there are several problems with this approach. First, there are often additional instructions between the slt and the branch. These must be checked to make sure they do not modify the registers as that would prevent reordering the instruction stream as desired. Secondly, if the result of the slt is found to be live, but unmodified, on both paths of the branch, clean_registers will normally write this value before the branch, to avoid duplicating the writeback code on both paths of the branch. This optimization would have to be removed if the slt was combined with the branch. ===x86-64=== Currently the x86-64 backend generates only 32-bit instructions. Proper 64-bit code generation would improve performance. ===PowerPC=== It would be possible to add a PowerPC code generator to the dynamic recompiler. Currently no one is working on this. (The mupen64gc project is using a different codebase.) The following is a summary of the changes which would be necessary to add a PowerPC backend. The slt* instructions use conditional moves, which are unavailable on PowerPC. A suitable alternative (such as moves from the condition register) would need to be used. The assembler can generate as much as 256K of code in a single block, however conditional branches on PowerPC are limited to +/-64K. It will be necessary to either restrict the block size, or insert jump tables in a manner similar to the literal pools on ARM. PowerPC generally relies on early branch resolution rather than statistical branch prediction. Scheduling branch condition tests earlier may be advantageous. (For example, the address bounds check could be done in address_generation, rather than just before the load or store. Similarly it may be advantageous to test the branch condition and update the cycle count before executing the delay slot.) ===MIPS=== Recompiling MIPS into MIPS would be relatively straightforward, however the current code generator has no facility for filling delay slots. This capability would be required for efficient code generation. [[Category:Emulators]] [[Category:Optimization]] [[Category:Development]] mupen64plus-core-src-2.6.0/projects/000077500000000000000000000000001464506436200172775ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/projects/msvc/000077500000000000000000000000001464506436200202475ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/projects/msvc/mupen64plus-core.vcxproj000066400000000000000000003213431464506436200250220ustar00rootroot00000000000000 ARM64_New_Dynarec_Debug x64 ARM_New_Dynarec_Debug Win32 Debug Win32 Debug x64 New_Dynarec_Debug Win32 New_Dynarec_Debug x64 New_Dynarec_Release Win32 New_Dynarec_Release x64 Release Win32 Release x64 x64_New_Dynarec_Debug x64 x86_New_Dynarec_Debug Win32 true true true true true true true true true true true true true true true true true true true true true true true true true true true false false true false false true true true true 4244 4244 4244 4244 true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true false false false false false false true true false false 4244 4244 4244 4244 4244 4244 4244 4244 4244 true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true false true true true true true true true false true true true false true true true true true true true false true true true false true true true true true true true false true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true false false false false false false true true false false true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true true false true true true true true true true false true true true false true true true true true true true false true true true false true true true true true true true false true true true false true true true true true true true false true true true true true true true false false false true true true false Document "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x64\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x64.obj" -f win64 -d WIN64 "%(FullPath)" $(IntDir)linkage_x64.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x64\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x64.obj" -f win64 -d WIN64 "%(FullPath)" $(IntDir)linkage_x64.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x64\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x64.obj" -f win64 -d WIN64 "%(FullPath)" $(IntDir)linkage_x64.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x64\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x64.obj" -f win64 -d WIN64 "%(FullPath)" $(IntDir)linkage_x64.obj true true true true true true true true true true true true true true true true true true true true true true true true true true false false false true true true true true false true Document "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x86\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x86.obj" -f win32 -d LEADING_UNDERSCORE "%(FullPath)" $(IntDir)linkage_x86.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x86\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x86.obj" -f win32 -d LEADING_UNDERSCORE "%(FullPath)" $(IntDir)linkage_x86.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x86\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x86.obj" -f win32 -d LEADING_UNDERSCORE "%(FullPath)" $(IntDir)linkage_x86.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x86\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)linkage_x86.obj" -f win32 -d LEADING_UNDERSCORE "%(FullPath)" $(IntDir)linkage_x86.obj false true true true true true false true true true true true Document "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x64\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)dyna_start.obj" -f win64 -d WIN64 "%(FullPath)" $(IntDir)dyna_start.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x64\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)dyna_start.obj" -f win64 -d WIN64 "%(FullPath)" $(IntDir)dyna_start.obj true true true true true true false true true true false true Document "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x86\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)dyna_start.obj" -f win32 -d LEADING_UNDERSCORE "%(FullPath)" $(IntDir)dyna_start.obj "..\..\..\mupen64plus-win32-deps\nasm-2.16.01\x86\nasm.exe" -i ..\..\src\ -i ..\..\src\asm_defines\ -o "$(IntDir)dyna_start.obj" -f win32 -d LEADING_UNDERSCORE "%(FullPath)" $(IntDir)dyna_start.obj {92D3FEB9-2129-41C5-8577-BCD7D961EF41} mupen64pluscore $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) $(LatestTargetPlatformVersion) $(WindowsTargetPlatformVersion) $(DefaultPlatformToolset) DynamicLibrary MultiByte true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte true $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus DynamicLibrary MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ mupen64plus Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_NETPLAY;M64P_PARALLEL;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x86\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x86\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x86\freetype.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_PARALLEL;M64P_OSD;M64P_NETPLAY;__x86_64__;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x64\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x64\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x64\freetype.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "__x86_64__" Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_NETPLAY;M64P_PARALLEL;NEW_DYNAREC=1;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x86\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x86\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x86\freetype.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "NEW_DYNAREC=1" Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;..\..\..\mupen64plus-win32-deps\capstone\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_NETPLAY;M64P_PARALLEL;NEW_DYNAREC=1;RECOMPILER_DEBUG=1;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x86\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x86\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x86\freetype.lib;..\..\..\mupen64plus-win32-deps\capstone\lib\x86\capstone_dll.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "NEW_DYNAREC=1" Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;..\..\..\mupen64plus-win32-deps\capstone\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_NETPLAY;M64P_PARALLEL;NEW_DYNAREC=1;RECOMPILER_DEBUG=3;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x86\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x86\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x86\freetype.lib;..\..\..\mupen64plus-win32-deps\capstone\lib\x86\capstone_dll.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "NEW_DYNAREC=1" Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_PARALLEL;M64P_OSD;M64P_NETPLAY;NEW_DYNAREC=2;__x86_64__;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x64\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x64\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x64\freetype.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "__x86_64__" /D "NEW_DYNAREC=2" Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;..\..\..\mupen64plus-win32-deps\capstone\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_PARALLEL;M64P_OSD;M64P_NETPLAY;NEW_DYNAREC=2;__x86_64__;RECOMPILER_DEBUG=4;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x64\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x64\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x64\freetype.lib;..\..\..\mupen64plus-win32-deps\capstone\lib\x64\capstone_dll.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "__x86_64__" /D "NEW_DYNAREC=2" Disabled ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;..\..\..\mupen64plus-win32-deps\capstone\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_PARALLEL;M64P_OSD;M64P_NETPLAY;NEW_DYNAREC=2;__x86_64__;RECOMPILER_DEBUG=2;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x64\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x64\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x64\freetype.lib;..\..\..\mupen64plus-win32-deps\capstone\lib\x64\capstone_dll.lib;%(AdditionalDependencies) true Windows ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "__x86_64__" /D "NEW_DYNAREC=2" ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_NETPLAY;M64P_PARALLEL;%(PreprocessorDefinitions) MultiThreadedDLL Level3 MaxSpeed true true shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x86\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x86\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x86\freetype.lib;%(AdditionalDependencies) true Windows true true ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_PARALLEL;M64P_OSD;M64P_NETPLAY;__x86_64__;%(PreprocessorDefinitions) MultiThreadedDLL Level3 MaxSpeed true true shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x64\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x64\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x64\freetype.lib;%(AdditionalDependencies) true Windows true true ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "__x86_64__" ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_OSD;M64P_NETPLAY;M64P_PARALLEL;NEW_DYNAREC=1;%(PreprocessorDefinitions) MultiThreadedDLL Level3 MaxSpeed true true shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x86\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x86\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x86\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x86\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x86\freetype.lib;%(AdditionalDependencies) true Windows true true ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "NEW_DYNAREC=1" ..\..\src;..\..\subprojects\md5;..\..\subprojects\minizip;..\..\subprojects\oglft;..\..\subprojects\xxhash;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\include;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\include;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\include;..\..\..\mupen64plus-win32-deps\opencv-3.0.0\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;DYNAREC;M64P_PARALLEL;M64P_OSD;M64P_NETPLAY;NEW_DYNAREC=2;__x86_64__;%(PreprocessorDefinitions) MultiThreadedDLL Level3 MaxSpeed true true shell32.lib;opengl32.lib;glu32.lib;..\..\..\mupen64plus-win32-deps\SDL2-2.26.3\lib\x64\SDL2.lib;..\..\..\mupen64plus-win32-deps\SDL2_net-2.2.0\lib\x64\SDL2_net.lib;..\..\..\mupen64plus-win32-deps\zlib-1.2.13\lib\x64\zlib.lib;..\..\..\mupen64plus-win32-deps\libpng-1.6.39\lib\x64\libpng16.lib;..\..\..\mupen64plus-win32-deps\freetype-2.13.0\lib\x64\freetype.lib;%(AdditionalDependencies) true Windows true true ..\..\tools\gen_asm_script.cmd ..\..\src\asm_defines\ $(IntDir) /D "__x86_64__" /D "NEW_DYNAREC=2" mupen64plus-core-src-2.6.0/projects/msvc/mupen64plus-core.vcxproj.filters000066400000000000000000000762361464506436200265010ustar00rootroot00000000000000 {9deae173-605c-40ef-a0cb-3e7536ca5490} {7f51f5eb-d111-4ea0-8e53-16af048aa72c} {ff56da04-0803-4045-b46c-e3dc66c192a6} {fec5e53b-4b84-4c79-af26-e473e369a269} {7dbf3f3e-a99d-49a0-8d55-b0b14ac0bde4} {f8d14190-4f81-4bfa-bb8d-5a10c2292396} {4e08d3a7-cb15-4bc5-8d8a-04fea5461fb1} {e879612e-16c4-48d4-bc9c-bbdadf92295b} {34995a42-e31b-454b-b4c8-968095acfbc1} {9529393c-1033-4db2-9847-d99d0f2a3efc} {0a3e6535-058f-4cf8-94a1-cf33e0668572} {2ce19bee-47cf-4152-bddf-d2587d4ad1c1} {873c3262-2472-407c-8451-67cbb5f78bae} {11f2d5a7-413e-462b-a57b-693174db54b3} {87776cb1-be61-4bae-b41a-b58247a4d566} {0628d2cb-f4d7-4b1e-ad47-00501bd18048} {8f670ceb-ce46-4a21-a0bf-8540bcae178c} {e421c1e2-dc2e-4360-8556-3acd87d848e5} {da1e6509-b45c-44b5-b5af-22461efed567} {c5515050-4fb5-4679-be02-0d6ca91b776f} {b5480a4a-bc62-431c-b1a4-0451c607c62a} {2e17a06a-4e59-4cc9-a3a0-486ec5caae74} {5cb4209c-8a0d-49d8-bc25-50fdd77cd530} {31367ef4-0b07-4c6a-8123-91b680aed4fa} {3b7e8091-cd59-447d-811b-50d50aa3b4b0} {69adb39a-b46f-48f1-8775-2e31e037f566} {7b07613b-6f92-426f-aa1d-a84b40c8968b} {4bfb7a7d-1089-4da4-a766-ccc14a7a6d9e} {aa30f585-b79e-4703-86bf-c1d2cff57ea2} {f1849de7-61bf-4605-b4e8-6a7f9e45ed9c} {56606d99-6307-4b2b-ae66-aa9ef43d9ac4} {ba830992-ba04-4afc-aac4-7538801f1eb5} {27554d80-a417-4e23-8beb-ee0d70bb282f} {8eff5a55-cd16-4582-97bf-7eb08afe59bc} {11be67bc-8d5a-4efd-aefb-31bbeec5aad8} {16a4986e-7be6-4bd3-8cd4-ef7370155db4} {d5c557d7-774e-48e6-b9c2-75d3ae05bfea} {ff19301d-1e15-4787-8e09-d608004dd009} {23daae91-0471-4a19-a7e8-70975acb835a} {8f211c2b-70bb-4714-bcbb-c77abd1af54d} api api api api api api main main main main main main main main main main main device\memory osal osal osal osal osd osd backends backends backends backends plugin plugin plugin plugin plugin device\pif device\pif device\pif device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300\x86 device\r4300\x86 device\r4300\x86 device\r4300\x86_64 device\r4300\x86_64 device\r4300\x86_64 device\r4300\new_dynarec device\r4300\new_dynarec\arm device\r4300\new_dynarec\arm device\r4300\new_dynarec\x86 debugger debugger debugger debugger device device\pif backends backends\plugins_compat backends\plugins_compat device\gb device\gb device\gb device\cart device\cart device\cart device\cart device\cart device\cart device\cart device\controllers\paks device\controllers\paks device\controllers\paks device\controllers\paks device\controllers device\controllers device\rdram device\rcp\ai device\rcp\mi device\rcp\pi device\rcp\ri device\rcp\si device\rcp\vi device\rcp\rdp device\rcp\rsp device\rcp\rdp device\dd device\dd subprojects\md5 subprojects\oglft subprojects\minizip subprojects\minizip subprojects\minizip device\r4300\new_dynarec device\r4300\new_dynarec\x64 device\r4300\new_dynarec\arm64 api api api api api api api api api api api api main main main main main main main main main main main main main device\memory osal osal osal osd osd backends backends plugin plugin plugin plugin plugin device\pif device\pif device\pif device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300 device\r4300\x86 device\r4300\x86 device\r4300\x86 device\r4300\x86 device\r4300\x86_64 device\r4300\x86_64 device\r4300\x86_64 device\r4300\x86_64 device\r4300\new_dynarec device\r4300\new_dynarec\arm device\r4300\new_dynarec\arm device\r4300\new_dynarec\x86 debugger debugger debugger debugger debugger device\r4300 device device\pif backends\api backends\api backends\api backends\api backends\api backends\api backends\api backends\plugins_compat device\gb device\gb device\gb device\cart device\cart device\cart device\cart device\cart device\cart device\cart device\controllers\paks device\controllers\paks device\controllers\paks device\controllers\paks device\controllers device\controllers device\rdram device\rcp\ai device\rcp\mi device\rcp\pi device\rcp\ri device\rcp\si device\rcp\vi device\rcp\rdp device\rcp\rsp device\rcp\rdp device\dd subprojects\md5 subprojects\oglft subprojects\xxhash subprojects\minizip subprojects\minizip subprojects\minizip subprojects\minizip device\r4300\new_dynarec\x64 device\r4300\new_dynarec\arm64 device\dd device\r4300 device\r4300 device\r4300\new_dynarec\arm device\r4300\new_dynarec\arm64 device\r4300\new_dynarec\x86 device\r4300\x86_64 device\r4300\x86 device\r4300\new_dynarec\x64 mupen64plus-core-src-2.6.0/projects/unix/000077500000000000000000000000001464506436200202625ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/projects/unix/Makefile000077500000000000000000000674041464506436200217400ustar00rootroot00000000000000#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # * Mupen64plus - Makefile * # * Mupen64Plus homepage: https://mupen64plus.org/ * # * Copyright (C) 2008-2009 Richard Goedeken * # * Copyright (C) 2007-2008 DarkJeztr Tillin9 * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ # Makefile for Mupen64Plus Core # detect operating system UNAME ?= $(shell uname -s) OS := NONE ifeq ("$(UNAME)","Linux") OS = LINUX endif ifeq ("$(UNAME)","linux") OS = LINUX endif ifneq ("$(filter GNU hurd,$(UNAME))","") OS = LINUX endif ifeq ("$(UNAME)","Darwin") OS = OSX endif ifeq ("$(UNAME)","FreeBSD") OS = FREEBSD endif ifeq ("$(UNAME)","OpenBSD") OS = FREEBSD CFLAGS += -DIOAPI_NO_64 endif ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","") OS = LINUX endif ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW") OS = MINGW PIC = 0 endif ifeq ("$(OS)","NONE") $(error OS type "$(UNAME)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues') endif # detect system architecture HOST_CPU ?= $(shell uname -m) CPU := NONE ifneq ("$(filter x86_64 amd64,$(HOST_CPU))","") CPU := X86 ifeq ("$(BITS)", "32") ARCH_DETECTED := 64BITS_32 PIC ?= 0 else ARCH_DETECTED := 64BITS PIC ?= 1 endif endif ifneq ("$(filter pentium i%86,$(HOST_CPU))","") CPU := X86 ARCH_DETECTED := 32BITS PIC ?= 0 endif ifneq ("$(filter ppc macppc socppc powerpc,$(HOST_CPU))","") CPU := PPC ARCH_DETECTED := 32BITS BIG_ENDIAN := 1 PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.) endif ifneq ("$(filter ppc64 powerpc64,$(HOST_CPU))","") CPU := PPC ARCH_DETECTED := 64BITS BIG_ENDIAN := 1 PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.) endif ifneq ("$(filter ppc64le powerpc64le,$(HOST_CPU))","") CPU := PPC ARCH_DETECTED := 64BITS BIG_ENDIAN := 0 PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.) endif ifneq ("$(filter arm%,$(HOST_CPU))","") ifeq ("$(filter arm%b,$(HOST_CPU))","") CPU := ARM PIC ?= 1 NEW_DYNAREC := 1 ifneq ("$(filter arm64,$(HOST_CPU))","") ARCH_DETECTED := 64BITS $(warning Architecture "$(HOST_CPU)" not officially supported.) else ARCH_DETECTED := 32BITS CFLAGS += -marm ifneq ("$(filter armv5%,$(HOST_CPU))","") CFLAGS += -DARMv5_ONLY $(warning Using ARMv5_ONLY) endif ifneq ("$(filter armv6%,$(HOST_CPU))","") CFLAGS += -DARMv5_ONLY $(warning Using ARMv5_ONLY) endif ifeq ($(NEON), 1) CFLAGS += -mfpu=neon -mfloat-abi=hard else ifeq ($(VFP_HARD), 1) CFLAGS += -mfpu=vfp -mfloat-abi=hard else CFLAGS += -mfpu=vfp -mfloat-abi=softfp endif endif endif endif endif ifneq ("$(filter mips,$(HOST_CPU))","") CPU := MIPS ARCH_DETECTED := 32BITS PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.) endif ifneq ("$(filter aarch64,$(HOST_CPU))","") CPU := ARM ARCH_DETECTED := 64BITS PIC ?= 1 NEW_DYNAREC := 1 endif ifneq ("$(filter riscv64,$(HOST_CPU))","") CPU := RISCV64 ARCH_DETECTED := 64BITS PIC ?= 1 NO_ASM := 1 $(warning Architecture "$(HOST_CPU)" not officially supported.) endif ifeq ("$(CPU)","NONE") $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues') endif # directory paths SRCDIR = ../../src OBJDIR = _obj$(POSTFIX) SUBDIR = ../../subprojects # base CFLAGS, LDLIBS, and LDFLAGS OPTFLAGS ?= -O3 -flto WARNFLAGS ?= -Wall CFLAGS += -fno-strict-aliasing -fvisibility=hidden -I$(SRCDIR) -I$(SRCDIR)/asm_defines -DM64P_PARALLEL CXXFLAGS += -fvisibility-inlines-hidden LDLIBS += -lm # Since we are building a shared library, we must compile with -fPIC on some architectures # On 32-bit x86 systems we do not want to use -fPIC because we don't have to and it has a big performance penalty on this arch ifeq ($(PIC), 1) CFLAGS += -fPIC else CFLAGS += -fno-PIC endif ifeq ($(BIG_ENDIAN), 1) CFLAGS += -DM64P_BIG_ENDIAN endif # tweak flags for 32-bit build on 64-bit system ifeq ($(ARCH_DETECTED), 64BITS_32) ifeq ($(OS), FREEBSD) $(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386) endif ifneq ($(OS), OSX) ifeq ($(OS), MINGW) LDFLAGS += -Wl,-m,i386pe else CFLAGS += -m32 LDFLAGS += -Wl,-m,elf_i386 endif endif endif ifeq ($(ARCH_DETECTED), 64BITS) ifeq ($(OS), MINGW) LDFLAGS += -Wl,-m,i386pep endif endif # set special flags per-system ifeq ($(OS), FREEBSD) TARGET = libmupen64plus$(POSTFIX).so.2.0.0 SONAME = libmupen64plus$(POSTFIX).so.2 LDFLAGS += -Wl,-Bsymbolic -shared -Wl,-export-dynamic -Wl,-soname,$(SONAME) LDLIBS += -L${LOCALBASE}/lib -lc ifeq ($(ARCH_DETECTED), 64BITS) ASFLAGS = -f elf64 else ASFLAGS = -f elf endif endif ifeq ($(OS), LINUX) TARGET = libmupen64plus$(POSTFIX).so.2.0.0 SONAME = libmupen64plus$(POSTFIX).so.2 LDFLAGS += -Wl,-Bsymbolic -shared -Wl,-export-dynamic -Wl,-soname,$(SONAME) LDLIBS += -ldl # only export api symbols LDFLAGS += -Wl,-version-script,$(SRCDIR)/api/api_export.ver ifeq ($(ARCH_DETECTED), 64BITS) ASFLAGS = -f elf64 else ASFLAGS = -f elf endif endif ifeq ($(OS), OSX) OSX_SDK_PATH = $(shell xcrun --sdk macosx --show-sdk-path) TARGET = libmupen64plus$(POSTFIX).dylib LDFLAGS += -framework CoreFoundation -dynamiclib LDLIBS += -ldl ifeq ($(ARCH_DETECTED), 64BITS) ASFLAGS = -f macho64 -d LEADING_UNDERSCORE else ASFLAGS = -f macho -d LEADING_UNDERSCORE endif CXXFLAGS += '-stdlib=libc++' ifeq ($(CPU), X86) ifeq ($(ARCH_DETECTED), 64BITS) CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=10.9 -isysroot $(OSX_SDK_PATH) else CFLAGS += -pipe -mmmx -msse -arch i686 -mmacosx-version-min=10.9 -isysroot $(OSX_SDK_PATH) ifneq ($(PROFILE), 1) CFLAGS += -fomit-frame-pointer endif LDFLAGS += -read_only_relocs suppress endif endif ifeq ($(CPU), ARM) # assembly compilation not yet supported on macOS with Apple Silicon NO_ASM = 1 CFLAGS += -pipe -arch arm64 -mmacosx-version-min=10.16 -isysroot $(OSX_SDK_PATH) endif endif ifeq ($(OS), MINGW) TARGET = mupen64plus$(POSTFIX).dll ifeq ($(CC), clang) LDFLAGS += -shared -Wl,-export-all-symbols else LDFLAGS += -Wl,-Bsymbolic -shared -Wl,-export-all-symbols # only export api symbols LDFLAGS += -Wl,-version-script,$(SRCDIR)/api/api_export.ver endif LDLIBS += -lpthread ifeq ($(ARCH_DETECTED), 64BITS) ASFLAGS = -f win64 -d WIN64 else ASFLAGS = -f win32 -d LEADING_UNDERSCORE endif endif ifeq ($(PIC), 1) ASFLAGS += -d PIC endif # assembler also needs base include directories ASFLAGS += -I$(SRCDIR) -I$(SRCDIR)/asm_defines/ ifeq ($(CPU_ENDIANNESS), BIG) CFLAGS += -DM64P_BIG_ENDIAN endif # disable verbose output ifneq ($(findstring $(MAKEFLAGS),s),s) ifndef V Q_CC = @echo ' CC '$@; Q_CXX = @echo ' CXX '$@; Q_AS = @echo ' AS '$@; Q_LD = @echo ' LD '$@; endif endif # test for essential build dependencies ifeq ($(origin PKG_CONFIG), undefined) PKG_CONFIG = $(CROSS_COMPILE)pkg-config ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),) $(error $(PKG_CONFIG) not found) endif endif ifeq ($(OS), OSX) # use system zlib on OSX ZLIB_LDLIBS += -lz endif ifeq ($(origin ZLIB_CFLAGS) $(origin ZLIB_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion zlib 2>/dev/null),) $(error No zlib development libraries found!) endif ZLIB_CFLAGS += $(shell $(PKG_CONFIG) --cflags zlib) ZLIB_LDLIBS += $(shell $(PKG_CONFIG) --libs zlib) endif CFLAGS += $(ZLIB_CFLAGS) LDLIBS += $(ZLIB_LDLIBS) ifeq ($(origin MINIZIP_CFLAGS) $(origin MINIZIP_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion minizip 2>/dev/null),) CFLAGS += -DNOCRYPT -DNOUNCRYPT -I$(SUBDIR)/minizip MINIZIP_SOURCE = \ $(SUBDIR)/minizip/ioapi.c \ $(SUBDIR)/minizip/zip.c \ $(SUBDIR)/minizip/unzip.c else MINIZIP_CFLAGS = $(shell $(PKG_CONFIG) --cflags minizip) MINIZIP_LDLIBS = $(shell $(PKG_CONFIG) --libs minizip) endif endif CFLAGS += $(MINIZIP_CFLAGS) LDLIBS += $(MINIZIP_LDLIBS) ifeq ($(origin LIBPNG_CFLAGS) $(origin LIBPNG_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion libpng 2>/dev/null),) $(error No libpng development libraries found!) endif LIBPNG_CFLAGS += $(shell $(PKG_CONFIG) --cflags libpng) LIBPNG_LDLIBS += $(shell $(PKG_CONFIG) --libs libpng) endif CFLAGS += $(LIBPNG_CFLAGS) LDLIBS += $(LIBPNG_LDLIBS) ifeq ($(OPENCV), 1) # OpenCV lib ifeq ($(origin OPENCV_CFLAGS) $(origin OPENCV_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion opencv 2>/dev/null),) $(error No OpenCV development libraries found!) endif OPENCV_CFLAGS += $(shell $(PKG_CONFIG) --cflags opencv) OPENCV_LDLIBS += $(shell $(PKG_CONFIG) --libs opencv) endif CFLAGS += $(OPENCV_CFLAGS) LDLIBS += $(OPENCV_LDLIBS) endif # test for presence of SDL ifeq ($(origin SDL_CFLAGS) $(origin SDL_LDLIBS), undefined undefined) SDL_CONFIG = $(CROSS_COMPILE)sdl2-config ifeq ($(shell which $(SDL_CONFIG) 2>/dev/null),) SDL_CONFIG = $(CROSS_COMPILE)sdl-config ifeq ($(shell which $(SDL_CONFIG) 2>/dev/null),) $(error No SDL development libraries found!) else ifeq ($(NETPLAY), 1) SDL_LDLIBS += -lSDL_net endif # SDL1 doesn't support vulkan VULKAN = 0 $(warning Using SDL 1.2 libraries) endif else ifeq ($(NETPLAY), 1) SDL_LDLIBS += -lSDL2_net endif endif SDL_CFLAGS += $(shell $(SDL_CONFIG) --cflags) SDL_LDLIBS += $(shell $(SDL_CONFIG) --libs) endif CFLAGS += $(SDL_CFLAGS) LDLIBS += $(SDL_LDLIBS) ifeq ($(VC), 1) CFLAGS += -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/vmcs_host/linux LDLIBS += -L/opt/vc/lib -lbrcmEGL -lbcm_host -lvcos -lvchiq_arm GLES_LIB := -lbrcmGLESv2 USE_GLES := 1 endif ifeq ($(USE_GLES), 1) GLES_LIB ?= -lGLESv2 CFLAGS += -DUSE_GLES LDLIBS += $(GLES_LIB) # OSD uses non-ES code and breaks attribs of video plugins OSD=0 endif OSD ?= 1 ifeq ($(OSD), 1) CFLAGS += -DM64P_OSD ifeq ($(origin FREETYPE2_CFLAGS) $(origin FREETYPE2_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion freetype2 2>/dev/null),) $(error No freetype2 development libraries found!) endif FREETYPE2_CFLAGS += $(shell $(PKG_CONFIG) --cflags freetype2) FREETYPE2_LDLIBS += $(shell $(PKG_CONFIG) --libs freetype2) endif CFLAGS += $(FREETYPE2_CFLAGS) LDLIBS += $(FREETYPE2_LDLIBS) # search for OpenGL libraries ifeq ($(OS), OSX) GL_LDLIBS = -framework OpenGL GLU_LDLIBS = -framework OpenGL endif ifeq ($(OS), MINGW) GL_LDLIBS = -lopengl32 GLU_LDLIBS = -lglu32 endif ifeq ($(origin GL_CFLAGS) $(origin GL_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion gl 2>/dev/null),) $(error No OpenGL development libraries found!) endif GL_CFLAGS += $(shell $(PKG_CONFIG) --cflags gl) GL_LDLIBS += $(shell $(PKG_CONFIG) --libs gl) endif CFLAGS += $(GL_CFLAGS) LDLIBS += $(GL_LDLIBS) ifeq ($(origin GLU_CFLAGS) $(origin GLU_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion glu 2>/dev/null),) $(error No OpenGL utility development libraries found!) endif GLU_CFLAGS += $(shell $(PKG_CONFIG) --cflags glu) GLU_LDLIBS += $(shell $(PKG_CONFIG) --libs glu) endif CFLAGS += $(GLU_CFLAGS) LDLIBS += $(GLU_LDLIBS) endif ifneq ($(OS), OSX) ifneq ($(VULKAN), 0) CFLAGS += -DVIDEXT_VULKAN ifeq ($(origin VULKAN_CFLAGS) $(origin VULKAN_LDLIBS), undefined undefined) ifeq ($(shell $(PKG_CONFIG) --modversion vulkan 2>/dev/null),) $(error No Vulkan development libraries found!) endif VULKAN_CFLAGS += $(shell $(PKG_CONFIG) --cflags vulkan) VULKAN_LDLIBS += $(shell $(PKG_CONFIG) --libs vulkan) endif CFLAGS += $(VULKAN_CFLAGS) LDLIBS += $(VULKAN_LDLIBS) endif endif # set base program pointers and flags CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ STRINGS = $(CROSS_COMPILE)strings AS = nasm TR ?= tr RM ?= rm -f INSTALL ?= install MKDIR ?= mkdir -p AWK ?= awk COMPILE.c = $(Q_CC)$(CC) $(OPTFLAGS) $(WARNFLAGS) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c COMPILE.cc = $(Q_CXX)$(CXX) $(OPTFLAGS) $(WARNFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c COMPILE.as = $(Q_AS)$(AS) $(ASFLAGS) LINK.o = $(Q_LD)$(CXX) $(OPTFLAGS) $(WARNFLAGS) $(CXXFLAGS) $(LDFLAGS) $(TARGET_ARCH) ifeq ($(OS),OSX) LDCONFIG ?= true # no 'ldconfig' under OSX else ifeq ($(OS),LINUX) LDCONFIG ?= PATH="$$PATH:/sbin" ldconfig -n endif ifeq ($(OS),FREEBSD) LDCONFIG ?= PATH="$$PATH:/sbin" ldconfig -m endif endif # compiler/linker flags for various compile-time options. # 1. macro for no assembly language ifeq ($(NO_ASM), 1) CFLAGS += -DNO_ASM endif # 2. variables for profiling and adding debugging symbols ifeq ($(PROFILE), 1) CFLAGS += -pg -g INSTALL_STRIP_FLAG ?= else ifeq ($(DEBUG), 1) CFLAGS += -g OPTFLAGS = -Og INSTALL_STRIP_FLAG ?= else CFLAGS += -DNDEBUG ifneq ($(OS),OSX) INSTALL_STRIP_FLAG ?= -s endif endif endif # 3. other options given to the makefile on the command line ifeq ($(LIRC), 1) CFLAGS += -DWITH_LIRC endif ifeq ($(DEBUGGER), 1) CFLAGS += -DDBG endif ifeq ($(DBG_COMPARE), 1) CFLAGS += -DCOMPARE_CORE endif ifeq ($(DBG_CORE), 1) CFLAGS += -DCORE_DBG endif ifeq ($(DBG_TIMING), 1) CFLAGS += -DPROFILE LDFLAGS += -lrt endif # 4. compile-time directory paths for building into the library ifneq ($(SHAREDIR),) CFLAGS += -DSHAREDIR="$(SHAREDIR)" endif # set installation options ifeq ($(PREFIX),) PREFIX := /usr/local endif ifeq ($(SHAREDIR),) SHAREDIR := $(PREFIX)/share/mupen64plus endif ifeq ($(LIBDIR),) LIBDIR := $(PREFIX)/lib endif ifeq ($(INCDIR),) INCDIR := $(PREFIX)/include/mupen64plus endif # list of required source files for compilation SOURCE = \ $(SRCDIR)/api/callbacks.c \ $(SRCDIR)/api/common.c \ $(SRCDIR)/api/config.c \ $(SRCDIR)/api/debugger.c \ $(SRCDIR)/api/frontend.c \ $(SRCDIR)/api/vidext.c \ $(SRCDIR)/backends/api/video_capture_backend.c \ $(SRCDIR)/backends/plugins_compat/audio_plugin_compat.c \ $(SRCDIR)/backends/plugins_compat/input_plugin_compat.c \ $(SRCDIR)/backends/clock_ctime_plus_delta.c \ $(SRCDIR)/backends/dummy_video_capture.c \ $(SRCDIR)/backends/file_storage.c \ $(SRCDIR)/device/cart/cart.c \ $(SRCDIR)/device/cart/af_rtc.c \ $(SRCDIR)/device/cart/cart_rom.c \ $(SRCDIR)/device/cart/eeprom.c \ $(SRCDIR)/device/cart/flashram.c \ $(SRCDIR)/device/cart/is_viewer.c \ $(SRCDIR)/device/cart/sram.c \ $(SRCDIR)/device/controllers/game_controller.c \ $(SRCDIR)/device/controllers/vru_controller.c \ $(SRCDIR)/device/controllers/paks/biopak.c \ $(SRCDIR)/device/controllers/paks/mempak.c \ $(SRCDIR)/device/controllers/paks/rumblepak.c \ $(SRCDIR)/device/controllers/paks/transferpak.c \ $(SRCDIR)/device/dd/dd_controller.c \ $(SRCDIR)/device/dd/disk.c \ $(SRCDIR)/device/device.c \ $(SRCDIR)/device/gb/gb_cart.c \ $(SRCDIR)/device/gb/mbc3_rtc.c \ $(SRCDIR)/device/gb/m64282fp.c \ $(SRCDIR)/device/memory/memory.c \ $(SRCDIR)/device/pif/bootrom_hle.c \ $(SRCDIR)/device/pif/cic.c \ $(SRCDIR)/device/pif/n64_cic_nus_6105.c \ $(SRCDIR)/device/pif/pif.c \ $(SRCDIR)/device/r4300/cached_interp.c \ $(SRCDIR)/device/r4300/cp0.c \ $(SRCDIR)/device/r4300/cp1.c \ $(SRCDIR)/device/r4300/cp2.c \ $(SRCDIR)/device/r4300/idec.c \ $(SRCDIR)/device/r4300/interrupt.c \ $(SRCDIR)/device/r4300/pure_interp.c \ $(SRCDIR)/device/r4300/r4300_core.c \ $(SRCDIR)/device/r4300/tlb.c \ $(SRCDIR)/device/rcp/ai/ai_controller.c \ $(SRCDIR)/device/rcp/mi/mi_controller.c \ $(SRCDIR)/device/rcp/pi/pi_controller.c \ $(SRCDIR)/device/rcp/rdp/fb.c \ $(SRCDIR)/device/rcp/rdp/rdp_core.c \ $(SRCDIR)/device/rcp/ri/ri_controller.c \ $(SRCDIR)/device/rcp/rsp/rsp_core.c \ $(SRCDIR)/device/rcp/si/si_controller.c \ $(SRCDIR)/device/rcp/vi/vi_controller.c \ $(SRCDIR)/device/rdram/rdram.c \ $(SRCDIR)/main/main.c \ $(SRCDIR)/main/util.c \ $(SRCDIR)/main/cheat.c \ $(SRCDIR)/main/eventloop.c \ $(SRCDIR)/main/rom.c \ $(SRCDIR)/main/savestates.c \ $(SRCDIR)/main/screenshot.c \ $(SRCDIR)/main/sdl_key_converter.c \ $(SRCDIR)/main/workqueue.c \ $(SRCDIR)/plugin/plugin.c \ $(SRCDIR)/plugin/dummy_video.c \ $(SRCDIR)/plugin/dummy_audio.c \ $(SRCDIR)/plugin/dummy_input.c \ $(SRCDIR)/plugin/dummy_rsp.c \ $(MINIZIP_SOURCE) # MD5 lib SOURCE += \ $(SUBDIR)/md5/md5.c CFLAGS += -I$(SUBDIR)/md5 # xxhash CFLAGS += -I$(SUBDIR)/xxhash ifeq ("$(OS)","MINGW") SOURCE += \ $(SRCDIR)/osal/dynamiclib_win32.c \ $(SRCDIR)/osal/files_win32.c else ifeq ("$(OS)","OSX") SOURCE += \ $(SRCDIR)/osal/dynamiclib_unix.c \ $(SRCDIR)/osal/files_macos.c else SOURCE += \ $(SRCDIR)/osal/dynamiclib_unix.c \ $(SRCDIR)/osal/files_unix.c endif ifeq ($(OSD), 1) SOURCE += \ $(SRCDIR)/osd/osd.c \ $(SRCDIR)/osd/oglft_c.cpp # oglft SOURCE += $(SUBDIR)/oglft/OGLFT.cpp CXXFLAGS += -I$(SUBDIR)/oglft endif # netplay ifeq ($(NETPLAY), 1) CFLAGS += -DM64P_NETPLAY SOURCE += $(SRCDIR)/main/netplay.c endif # source files for optional features ifeq ($(DBG_COUNT), 1) CFLAGS += -DCOUNT_INSTR SOURCE += $(SRCDIR)/device/r4300/instr_counters.c endif ifeq ($(DBG_PROFILE), 1) CFLAGS += -DPROFILE_R4300 SOURCE += $(SRCDIR)/main/profile.c endif ifneq ($(NO_ASM), 1) ifeq ($(CPU), X86) ifeq ($(ARCH_DETECTED), 64BITS) DYNAREC = x86_64 else DYNAREC = x86 endif endif ifeq ($(CPU), ARM) ifeq ($(ARCH_DETECTED), 64BITS) DYNAREC = arm64 else DYNAREC = arm endif endif endif ifneq ($(DYNAREC), ) CFLAGS += -DDYNAREC ifeq ($(NEW_DYNAREC), 1) ifeq ($(DYNAREC), x86) CFLAGS += -DNEW_DYNAREC=1 SOURCE += \ $(SRCDIR)/device/r4300/new_dynarec/x86/linkage_x86.asm else ifeq ($(DYNAREC), x86_64) CFLAGS += -DNEW_DYNAREC=2 SOURCE += \ $(SRCDIR)/device/r4300/new_dynarec/x64/linkage_x64.asm else ifeq ($(DYNAREC), arm) CFLAGS += -DNEW_DYNAREC=3 SOURCE += \ $(SRCDIR)/device/r4300/new_dynarec/arm/linkage_arm.S \ $(SRCDIR)/device/r4300/new_dynarec/arm/arm_cpu_features.c else ifeq ($(DYNAREC), arm64) CFLAGS += -DNEW_DYNAREC=4 SOURCE += \ $(SRCDIR)/device/r4300/new_dynarec/arm64/linkage_arm64.S else $(error NEW_DYNAREC is not supported on this architecture) endif SOURCE += \ $(SRCDIR)/device/r4300/new_dynarec/new_dynarec.c else SOURCE += \ $(SRCDIR)/device/r4300/recomp.c \ $(SRCDIR)/device/r4300/$(DYNAREC)/assemble.c \ $(SRCDIR)/device/r4300/$(DYNAREC)/dynarec.c \ $(SRCDIR)/device/r4300/$(DYNAREC)/regcache.c \ $(SRCDIR)/device/r4300/$(DYNAREC)/dyna_start.asm endif endif ifeq ($(LIRC), 1) SOURCE += $(SRCDIR)/main/lirc.c LDLIBS += -llirc_client endif ifeq ($(KEYBINDINGS), 0) CFLAGS += -DNO_KEYBINDINGS endif ifeq ($(ACCURATE_FPU), 1) CFLAGS += -DACCURATE_FPU_BEHAVIOR endif ifeq ($(DEBUGGER), 1) SOURCE += \ $(SRCDIR)/debugger/dbg_debugger.c \ $(SRCDIR)/debugger/dbg_decoder.c \ $(SRCDIR)/debugger/dbg_memory.c \ $(SRCDIR)/debugger/dbg_breakpoints.c LDLIBS += -lopcodes -lbfd # UGLY libopcodes/libbfd version check (we check for >= 2.28 and >= 2.39) LIBOPCODES_VERSION := $(shell $(STRINGS) --version | head -n1 | rev | cut -d ' ' -f1 | rev) LIBOPCODES_MAJOR := $(shell echo $(LIBOPCODES_VERSION) | cut -f1 -d.) LIBOPCODES_MINOR := $(shell echo $(LIBOPCODES_VERSION) | cut -f2 -d.) LIBOPCODES_POINT := $(shell echo $(LIBOPCODES_VERSION) | cut -f3 -d. | sed 's/^$$/0/') LIBOPCODES_GE_2_29 := $(shell [ $(LIBOPCODES_MAJOR) -gt 2 -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -ge 28 \) -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -eq 28 -a $(LIBOPCODES_POINT) -ge 1 \) ] && echo true) LIBBFD_GE_2_39 := $(shell [ $(LIBOPCODES_MAJOR) -gt 2 -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -ge 39 \) -o \( $(LIBOPCODES_MAJOR) -eq 2 -a $(LIBOPCODES_MINOR) -eq 39 -a $(LIBOPCODES_POINT) -ge 1 \) ] && echo true) ifeq ($(LIBOPCODES_GE_2_29),true) CFLAGS += -DUSE_LIBOPCODES_GE_2_29 endif ifeq ($(LIBBFD_GE_2_39),true) CFLAGS += -DUSE_LIBBFD_GE_2_39 endif endif ifeq ($(OPENCV), 1) SOURCE += $(SRCDIR)/backends/opencv_video_capture.cpp CFLAGS += -DM64P_OPENCV endif # generate a list of object files to build, make a temporary directory for them OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter $(SRCDIR)/%.c, $(SOURCE))) OBJECTS += $(patsubst $(SUBDIR)/%.c, $(OBJDIR)/subprojects/%.o, $(filter $(SUBDIR)/%.c, $(SOURCE))) OBJECTS += $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRCDIR)/asm_defines/asm_defines.c) OBJECTS += $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(filter $(SRCDIR)/%.cpp, $(SOURCE))) OBJECTS += $(patsubst $(SUBDIR)/%.cpp, $(OBJDIR)/subprojects/%.o, $(filter $(SUBDIR)/%.cpp, $(SOURCE))) OBJECTS += $(patsubst $(SRCDIR)/%.S, $(OBJDIR)/%.o, $(filter %.S, $(SOURCE))) OBJECTS += $(patsubst $(SRCDIR)/%.asm, $(OBJDIR)/%.o, $(filter %.asm, $(SOURCE))) OBJDIRS = $(dir $(OBJECTS)) $(shell $(MKDIR) $(OBJDIRS)) # we have a special object file for the new dynarec ASM_DEFINES_OBJ = $(OBJDIR)/asm_defines/asm_defines.o # build targets targets: @echo "Mupen64Plus-core makefile." @echo " Targets:" @echo " all == Build Mupen64Plus core library" @echo " clean == remove object files" @echo " install == Install Mupen64Plus core library" @echo " uninstall == Uninstall Mupen64Plus core library" @echo " Build Options:" @echo " BITS=32 == build 32-bit binaries on 64-bit machine" @echo " LIRC=1 == enable LIRC support" @echo " NO_ASM=1 == build without assembly (no dynamic recompiler or MMX/SSE code)" @echo " USE_GLES=1 == build against GLESv2 instead of OpenGL" @echo " VC=1 == build against Broadcom Videocore GLESv2" @echo " NEON=1 == (ARM only) build for hard floating point environments" @echo " VFP_HARD=1 == (ARM only) full hardware floating point ABI" @echo " SHAREDIR=path == extra path to search for shared data files" @echo " OPTFLAGS=flag == compiler optimization (default: -O3 -flto)" @echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)" @echo " PIC=(1|0) == Force enable/disable of position independent code" @echo " OSD=(1|0) == Enable/disable build of OpenGL On-screen display" @echo " NETPLAY=1 == Enable netplay functionality, requires SDL2_net" @echo " NEW_DYNAREC=1 == Replace dynamic recompiler with Ari64's experimental dynarec" @echo " KEYBINDINGS=0 == Disables the default keybindings" @echo " ACCURATE_FPU=1 == Enables accurate FPU behavior (i.e correct cause bits)" @echo " OPENCV=1 == Enable OpenCV support" @echo " VULKAN=0 == Disable vulkan support for the default video extension implementation" @echo " POSTFIX=name == String added to the name of the the build (default: '')" @echo " Install Options:" @echo " PREFIX=path == install/uninstall prefix (default: /usr/local)" @echo " SHAREDIR=path == path to install shared data files (default: PREFIX/share/mupen64plus)" @echo " LIBDIR=path == path to install core library (default: PREFIX/lib)" @echo " INCDIR=path == path to install core header files (default: PREFIX/include/mupen64plus)" @echo " DESTDIR=path == path to prepend to all installation paths (only for packagers)" @echo " Debugging Options:" @echo " PROFILE=1 == build gprof instrumentation into binaries for profiling" @echo " DEBUG=1 == add debugging symbols to binaries" @echo " DEBUGGER=1 == build debugger API into core for front-ends. runs slower." @echo " DBG_CORE=1 == print debugging info in r4300 core" @echo " DBG_COUNT=1 == print R4300 instruction count totals (64-bit dynarec only)" @echo " DBG_COMPARE=1 == enable core-synchronized r4300 debugging" @echo " DBG_TIMING=1 == print timing data" @echo " DBG_PROFILE=1 == dump profiling data for r4300 dynarec to data file" @echo " V=1 == show verbose compiler output" all: $(TARGET) install: $(TARGET) $(INSTALL) -d "$(DESTDIR)$(LIBDIR)" $(INSTALL) -m 0644 $(INSTALL_STRIP_FLAG) $(TARGET) "$(DESTDIR)$(LIBDIR)" $(INSTALL) -d "$(DESTDIR)$(SHAREDIR)" $(INSTALL) -m 0644 $(SRCDIR)/../data/* "$(DESTDIR)$(SHAREDIR)" $(INSTALL) -d "$(DESTDIR)$(INCDIR)" $(INSTALL) -m 0644 $(SRCDIR)/api/m64p_*.h "$(DESTDIR)$(INCDIR)" -$(LDCONFIG) "$(DESTDIR)$(LIBDIR)" if [ ! -e "$(DESTDIR)$(LIBDIR)/$(SONAME)" ]; then ln -sf "$(TARGET)" "$(DESTDIR)$(LIBDIR)/$(SONAME)"; fi uninstall: $(RM) "$(DESTDIR)$(LIBDIR)/$(TARGET)" if [ "$(SONAME)" != "" ]; then $(RM) "$(DESTDIR)$(LIBDIR)/$(SONAME)"; fi $(RM) $(DESTDIR)$(INCDIR)/m64p_*.h $(RM) "$(DESTDIR)$(SHAREDIR)/mupen64plus.ini" $(RM) "$(DESTDIR)$(SHAREDIR)/font.ttf" $(RM) "$(DESTDIR)$(SHAREDIR)/mupencheat.txt" clean: $(RM) -r _obj $(OBJDIR) $(TARGET) $(SONAME) $(SRCDIR)/asm_defines/asm_defines_*.h # build dependency files CFLAGS += -MD -MP -include $(OBJECTS:.o=.d) CXXFLAGS += $(CFLAGS) # It is important to disable LTO for this object file # otherwise we can't extract usefull information from it. $(ASM_DEFINES_OBJ): $(SRCDIR)/asm_defines/asm_defines.c $(COMPILE.c) -fno-lto -o $@ $< # Script hackery for generating ASM include files for the new dynarec assembly code $(SRCDIR)/asm_defines/asm_defines_gas.h: $(SRCDIR)/asm_defines/asm_defines_nasm.h $(SRCDIR)/asm_defines/asm_defines_nasm.h: $(ASM_DEFINES_OBJ) $(SRCDIR)/../tools/gen_asm_script.sh bash $(SRCDIR)/../tools/gen_asm_script.sh "$(SRCDIR)/asm_defines" "$(ASM_DEFINES_OBJ)" # standard build rules $(OBJDIR)/%.o: $(SRCDIR)/%.asm $(SRCDIR)/asm_defines/asm_defines_nasm.h $(COMPILE.as) -o $@ $< $(OBJDIR)/%.o: $(SRCDIR)/%.S $(SRCDIR)/asm_defines/asm_defines_gas.h $(COMPILE.c) -o $@ $< $(OBJDIR)/%.o: $(SRCDIR)/%.c $(COMPILE.c) -o $@ $< $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(COMPILE.cc) -o $@ $< $(OBJDIR)/subprojects/%.o: $(SUBDIR)/%.c $(COMPILE.c) -o $@ $< $(OBJDIR)/subprojects/%.o: $(SUBDIR)/%.cpp $(COMPILE.cc) -o $@ $< $(TARGET): $(OBJECTS) $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ if [ "$(SONAME)" != "" ]; then ln -sf $@ $(SONAME); fi .PHONY: all clean install uninstall targets mupen64plus-core-src-2.6.0/src/000077500000000000000000000000001464506436200162355ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/api/000077500000000000000000000000001464506436200170065ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/api/api_export.ver000066400000000000000000000033201464506436200216740ustar00rootroot00000000000000{ global: ConfigExternalGetParameter; ConfigExternalOpen; ConfigExternalClose; ConfigDeleteSection; ConfigGetParamBool; ConfigGetParameter; ConfigGetParameterHelp; ConfigGetParameterType; ConfigGetParamFloat; ConfigGetParamInt; ConfigGetParamString; ConfigGetSharedDataFilepath; ConfigGetUserCachePath; ConfigGetUserConfigPath; ConfigGetUserDataPath; ConfigHasUnsavedChanges; ConfigListParameters; ConfigListSections; ConfigOpenSection; ConfigRevertChanges; ConfigSaveFile; ConfigSaveSection; ConfigSetDefaultBool; ConfigSetDefaultFloat; ConfigSetDefaultInt; ConfigSetDefaultString; ConfigSetParameter; ConfigSetParameterHelp; ConfigSendNetplayConfig; ConfigReceiveNetplayConfig; ConfigOverrideUserPaths; CoreAddCheat; CoreAttachPlugin; CoreCheatEnabled; CoreDetachPlugin; CoreDoCommand; CoreErrorMessage; CoreGetAPIVersions; CoreGetRomSettings; CoreOverrideVidExt; CoreShutdown; CoreStartup; DebugBreakpointCommand; DebugBreakpointLookup; DebugBreakpointTriggeredBy; DebugDecodeOp; DebugGetCPUDataPtr; DebugGetState; DebugMemGetMemInfo; DebugMemGetPointer; DebugMemGetRecompInfo; DebugMemRead16; DebugMemRead32; DebugMemRead64; DebugMemRead8; DebugMemWrite16; DebugMemWrite32; DebugMemWrite64; DebugMemWrite8; DebugSetCallbacks; DebugSetCoreCompare; DebugSetRunState; DebugStep; DebugVirtualToPhysical; PluginGetVersion; VidExt_GL_GetProcAddress; VidExt_GL_SetAttribute; VidExt_GL_GetAttribute; VidExt_GL_SwapBuffers; VidExt_Init; VidExt_InitWithRenderMode; VidExt_ListFullscreenModes; VidExt_ListFullscreenRates; VidExt_Quit; VidExt_SetCaption; VidExt_SetVideoMode; VidExt_SetVideoModeWithRate; VidExt_ToggleFullScreen; VidExt_ResizeWindow; VidExt_GL_GetDefaultFramebuffer; VidExt_VK_GetSurface; VidExt_VK_GetInstanceExtensions; local: *; }; mupen64plus-core-src-2.6.0/src/api/callbacks.c000066400000000000000000000053221464506436200210730ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/callbacks.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the Core functions for handling callbacks to the * front-end application */ #include #include #include #include "api/m64p_frontend.h" #include "callbacks.h" #include "m64p_types.h" /* local variables */ static ptr_DebugCallback pDebugFunc = NULL; static ptr_StateCallback pStateFunc = NULL; static void * DebugContext = NULL; static void * StateContext = NULL; /* global Functions for use by the Core */ m64p_error SetDebugCallback(ptr_DebugCallback pFunc, void *Context) { pDebugFunc = pFunc; DebugContext = Context; return M64ERR_SUCCESS; } m64p_error SetStateCallback(ptr_StateCallback pFunc, void *Context) { pStateFunc = pFunc; StateContext = Context; return M64ERR_SUCCESS; } void DebugMessage(int level, const char *message, ...) { char msgbuf[512]; va_list args; if (pDebugFunc == NULL) return; va_start(args, message); vsnprintf(msgbuf, 512, message, args); (*pDebugFunc)(DebugContext, level, msgbuf); va_end(args); } void StateChanged(m64p_core_param param_type, int new_value) { if (pStateFunc == NULL) return; (*pStateFunc)(StateContext, param_type, new_value); } mupen64plus-core-src-2.6.0/src/api/callbacks.h000066400000000000000000000044521464506436200211030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/callbacks.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for callback functions which will be * called from the other Core modules */ #if !defined(API_CALLBACKS_H) #define API_CALLBACKS_H #include "m64p_frontend.h" #include "m64p_types.h" #if defined(__GNUC__) #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) #else #define ATTR_FMT(fmtpos, attrpos) #endif /* Functions for use by the Core, to send information back to the front-end app */ extern m64p_error SetDebugCallback(ptr_DebugCallback pFunc, void *Context); extern m64p_error SetStateCallback(ptr_StateCallback pFunc, void *Context); extern void DebugMessage(int level, const char *message, ...) ATTR_FMT(2,3); extern void StateChanged(m64p_core_param param_type, int new_value); #endif /* API_CALLBACKS_H */ mupen64plus-core-src-2.6.0/src/api/common.c000066400000000000000000000111171464506436200204430ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/common.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the Core common functions which will be exported * outside of the core library. */ #include #include #define M64P_CORE_PROTOTYPES 1 #include "../main/version.h" #include "m64p_common.h" #include "m64p_types.h" EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { /* set version info */ if (PluginType != NULL) *PluginType = M64PLUGIN_CORE; if (PluginVersion != NULL) *PluginVersion = MUPEN_CORE_VERSION; if (APIVersion != NULL) *APIVersion = FRONTEND_API_VERSION; if (PluginNamePtr != NULL) *PluginNamePtr = MUPEN_CORE_NAME; if (Capabilities != NULL) { *Capabilities = 0; #if defined(DBG) *Capabilities |= M64CAPS_DEBUGGER; #endif #if defined(DYNAREC) *Capabilities |= M64CAPS_DYNAREC; #endif #if defined(COMPARE_CORE) *Capabilities |= M64CAPS_CORE_COMPARE; #endif } return M64ERR_SUCCESS; } EXPORT m64p_error CALL CoreGetAPIVersions(int *ConfigVersion, int *DebugVersion, int *VidextVersion, int *ExtraVersion) { /* set version info */ if (ConfigVersion != NULL) *ConfigVersion = CONFIG_API_VERSION; if (DebugVersion != NULL) *DebugVersion = DEBUG_API_VERSION; if (VidextVersion != NULL) *VidextVersion = VIDEXT_API_VERSION; if (ExtraVersion != NULL) *ExtraVersion = 0; return M64ERR_SUCCESS; } static const char *ErrorMessages[] = { "SUCCESS: No error", "NOT_INIT: A function was called before it's associated module was initialized", "ALREADY_INIT: Initialization function called twice", "INCOMPATIBLE: API versions between components are incompatible", "INPUT_ASSERT: Invalid function parameters, such as a NULL pointer", "INPUT_INVALID: An input function parameter is logically invalid", "INPUT_NOT_FOUND: The input parameter(s) specified a particular item which was not found", "NO_MEMORY: Memory allocation failed", "FILES: Error opening, creating, reading, or writing to a file", "INTERNAL: logical inconsistency in program code. Probably a bug.", "INVALID_STATE: An operation was requested which is not allowed in the current state", "PLUGIN_FAIL: A plugin function returned a fatal error", "SYSTEM_FAIL: A system function call, such as an SDL or file operation, failed", "UNSUPPORTED: Function call is not supported (ie, core not built with debugger)", "WRONG_TYPE: A given input type parameter cannot be used for desired operation" }; EXPORT const char * CALL CoreErrorMessage(m64p_error ReturnCode) { size_t i = (size_t) ReturnCode; if (i >= (sizeof(ErrorMessages) / sizeof(char *))) return "ERROR: Invalid m64p_error code given to CoreErrorMessage()"; return ErrorMessages[i]; } mupen64plus-core-src-2.6.0/src/api/config.c000066400000000000000000001462131464506436200204260ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/config.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the Core config functions which will be exported * outside of the core library. */ #include #include #include #include #define M64P_CORE_PROTOTYPES 1 #include "callbacks.h" #include "config.h" #include "m64p_config.h" #include "m64p_types.h" #include "main/util.h" #include "main/netplay.h" #include "osal/files.h" #include "osal/preproc.h" /* local types */ #define MUPEN64PLUS_CFG_NAME "mupen64plus.cfg" #define SECTION_MAGIC 0xDBDC0580 struct external_config { char *file; size_t length; }; typedef struct _config_var { char *name; m64p_type type; union { int integer; float number; char *string; } val; char *comment; struct _config_var *next; } config_var; typedef struct _config_section { unsigned int magic; char *name; struct _config_var *first_var; struct _config_section *next; } config_section; typedef config_section *config_list; /* local variables */ static int l_ConfigInit = 0; static char *l_DataDirOverride = NULL; static char *l_ConfigDirOverride = NULL; static char *l_UserCacheDirOverride = NULL; static char *l_UserDataDirOverride = NULL; static config_list l_ConfigListActive = NULL; static config_list l_ConfigListSaved = NULL; /* --------------- */ /* local functions */ /* --------------- */ static int is_numeric(const char *string) { char chTemp[16]; float fTemp; int rval = sscanf(string, "%f%8s", &fTemp, chTemp); /* I want to find exactly one matched input item: a number with no garbage on the end */ /* I use sscanf() instead of a custom loop because this routine must handle locales in which the decimal separator is not '.' */ return (rval == 1); } /* This function returns a pointer to the pointer of the requested section * (i.e. a pointer the next field of the previous element, or to the first node). * * If there's no section named 'ParamName', returns the pointer to the next * field of the last element in the list (such that derefencing it is NULL). * * Useful for operations that need to modify the links, e.g. deleting a section. */ static config_section **find_section_link(config_list *list, const char *ParamName) { config_section **curr_sec_link; for (curr_sec_link = list; *curr_sec_link != NULL; curr_sec_link = &(*curr_sec_link)->next) { if (osal_insensitive_strcmp(ParamName, (*curr_sec_link)->name) == 0) break; } return curr_sec_link; } /* This function is similar to the previous function, but instead it returns a * pointer to the pointer to the next section whose name is alphabetically * greater than or equal to 'ParamName'. * * Useful for inserting a section in its alphabetical position. */ static config_section **find_alpha_section_link(config_list *list, const char *ParamName) { config_section **curr_sec_link; for (curr_sec_link = list; *curr_sec_link != NULL; curr_sec_link = &(*curr_sec_link)->next) { if (osal_insensitive_strcmp((*curr_sec_link)->name, ParamName) >= 0) break; } return curr_sec_link; } static config_section *find_section(config_list list, const char *ParamName) { return *find_section_link(&list, ParamName); } static config_var *config_var_create(const char *ParamName, const char *ParamHelp) { config_var *var; if (ParamName == NULL) return NULL; var = (config_var *) malloc(sizeof(config_var)); if (var == NULL) return NULL; memset(var, 0, sizeof(config_var)); var->name = strdup(ParamName); if (var->name == NULL) { free(var); return NULL; } var->type = M64TYPE_INT; var->val.integer = 0; if (ParamHelp != NULL) { var->comment = strdup(ParamHelp); if (var->comment == NULL) { free(var->name); free(var); return NULL; } } else var->comment = NULL; var->next = NULL; return var; } static config_var *find_section_var(config_section *section, const char *ParamName) { /* walk through the linked list of variables in the section */ config_var *curr_var; for (curr_var = section->first_var; curr_var != NULL; curr_var = curr_var->next) { if (osal_insensitive_strcmp(ParamName, curr_var->name) == 0) return curr_var; } /* couldn't find this configuration parameter */ return NULL; } static void append_var_to_section(config_section *section, config_var *var) { config_var *last_var; if (section == NULL || var == NULL || section->magic != SECTION_MAGIC) return; if (section->first_var == NULL) { section->first_var = var; return; } last_var = section->first_var; while (last_var->next != NULL) last_var = last_var->next; last_var->next = var; } static void delete_var(config_var *var) { if (var->type == M64TYPE_STRING) free(var->val.string); free(var->name); free(var->comment); free(var); } static void delete_section(config_section *pSection) { config_var *curr_var; if (pSection == NULL) return; curr_var = pSection->first_var; while (curr_var != NULL) { config_var *next_var = curr_var->next; delete_var(curr_var); curr_var = next_var; } free(pSection->name); free(pSection); } static void delete_list(config_list *pConfigList) { config_section *curr_section = *pConfigList; while (curr_section != NULL) { config_section *next_section = curr_section->next; /* delete the section itself */ delete_section(curr_section); curr_section = next_section; } *pConfigList = NULL; } static config_section *config_section_create(const char *ParamName) { config_section *sec; if (ParamName == NULL) return NULL; sec = (config_section *) malloc(sizeof(config_section)); if (sec == NULL) return NULL; sec->magic = SECTION_MAGIC; sec->name = strdup(ParamName); if (sec->name == NULL) { free(sec); return NULL; } sec->first_var = NULL; sec->next = NULL; return sec; } static config_section * section_deepcopy(config_section *orig_section) { config_section *new_section; config_var *orig_var, *last_new_var; /* Input validation */ if (orig_section == NULL) return NULL; /* create and copy section struct */ new_section = config_section_create(orig_section->name); if (new_section == NULL) return NULL; /* create and copy all section variables */ orig_var = orig_section->first_var; last_new_var = NULL; while (orig_var != NULL) { config_var *new_var = config_var_create(orig_var->name, orig_var->comment); if (new_var == NULL) { delete_section(new_section); return NULL; } new_var->type = orig_var->type; switch (orig_var->type) { case M64TYPE_INT: case M64TYPE_BOOL: new_var->val.integer = orig_var->val.integer; break; case M64TYPE_FLOAT: new_var->val.number = orig_var->val.number; break; case M64TYPE_STRING: if (orig_var->val.string != NULL) { new_var->val.string = strdup(orig_var->val.string); if (new_var->val.string == NULL) { delete_section(new_section); delete_var(new_var); return NULL; } } else new_var->val.string = NULL; break; } /* add the new variable to the new section */ if (last_new_var == NULL) new_section->first_var = new_var; else last_new_var->next = new_var; last_new_var = new_var; /* advance variable pointer in original section variable list */ orig_var = orig_var->next; } return new_section; } static void copy_configlist_active_to_saved(void) { config_section *curr_section = l_ConfigListActive; config_section *last_section = NULL; /* delete any pre-existing Saved config list */ delete_list(&l_ConfigListSaved); /* duplicate all of the config sections in the Active list, adding them to the Saved list */ while (curr_section != NULL) { config_section *new_section = section_deepcopy(curr_section); if (new_section == NULL) break; if (last_section == NULL) l_ConfigListSaved = new_section; else last_section->next = new_section; last_section = new_section; curr_section = curr_section->next; } } static m64p_error write_configlist_file(void) { config_section *curr_section; const char *configpath; char *filepath; FILE *fPtr; /* get the full pathname to the config file and try to open it */ configpath = ConfigGetUserConfigPath(); if (configpath == NULL) return M64ERR_FILES; filepath = combinepath(configpath, MUPEN64PLUS_CFG_NAME); if (filepath == NULL) return M64ERR_NO_MEMORY; fPtr = osal_file_open(filepath, "wb"); if (fPtr == NULL) { DebugMessage(M64MSG_ERROR, "Couldn't open configuration file '%s' for writing.", filepath); free(filepath); return M64ERR_FILES; } free(filepath); /* write out header */ fprintf(fPtr, "# Mupen64Plus Configuration File\n"); fprintf(fPtr, "# This file is automatically read and written by the Mupen64Plus Core library\n"); /* write out all of the config parameters from the Saved list */ curr_section = l_ConfigListSaved; while (curr_section != NULL) { config_var *curr_var = curr_section->first_var; fprintf(fPtr, "\n[%s]\n\n", curr_section->name); while (curr_var != NULL) { if (curr_var->comment != NULL && strlen(curr_var->comment) > 0) fprintf(fPtr, "# %s\n", curr_var->comment); if (curr_var->type == M64TYPE_INT) fprintf(fPtr, "%s = %i\n", curr_var->name, curr_var->val.integer); else if (curr_var->type == M64TYPE_FLOAT) fprintf(fPtr, "%s = %f\n", curr_var->name, curr_var->val.number); else if (curr_var->type == M64TYPE_BOOL && curr_var->val.integer) fprintf(fPtr, "%s = True\n", curr_var->name); else if (curr_var->type == M64TYPE_BOOL && !curr_var->val.integer) fprintf(fPtr, "%s = False\n", curr_var->name); else if (curr_var->type == M64TYPE_STRING && curr_var->val.string != NULL) fprintf(fPtr, "%s = \"%s\"\n", curr_var->name, curr_var->val.string); curr_var = curr_var->next; } fprintf(fPtr, "\n"); curr_section = curr_section->next; } fclose(fPtr); return M64ERR_SUCCESS; } /* ----------------------------------------------------------- */ /* these functions are only to be used within the Core library */ /* ----------------------------------------------------------- */ m64p_error ConfigInit(const char *ConfigDirOverride, const char *DataDirOverride) { m64p_error rval; const char *configpath = NULL; char *filepath; long ftell_result; size_t filelen; FILE *fPtr; char *configtext; config_section *current_section = NULL; char *line, *end, *lastcomment; if (l_ConfigInit) return M64ERR_ALREADY_INIT; l_ConfigInit = 1; /* if a data directory was specified, make a copy of it */ if (DataDirOverride != NULL) { l_DataDirOverride = strdup(DataDirOverride); if (l_DataDirOverride == NULL) return M64ERR_NO_MEMORY; } /* if a config directory was specified, make a copy of it */ if (ConfigDirOverride != NULL) { l_ConfigDirOverride = strdup(ConfigDirOverride); if (l_ConfigDirOverride == NULL) return M64ERR_NO_MEMORY; } /* get the full pathname to the config file and try to open it */ configpath = ConfigGetUserConfigPath(); if (configpath == NULL) return M64ERR_FILES; filepath = combinepath(configpath, MUPEN64PLUS_CFG_NAME); if (filepath == NULL) return M64ERR_NO_MEMORY; fPtr = osal_file_open(filepath, "rb"); if (fPtr == NULL) { DebugMessage(M64MSG_INFO, "Couldn't open configuration file '%s'. Using defaults.", filepath); free(filepath); return M64ERR_SUCCESS; } free(filepath); /* read the entire config file */ if (fseek(fPtr, 0L, SEEK_END) != 0) { fclose(fPtr); return M64ERR_FILES; } ftell_result = ftell(fPtr); if (ftell_result == -1) { fclose(fPtr); return M64ERR_FILES; } filelen = (size_t)ftell_result; if (fseek(fPtr, 0L, SEEK_SET) != 0) { fclose(fPtr); return M64ERR_FILES; } configtext = (char *) malloc(filelen + 1); if (configtext == NULL) { fclose(fPtr); return M64ERR_NO_MEMORY; } if (fread(configtext, 1, filelen, fPtr) != filelen) { free(configtext); fclose(fPtr); return M64ERR_FILES; } fclose(fPtr); /* parse the file data */ current_section = NULL; line = configtext; end = configtext + filelen; lastcomment = NULL; *end = 0; while (line < end) { ini_line l = ini_parse_line(&line); switch (l.type) { case INI_COMMENT: lastcomment = l.value; break; case INI_SECTION: rval = ConfigOpenSection(l.name, (m64p_handle *) ¤t_section); if (rval != M64ERR_SUCCESS) { free(configtext); return rval; } lastcomment = NULL; break; case INI_PROPERTY: if (l.value[0] == '"' && l.value[strlen(l.value)-1] == '"') { l.value++; l.value[strlen(l.value)-1] = 0; ConfigSetDefaultString((m64p_handle) current_section, l.name, l.value, lastcomment); } else if (osal_insensitive_strcmp(l.value, "false") == 0) { ConfigSetDefaultBool((m64p_handle) current_section, l.name, 0, lastcomment); } else if (osal_insensitive_strcmp(l.value, "true") == 0) { ConfigSetDefaultBool((m64p_handle) current_section, l.name, 1, lastcomment); } else if (is_numeric(l.value)) { /* preserve values as floats if they are written in the config as floats */ if (strchr(l.value, '.')) { float val_float = (float) strtod(l.value, NULL); ConfigSetDefaultFloat((m64p_handle) current_section, l.name, val_float, lastcomment); } else { int val_int = (int) strtol(l.value, NULL, 10); ConfigSetDefaultInt((m64p_handle) current_section, l.name, val_int, lastcomment); } } else { /* assume that it's a string */ ConfigSetDefaultString((m64p_handle) current_section, l.name, l.value, lastcomment); } lastcomment = NULL; break; default: break; } } /* release memory used for config file text */ free(configtext); /* duplicate the entire config data list, to store a copy of the list which represents the state of the file on disk */ copy_configlist_active_to_saved(); return M64ERR_SUCCESS; } m64p_error ConfigShutdown(void) { /* reset the initialized flag */ if (!l_ConfigInit) return M64ERR_NOT_INIT; l_ConfigInit = 0; /* free any malloc'd local variables */ if (l_DataDirOverride != NULL) { free(l_DataDirOverride); l_DataDirOverride = NULL; } if (l_ConfigDirOverride != NULL) { free(l_ConfigDirOverride); l_ConfigDirOverride = NULL; } if (l_UserDataDirOverride != NULL) { free(l_UserDataDirOverride); l_UserDataDirOverride = NULL; } if (l_UserCacheDirOverride != NULL) { free(l_UserCacheDirOverride); l_UserCacheDirOverride = NULL; } /* free all of the memory in the 2 lists */ delete_list(&l_ConfigListActive); delete_list(&l_ConfigListSaved); return M64ERR_SUCCESS; } /* ------------------------------------------------ */ /* Selector functions, exported outside of the Core */ /* ------------------------------------------------ */ EXPORT m64p_error CALL ConfigExternalOpen(const char *FileName, m64p_handle *Handle) { FILE *fPtr; struct external_config* ext_config; long ftell_result; size_t filelen = 0; if (FileName == NULL || (fPtr = osal_file_open(FileName, "rb")) == NULL) { DebugMessage(M64MSG_ERROR, "Unable to open config file '%s'.", FileName); return M64ERR_INPUT_INVALID; } /* read the entire config file */ if (fseek(fPtr, 0L, SEEK_END) != 0) { fclose(fPtr); return M64ERR_INPUT_INVALID; } ftell_result = ftell(fPtr); if (ftell_result == -1) { fclose(fPtr); return M64ERR_INPUT_INVALID; } filelen = (size_t)ftell_result; if (fseek(fPtr, 0L, SEEK_SET) != 0) { fclose(fPtr); return M64ERR_INPUT_INVALID; } ext_config = malloc(sizeof(struct external_config)); if (ext_config == NULL) { fclose(fPtr); return M64ERR_INPUT_INVALID; } ext_config->file = malloc(filelen + 1); if (ext_config->file == NULL) { free(ext_config); fclose(fPtr); return M64ERR_INPUT_INVALID; } if (fread(ext_config->file, 1, filelen, fPtr) != filelen) { free(ext_config->file); free(ext_config); fclose(fPtr); return M64ERR_INPUT_INVALID; } fclose(fPtr); ext_config->length = filelen; *Handle = ext_config; return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigExternalClose(m64p_handle Handle) { struct external_config* ext_config = Handle; if (ext_config != NULL) { if (ext_config->file != NULL) free(ext_config->file); free(ext_config); return M64ERR_SUCCESS; } return M64ERR_INPUT_INVALID; } EXPORT m64p_error CALL ConfigExternalGetParameter(m64p_handle Handle, const char *SectionName, const char *ParamName, char* ParamPtr, int ParamMaxLength) { struct external_config* ext_config = Handle; int foundSection = 0; if (ParamPtr == NULL || SectionName == NULL || ParamName == NULL) return M64ERR_INPUT_INVALID; void *buffer = malloc(ext_config->length + 1); memcpy(buffer, ext_config->file, ext_config->length + 1); char *line = buffer; char *end = line + ext_config->length; while (line < end) { ini_line l = ini_parse_line(&line); switch (l.type) { case INI_SECTION: if (osal_insensitive_strcmp(SectionName, l.name) == 0) foundSection = 1; else foundSection = 0; break; case INI_PROPERTY: if (foundSection) { if (osal_insensitive_strcmp(ParamName, l.name) == 0) { strncpy(ParamPtr, l.value, ParamMaxLength); free(buffer); return M64ERR_SUCCESS; } } break; default: break; } } free(buffer); return M64ERR_INPUT_NOT_FOUND; } EXPORT m64p_error CALL ConfigListSections(void *context, void (*SectionListCallback)(void * context, const char * SectionName)) { config_section *curr_section; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionListCallback == NULL) return M64ERR_INPUT_ASSERT; /* just walk through the section list, making a callback for each section name */ curr_section = l_ConfigListActive; while (curr_section != NULL) { (*SectionListCallback)(context, curr_section->name); curr_section = curr_section->next; } return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigOpenSection(const char *SectionName, m64p_handle *ConfigSectionHandle) { config_section **curr_section; config_section *new_section; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL || ConfigSectionHandle == NULL) return M64ERR_INPUT_ASSERT; /* walk through the section list, looking for a case-insensitive name match */ curr_section = find_alpha_section_link(&l_ConfigListActive, SectionName); if (*curr_section != NULL && osal_insensitive_strcmp(SectionName, (*curr_section)->name) == 0) { *ConfigSectionHandle = *curr_section; return M64ERR_SUCCESS; } /* didn't find the section, so create new one */ new_section = config_section_create(SectionName); if (new_section == NULL) return M64ERR_NO_MEMORY; /* add section to list in alphabetical order */ new_section->next = *curr_section; *curr_section = new_section; *ConfigSectionHandle = new_section; return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigListParameters(m64p_handle ConfigSectionHandle, void *context, void (*ParameterListCallback)(void * context, const char *ParamName, m64p_type ParamType)) { config_section *section; config_var *curr_var; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParameterListCallback == NULL) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* walk through this section's parameter list, making a callback for each parameter */ curr_var = section->first_var; while (curr_var != NULL) { (*ParameterListCallback)(context, curr_var->name, curr_var->type); curr_var = curr_var->next; } return M64ERR_SUCCESS; } EXPORT int CALL ConfigHasUnsavedChanges(const char *SectionName) { config_section *input_section, *curr_section; config_var *active_var, *saved_var; /* check input conditions */ if (!l_ConfigInit) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Core config not initialized!"); return 0; } /* if SectionName is NULL or blank, then check all sections */ if (SectionName == NULL || strlen(SectionName) < 1) { int iNumActiveSections = 0, iNumSavedSections = 0; /* first, search through all sections in Active list. Recursively call ourself and return 1 if changed */ curr_section = l_ConfigListActive; while (curr_section != NULL) { if (ConfigHasUnsavedChanges(curr_section->name)) return 1; curr_section = curr_section->next; iNumActiveSections++; } /* Next, count the number of Saved sections and see if the count matches */ curr_section = l_ConfigListSaved; while (curr_section != NULL) { curr_section = curr_section->next; iNumSavedSections++; } if (iNumActiveSections == iNumSavedSections) return 0; /* no changes */ else return 1; } /* walk through the Active section list, looking for a case-insensitive name match with input string */ input_section = find_section(l_ConfigListActive, SectionName); if (input_section == NULL) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): section name '%s' not found!", SectionName); return 0; } /* walk through the Saved section list, looking for a case-insensitive name match */ curr_section = find_section(l_ConfigListSaved, SectionName); if (curr_section == NULL) { /* if this section isn't present in saved list, then it has been newly created */ return 1; } /* compare all of the variables in the two sections. They are expected to be in the same order */ active_var = input_section->first_var; saved_var = curr_section->first_var; while (active_var != NULL && saved_var != NULL) { if (strcmp(active_var->name, saved_var->name) != 0) return 1; if (active_var->type != saved_var->type) return 1; switch(active_var->type) { case M64TYPE_INT: if (active_var->val.integer != saved_var->val.integer) return 1; break; case M64TYPE_FLOAT: if (active_var->val.number != saved_var->val.number) return 1; break; case M64TYPE_BOOL: if ((active_var->val.integer != 0) != (saved_var->val.integer != 0)) return 1; break; case M64TYPE_STRING: if (active_var->val.string == NULL) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Variable '%s' NULL Active string pointer!", active_var->name); return 1; } if (saved_var->val.string == NULL) { DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Variable '%s' NULL Saved string pointer!", active_var->name); return 1; } if (strcmp(active_var->val.string, saved_var->val.string) != 0) return 1; break; default: DebugMessage(M64MSG_ERROR, "ConfigHasUnsavedChanges(): Invalid variable '%s' type %i!", active_var->name, active_var->type); return 1; } if (active_var->comment != NULL && saved_var->comment != NULL && strcmp(active_var->comment, saved_var->comment) != 0) return 1; active_var = active_var->next; saved_var = saved_var->next; } /* any extra new variables on the end, or deleted variables? */ if (active_var != NULL || saved_var != NULL) return 1; /* exactly the same */ return 0; } /* ------------------------------------------------------- */ /* Modifier functions, exported outside of the Core */ /* ------------------------------------------------------- */ EXPORT m64p_error CALL ConfigDeleteSection(const char *SectionName) { config_section **curr_section_link; config_section *next_section; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (l_ConfigListActive == NULL) return M64ERR_INPUT_NOT_FOUND; /* find the named section and pull it out of the list */ curr_section_link = find_section_link(&l_ConfigListActive, SectionName); if (*curr_section_link == NULL) return M64ERR_INPUT_NOT_FOUND; next_section = (*curr_section_link)->next; /* delete the named section */ delete_section(*curr_section_link); /* fix the pointer to point to the next section after the deleted one */ *curr_section_link = next_section; return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigSaveFile(void) { if (!l_ConfigInit) return M64ERR_NOT_INIT; /* copy the active config list to the saved config list */ copy_configlist_active_to_saved(); /* write the saved config list out to a file */ return (write_configlist_file()); } EXPORT m64p_error CALL ConfigSaveSection(const char *SectionName) { config_section *curr_section, *new_section; config_section **insertion_point; if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL || strlen(SectionName) < 1) return M64ERR_INPUT_ASSERT; /* walk through the Active section list, looking for a case-insensitive name match */ curr_section = find_section(l_ConfigListActive, SectionName); if (curr_section == NULL) return M64ERR_INPUT_NOT_FOUND; /* duplicate this section */ new_section = section_deepcopy(curr_section); if (new_section == NULL) return M64ERR_NO_MEMORY; /* update config section that's in the Saved list with the new one */ insertion_point = find_alpha_section_link(&l_ConfigListSaved, SectionName); if (*insertion_point != NULL && osal_insensitive_strcmp((*insertion_point)->name, SectionName) == 0) { /* the section exists in the saved list and will be replaced */ new_section->next = (*insertion_point)->next; delete_section(*insertion_point); *insertion_point = new_section; } else { /* the section didn't exist in the saved list and has to be inserted */ new_section->next = *insertion_point; *insertion_point = new_section; } /* write the saved config list out to a file */ return (write_configlist_file()); } EXPORT m64p_error CALL ConfigRevertChanges(const char *SectionName) { config_section **active_section_link, *active_section, *saved_section, *new_section; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (SectionName == NULL) return M64ERR_INPUT_ASSERT; /* walk through the Active section list, looking for a case-insensitive name match with input string */ active_section_link = find_section_link(&l_ConfigListActive, SectionName); active_section = *active_section_link; if (active_section == NULL) return M64ERR_INPUT_NOT_FOUND; /* walk through the Saved section list, looking for a case-insensitive name match */ saved_section = find_section(l_ConfigListSaved, SectionName); if (saved_section == NULL) { /* if this section isn't present in saved list, then it has been newly created */ return M64ERR_INPUT_NOT_FOUND; } /* copy the section as it is on the disk */ new_section = section_deepcopy(saved_section); if (new_section == NULL) return M64ERR_NO_MEMORY; /* replace active_section with saved_section in the linked list */ *active_section_link = new_section; new_section->next = active_section->next; /* release memory associated with active_section */ delete_section(active_section); return M64ERR_SUCCESS; } /* ------------------------------------------------------- */ /* Generic Get/Set functions, exported outside of the Core */ /* ------------------------------------------------------- */ EXPORT m64p_error CALL ConfigSetParameter(m64p_handle ConfigSectionHandle, const char *ParamName, m64p_type ParamType, const void *ParamValue) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL || ParamValue == NULL || (int) ParamType < 1 || (int) ParamType > 4) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter doesn't already exist, then create it and add it to the section */ var = find_section_var(section, ParamName); if (var == NULL) { var = config_var_create(ParamName, NULL); if (var == NULL) return M64ERR_NO_MEMORY; append_var_to_section(section, var); } /* cleanup old values */ switch (var->type) { case M64TYPE_STRING: free(var->val.string); break; default: break; } /* set this parameter's value */ var->type = ParamType; switch(ParamType) { case M64TYPE_INT: var->val.integer = *((int *) ParamValue); break; case M64TYPE_FLOAT: var->val.number = *((float *) ParamValue); break; case M64TYPE_BOOL: var->val.integer = (*((int *) ParamValue) != 0); break; case M64TYPE_STRING: var->val.string = strdup((char *)ParamValue); if (var->val.string == NULL) return M64ERR_NO_MEMORY; break; default: /* this is logically impossible because of the ParamType check at the top of this function */ break; } return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigSetParameterHelp(m64p_handle ConfigSectionHandle, const char *ParamName, const char *ParamHelp) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL || ParamHelp == NULL) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) return M64ERR_INPUT_NOT_FOUND; if (var->comment != NULL) free(var->comment); var->comment = strdup(ParamHelp); return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigGetParameter(m64p_handle ConfigSectionHandle, const char *ParamName, m64p_type ParamType, void *ParamValue, int MaxSize) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL || ParamValue == NULL || (int) ParamType < 1 || (int) ParamType > 4) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) return M64ERR_INPUT_NOT_FOUND; /* call the specific Get function to translate the parameter to the desired type */ switch(ParamType) { case M64TYPE_INT: if (MaxSize < (int)sizeof(int)) return M64ERR_INPUT_INVALID; *((int *) ParamValue) = ConfigGetParamInt(ConfigSectionHandle, ParamName); break; case M64TYPE_FLOAT: if (MaxSize < (int)sizeof(float)) return M64ERR_INPUT_INVALID; *((float *) ParamValue) = ConfigGetParamFloat(ConfigSectionHandle, ParamName); break; case M64TYPE_BOOL: if (MaxSize < (int)sizeof(int)) return M64ERR_INPUT_INVALID; *((int *) ParamValue) = ConfigGetParamBool(ConfigSectionHandle, ParamName); break; case M64TYPE_STRING: { const char *string; if (MaxSize < 1) return M64ERR_INPUT_INVALID; if (var->type != M64TYPE_STRING && var->type != M64TYPE_BOOL) return M64ERR_WRONG_TYPE; string = ConfigGetParamString(ConfigSectionHandle, ParamName); strncpy((char *) ParamValue, string, MaxSize); *((char *) ParamValue + MaxSize - 1) = 0; break; } default: /* this is logically impossible because of the ParamType check at the top of this function */ break; } return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigGetParameterType(m64p_handle ConfigSectionHandle, const char *ParamName, m64p_type *ParamType) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL || ParamType == NULL) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) return M64ERR_INPUT_NOT_FOUND; *ParamType = var->type; return M64ERR_SUCCESS; } EXPORT const char * CALL ConfigGetParameterHelp(m64p_handle ConfigSectionHandle, const char *ParamName) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit || ConfigSectionHandle == NULL || ParamName == NULL) return NULL; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return NULL; /* if this parameter doesn't exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) return NULL; return var->comment; } /* ------------------------------------------------------- */ /* Special Get/Set functions, exported outside of the Core */ /* ------------------------------------------------------- */ EXPORT m64p_error CALL ConfigSetDefaultInt(m64p_handle ConfigSectionHandle, const char *ParamName, int ParamValue, const char *ParamHelp) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter already exists, add help text if missing, then return successfully */ var = find_section_var(section, ParamName); if (var != NULL) { if (ParamHelp != NULL && var->comment == NULL) var->comment = strdup(ParamHelp); return M64ERR_SUCCESS; } /* otherwise create a new config_var object and add it to this section */ var = config_var_create(ParamName, ParamHelp); if (var == NULL) return M64ERR_NO_MEMORY; var->type = M64TYPE_INT; var->val.integer = ParamValue; append_var_to_section(section, var); return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigSetDefaultFloat(m64p_handle ConfigSectionHandle, const char *ParamName, float ParamValue, const char *ParamHelp) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter already exists, add help text if missing, then return successfully */ var = find_section_var(section, ParamName); if (var != NULL) { if (ParamHelp != NULL && var->comment == NULL) var->comment = strdup(ParamHelp); return M64ERR_SUCCESS; } /* otherwise create a new config_var object and add it to this section */ var = config_var_create(ParamName, ParamHelp); if (var == NULL) return M64ERR_NO_MEMORY; var->type = M64TYPE_FLOAT; var->val.number = ParamValue; append_var_to_section(section, var); return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigSetDefaultBool(m64p_handle ConfigSectionHandle, const char *ParamName, int ParamValue, const char *ParamHelp) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter already exists, add help text if missing, then return successfully */ var = find_section_var(section, ParamName); if (var != NULL) { if (ParamHelp != NULL && var->comment == NULL) var->comment = strdup(ParamHelp); return M64ERR_SUCCESS; } /* otherwise create a new config_var object and add it to this section */ var = config_var_create(ParamName, ParamHelp); if (var == NULL) return M64ERR_NO_MEMORY; var->type = M64TYPE_BOOL; var->val.integer = ParamValue ? 1 : 0; append_var_to_section(section, var); return M64ERR_SUCCESS; } EXPORT m64p_error CALL ConfigSetDefaultString(m64p_handle ConfigSectionHandle, const char *ParamName, const char * ParamValue, const char *ParamHelp) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit) return M64ERR_NOT_INIT; if (ConfigSectionHandle == NULL || ParamName == NULL || ParamValue == NULL) return M64ERR_INPUT_ASSERT; section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) return M64ERR_INPUT_INVALID; /* if this parameter already exists, add help text if missing, then return successfully */ var = find_section_var(section, ParamName); if (var != NULL) { if (ParamHelp != NULL && var->comment == NULL) var->comment = strdup(ParamHelp); return M64ERR_SUCCESS; } /* otherwise create a new config_var object and add it to this section */ var = config_var_create(ParamName, ParamHelp); if (var == NULL) return M64ERR_NO_MEMORY; var->type = M64TYPE_STRING; var->val.string = strdup(ParamValue); if (var->val.string == NULL) { delete_var(var); return M64ERR_NO_MEMORY; } append_var_to_section(section, var); return M64ERR_SUCCESS; } EXPORT int CALL ConfigGetParamInt(m64p_handle ConfigSectionHandle, const char *ParamName) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit || ConfigSectionHandle == NULL || ParamName == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamInt(): Input assertion!"); return 0; } section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) { DebugMessage(M64MSG_ERROR, "ConfigGetParamInt(): ConfigSectionHandle invalid!"); return 0; } /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamInt(): Parameter '%s' not found!", ParamName); return 0; } /* translate the actual variable type to an int */ switch(var->type) { case M64TYPE_INT: return var->val.integer; case M64TYPE_FLOAT: return (int) var->val.number; case M64TYPE_BOOL: return (var->val.integer != 0); case M64TYPE_STRING: return atoi(var->val.string); default: DebugMessage(M64MSG_ERROR, "ConfigGetParamInt(): invalid internal parameter type for '%s'", ParamName); return 0; } } EXPORT float CALL ConfigGetParamFloat(m64p_handle ConfigSectionHandle, const char *ParamName) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit || ConfigSectionHandle == NULL || ParamName == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamFloat(): Input assertion!"); return 0.0; } section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) { DebugMessage(M64MSG_ERROR, "ConfigGetParamFloat(): ConfigSectionHandle invalid!"); return 0.0; } /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamFloat(): Parameter '%s' not found!", ParamName); return 0.0; } /* translate the actual variable type to a float */ switch(var->type) { case M64TYPE_INT: return (float) var->val.integer; case M64TYPE_FLOAT: return var->val.number; case M64TYPE_BOOL: return (var->val.integer != 0) ? 1.0f : 0.0f; case M64TYPE_STRING: return (float) atof(var->val.string); default: DebugMessage(M64MSG_ERROR, "ConfigGetParamFloat(): invalid internal parameter type for '%s'", ParamName); return 0.0; } } EXPORT int CALL ConfigGetParamBool(m64p_handle ConfigSectionHandle, const char *ParamName) { config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit || ConfigSectionHandle == NULL || ParamName == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): Input assertion!"); return 0; } section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) { DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): ConfigSectionHandle invalid!"); return 0; } /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): Parameter '%s' not found!", ParamName); return 0; } /* translate the actual variable type to an int (0 or 1) */ switch(var->type) { case M64TYPE_INT: return (var->val.integer != 0); case M64TYPE_FLOAT: return (var->val.number != 0.0); case M64TYPE_BOOL: return var->val.integer; case M64TYPE_STRING: return (osal_insensitive_strcmp(var->val.string, "true") == 0); default: DebugMessage(M64MSG_ERROR, "ConfigGetParamBool(): invalid internal parameter type for '%s'", ParamName); return 0; } } EXPORT const char * CALL ConfigGetParamString(m64p_handle ConfigSectionHandle, const char *ParamName) { static char outstr[64]; /* warning: not thread safe */ config_section *section; config_var *var; /* check input conditions */ if (!l_ConfigInit || ConfigSectionHandle == NULL || ParamName == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamString(): Input assertion!"); return ""; } section = (config_section *) ConfigSectionHandle; if (section->magic != SECTION_MAGIC) { DebugMessage(M64MSG_ERROR, "ConfigGetParamString(): ConfigSectionHandle invalid!"); return ""; } /* if this parameter doesn't already exist, return an error */ var = find_section_var(section, ParamName); if (var == NULL) { DebugMessage(M64MSG_ERROR, "ConfigGetParamString(): Parameter '%s' not found!", ParamName); return ""; } /* translate the actual variable type to a string */ switch(var->type) { case M64TYPE_INT: snprintf(outstr, 63, "%i", var->val.integer); outstr[63] = 0; return outstr; case M64TYPE_FLOAT: snprintf(outstr, 63, "%f", var->val.number); outstr[63] = 0; return outstr; case M64TYPE_BOOL: return (var->val.integer ? "True" : "False"); case M64TYPE_STRING: return var->val.string; default: DebugMessage(M64MSG_ERROR, "ConfigGetParamString(): invalid internal parameter type for '%s'", ParamName); return ""; } } EXPORT m64p_error CALL ConfigOverrideUserPaths(const char *DataPath, const char *CachePath) { /* make sure we're initialized */ if (!l_ConfigInit) return M64ERR_NOT_INIT; /* cleanup variables */ if (l_UserDataDirOverride != NULL) { free(l_UserDataDirOverride); l_UserDataDirOverride = NULL; } if (l_UserCacheDirOverride != NULL) { free(l_UserCacheDirOverride); l_UserCacheDirOverride = NULL; } /* if a data directory was specified, make a copy of it */ if (DataPath != NULL) { l_UserDataDirOverride = strdup(DataPath); if (l_UserDataDirOverride == NULL) return M64ERR_NO_MEMORY; } /* if a cache directory was specified, make a copy of it */ if (CachePath != NULL) { l_UserCacheDirOverride = strdup(CachePath); if (l_UserCacheDirOverride == NULL) return M64ERR_NO_MEMORY; } return M64ERR_SUCCESS; } /* ------------------------------------------------------ */ /* OS Abstraction functions, exported outside of the Core */ /* ------------------------------------------------------ */ EXPORT const char * CALL ConfigGetSharedDataFilepath(const char *filename) { const char *configsharepath = NULL; m64p_handle CoreHandle = NULL; /* check input parameter */ if (filename == NULL) return NULL; /* try to get the SharedDataPath string variable in the Core configuration section */ if (ConfigOpenSection("Core", &CoreHandle) == M64ERR_SUCCESS) { configsharepath = ConfigGetParamString(CoreHandle, "SharedDataPath"); } return osal_get_shared_filepath(filename, l_DataDirOverride, configsharepath); } EXPORT const char * CALL ConfigGetUserConfigPath(void) { if (l_ConfigDirOverride != NULL) { osal_mkdirp(l_ConfigDirOverride, 0700); return l_ConfigDirOverride; } else return osal_get_user_configpath(); } EXPORT const char * CALL ConfigGetUserDataPath(void) { if (l_UserDataDirOverride != NULL) { osal_mkdirp(l_UserDataDirOverride, 0700); return l_UserDataDirOverride; } else return osal_get_user_datapath(); } EXPORT const char * CALL ConfigGetUserCachePath(void) { if (l_UserCacheDirOverride != NULL) { osal_mkdirp(l_UserCacheDirOverride, 0700); return l_UserCacheDirOverride; } else return osal_get_user_cachepath(); } EXPORT m64p_error CALL ConfigSendNetplayConfig(char* data, int size) { return netplay_send_config(data, size); } EXPORT m64p_error CALL ConfigReceiveNetplayConfig(char* data, int size) { return netplay_receive_config(data, size); } mupen64plus-core-src-2.6.0/src/api/config.h000066400000000000000000000034521464506436200204300ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/config.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the Core configuration functions */ #include "m64p_types.h" /* these functions are only to be used within the Core library */ m64p_error ConfigInit(const char *ConfigDirOverride, const char *DataDirOverride); m64p_error ConfigShutdown(void); mupen64plus-core-src-2.6.0/src/api/debugger.c000066400000000000000000000337321464506436200207460ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/debugger.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the Core debugger functions which will be exported * outside of the core library. */ #include #define M64P_CORE_PROTOTYPES 1 #include "callbacks.h" #include "debugger.h" #include "debugger/dbg_breakpoints.h" #include "debugger/dbg_debugger.h" #include "debugger/dbg_decoder.h" #include "debugger/dbg_memory.h" #include "device/device.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/r4300/tlb.h" #include "m64p_debugger.h" #include "m64p_types.h" #include "main/main.h" unsigned int op; /* local variables */ static void (*callback_ui_init)(void) = NULL; static void (*callback_ui_update)(unsigned int) = NULL; static void (*callback_ui_vi)(void) = NULL; static void (*callback_core_compare)(unsigned int) = NULL; static void (*callback_core_data_sync)(int, void *) = NULL; /* global Functions for use by the Core */ int DebuggerCallbacksAreSet(void) { if (callback_ui_init != NULL && callback_ui_update != NULL && callback_ui_vi != NULL) return 1; else return 0; } void DebuggerCallback(eDbgCallbackType type, unsigned int param) { if (type == DEBUG_UI_INIT) { if (callback_ui_init != NULL) (*callback_ui_init)(); } else if (type == DEBUG_UI_UPDATE) { if (callback_ui_update != NULL) (*callback_ui_update)(param); } else if (type == DEBUG_UI_VI) { if (callback_ui_vi != NULL) (*callback_ui_vi)(); } } void CoreCompareCallback(void) { if (callback_core_compare != NULL) (*callback_core_compare)(op); } void CoreCompareDataSync(int length, void *ptr) { if (callback_core_data_sync != NULL) (*callback_core_data_sync)(length, ptr); } /* exported functions for use by the front-end User Interface */ EXPORT m64p_error CALL DebugSetCoreCompare(void (*dbg_core_compare)(unsigned int), void (*dbg_core_data_sync)(int, void *)) { callback_core_compare = dbg_core_compare; callback_core_data_sync = dbg_core_data_sync; return M64ERR_SUCCESS; } EXPORT m64p_error CALL DebugSetCallbacks(void (*dbg_frontend_init)(void), void (*dbg_frontend_update)(unsigned int pc), void (*dbg_frontend_vi)(void)) { #ifdef DBG callback_ui_init = dbg_frontend_init; callback_ui_update = dbg_frontend_update; callback_ui_vi = dbg_frontend_vi; return M64ERR_SUCCESS; #else return M64ERR_UNSUPPORTED; #endif } EXPORT m64p_error CALL DebugSetRunState(m64p_dbg_runstate runstate) { #ifdef DBG g_dbg_runstate = runstate; /* in debugger/debugger.c */ if (runstate == M64P_DBG_RUNSTATE_RUNNING) { /* clear out last breakpoint state when resuming */ breakpointFlag = 0; breakpointAccessed = 0; } return M64ERR_SUCCESS; #else return M64ERR_UNSUPPORTED; #endif } EXPORT int CALL DebugGetState(m64p_dbg_state statenum) { #ifdef DBG switch (statenum) { case M64P_DBG_RUN_STATE: return g_dbg_runstate; case M64P_DBG_PREVIOUS_PC: return previousPC; case M64P_DBG_NUM_BREAKPOINTS: return g_NumBreakpoints; case M64P_DBG_CPU_DYNACORE: return get_r4300_emumode(&g_dev.r4300); case M64P_DBG_CPU_NEXT_INTERRUPT: return *r4300_cp0_next_interrupt(&g_dev.r4300.cp0); default: DebugMessage(M64MSG_WARNING, "Bug: invalid m64p_dbg_state input in DebugGetState()"); return 0; } return 0; #else DebugMessage(M64MSG_ERROR, "Bug: DebugGetState() called, but Debugger not supported in Core library"); return 0; #endif } EXPORT m64p_error CALL DebugStep(void) { #ifdef DBG if (!g_DebuggerActive) return M64ERR_INVALID_STATE; debugger_step(); /* in debugger/debugger.c */ return M64ERR_SUCCESS; #else return M64ERR_UNSUPPORTED; #endif } EXPORT void CALL DebugDecodeOp(unsigned int instruction, char *op, char *args, int pc) { #ifdef DBG r4300_decode_op(instruction, op, args, pc); #else DebugMessage(M64MSG_ERROR, "Bug: DebugDecodeOp() called, but Debugger not supported in Core library"); #endif } EXPORT void * CALL DebugMemGetRecompInfo(m64p_dbg_mem_info recomp_type, unsigned int address, int index) { #ifdef DBG struct r4300_core* r4300 = &g_dev.r4300; switch (recomp_type) { case M64P_DBG_RECOMP_OPCODE: return get_recompiled_opcode(r4300, address, index); case M64P_DBG_RECOMP_ARGS: return get_recompiled_args(r4300, address, index); case M64P_DBG_RECOMP_ADDR: return get_recompiled_addr(r4300, address, index); default: DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetRecompInfo() called with invalid m64p_dbg_mem_info"); return NULL; } #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetRecompInfo() called, but Debugger not supported in Core library"); return NULL; #endif } EXPORT int CALL DebugMemGetMemInfo(m64p_dbg_mem_info mem_info_type, unsigned int address) { #ifdef DBG struct device* dev = &g_dev; struct r4300_core* r4300 = &dev->r4300; switch (mem_info_type) { case M64P_DBG_MEM_TYPE: return get_memory_type(&dev->mem, address); case M64P_DBG_MEM_FLAGS: return get_memory_flags(dev, address); case M64P_DBG_MEM_HAS_RECOMPILED: return get_has_recompiled(r4300, address); case M64P_DBG_MEM_NUM_RECOMPILED: return get_num_recompiled(r4300, address); default: DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetMemInfo() called with invalid m64p_dbg_mem_info"); return 0; } #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetMemInfo() called, but Debugger not supported in Core library"); return 0; #endif } EXPORT void * CALL DebugMemGetPointer(m64p_dbg_memptr_type mem_ptr_type) { switch (mem_ptr_type) { case M64P_DBG_PTR_RDRAM: return g_dev.rdram.dram; case M64P_DBG_PTR_PI_REG: return g_dev.pi.regs; case M64P_DBG_PTR_SI_REG: return g_dev.si.regs; case M64P_DBG_PTR_VI_REG: return g_dev.vi.regs; case M64P_DBG_PTR_RI_REG: return g_dev.ri.regs; case M64P_DBG_PTR_AI_REG: return g_dev.ai.regs; default: DebugMessage(M64MSG_ERROR, "Bug: DebugMemGetPointer() called with invalid m64p_dbg_memptr_type"); return NULL; } } EXPORT unsigned long long CALL DebugMemRead64(unsigned int address) { #ifdef DBG struct device* dev = &g_dev; if ((address & 3) == 0) return read_memory_64(dev, address); else return read_memory_64_unaligned(dev, address); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead64() called, but Debugger not supported in Core library"); return 0LL; #endif } EXPORT unsigned int CALL DebugMemRead32(unsigned int address) { #ifdef DBG struct device* dev = &g_dev; if ((address & 3) == 0) return read_memory_32(dev, address); else return read_memory_32_unaligned(dev, address); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead32() called, but Debugger not supported in Core library"); return 0; #endif } EXPORT unsigned short CALL DebugMemRead16(unsigned int address) { #ifdef DBG struct device* dev = &g_dev; return read_memory_16(dev, address); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead16() called, but Debugger not supported in Core library"); return 0; #endif } EXPORT unsigned char CALL DebugMemRead8(unsigned int address) { #ifdef DBG struct device* dev = &g_dev; return read_memory_8(dev, address); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemRead8() called, but Debugger not supported in Core library"); return 0; #endif } EXPORT void CALL DebugMemWrite64(unsigned int address, unsigned long long value) { #ifdef DBG struct device* dev = &g_dev; if ((address & 3) == 0) write_memory_64(dev, address, value); else write_memory_64_unaligned(dev, address, value); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite64() called, but Debugger not supported in Core library"); #endif } EXPORT void CALL DebugMemWrite32(unsigned int address, unsigned int value) { #ifdef DBG struct device* dev = &g_dev; if ((address & 3) == 0) write_memory_32(dev, address, value); else write_memory_32_unaligned(dev, address, value); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite32() called, but Debugger not supported in Core library"); #endif } EXPORT void CALL DebugMemWrite16(unsigned int address, unsigned short value) { #ifdef DBG struct device* dev = &g_dev; write_memory_16(dev, address, value); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite16() called, but Debugger not supported in Core library"); #endif } EXPORT void CALL DebugMemWrite8(unsigned int address, unsigned char value) { #ifdef DBG struct device* dev = &g_dev; write_memory_8(dev, address, value); #else DebugMessage(M64MSG_ERROR, "Bug: DebugMemWrite8() called, but Debugger not supported in Core library"); #endif } EXPORT void * CALL DebugGetCPUDataPtr(m64p_dbg_cpu_data cpu_data_type) { struct device* dev = &g_dev; struct r4300_core* r4300 = &dev->r4300; cp1_reg *cp1_regs = r4300_cp1_regs(&r4300->cp1); switch (cpu_data_type) { case M64P_CPU_PC: return r4300_pc(r4300); case M64P_CPU_REG_REG: return r4300_regs(r4300); case M64P_CPU_REG_HI: return r4300_mult_hi(r4300); case M64P_CPU_REG_LO: return r4300_mult_lo(r4300); case M64P_CPU_REG_COP0: return r4300_cp0_regs(&r4300->cp0); case M64P_CPU_REG_COP1_DOUBLE_PTR: return r4300_cp1_regs_double(&r4300->cp1); case M64P_CPU_REG_COP1_SIMPLE_PTR: return r4300_cp1_regs_simple(&r4300->cp1); case M64P_CPU_REG_COP1_FGR_64: return &cp1_regs->dword; case M64P_CPU_TLB: return r4300->cp0.tlb.entries; default: DebugMessage(M64MSG_ERROR, "Bug: DebugGetCPUDataPtr() called with invalid input m64p_dbg_cpu_data"); return NULL; } } EXPORT int CALL DebugBreakpointLookup(unsigned int address, unsigned int size, unsigned int flags) { #ifdef DBG return lookup_breakpoint(address, size, flags); #else DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointLookup() called, but Debugger not supported in Core library"); return -1; #endif } EXPORT int CALL DebugBreakpointCommand(m64p_dbg_bkp_command command, unsigned int index, m64p_breakpoint *bkp) { #ifdef DBG struct memory* mem = &g_dev.mem; switch (command) { case M64P_BKP_CMD_ADD_ADDR: return add_breakpoint(mem, index); case M64P_BKP_CMD_ADD_STRUCT: return add_breakpoint_struct(mem, bkp); case M64P_BKP_CMD_REPLACE: replace_breakpoint_num(mem, index, bkp); return 0; case M64P_BKP_CMD_REMOVE_ADDR: remove_breakpoint_by_address(mem, index); return 0; case M64P_BKP_CMD_REMOVE_IDX: remove_breakpoint_by_num(mem, index); return 0; case M64P_BKP_CMD_ENABLE: enable_breakpoint(mem, index); return 0; case M64P_BKP_CMD_DISABLE: disable_breakpoint(mem, index); return 0; case M64P_BKP_CMD_CHECK: return check_breakpoints(index); default: DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointCommand() called with invalid input m64p_dbg_bkp_command"); return -1; } #else DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointCommand() called, but Debugger not supported in Core library"); return -1; #endif } EXPORT void CALL DebugBreakpointTriggeredBy(uint32_t *flags, uint32_t *accessed) { #ifdef DBG *flags = breakpointFlag; *accessed = breakpointAccessed; #else DebugMessage(M64MSG_ERROR, "Bug: DebugBreakpointTriggeredBy() called, but Debugger not supported in Core library"); #endif } EXPORT uint32_t CALL DebugVirtualToPhysical(uint32_t address) { #ifdef DBG struct device* dev = &g_dev; struct r4300_core* r4300 = &dev->r4300; if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) { address = virtual_to_physical_address(r4300, address, 0); if (address == 0) { return 0; } } address &= UINT32_C(0x1fffffff); return address; #else DebugMessage(M64MSG_ERROR, "Bug: DebugVirtualToPhysical() called, but Debugger not supported in Core library"); return address; #endif } mupen64plus-core-src-2.6.0/src/api/debugger.h000066400000000000000000000042431464506436200207460ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/debugger.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for debugger functions which will be * called from the other Core modules */ #if !defined(API_DEBUGGER_H) #define API_DEBUGGER_H #include "m64p_types.h" /* Debugger Definitions */ typedef enum { DEBUG_UI_INIT = 1, DEBUG_UI_UPDATE, DEBUG_UI_VI, DEBUG_CORE_COMPARE } eDbgCallbackType; /* Functions for use by the Core, to send information back to the front-end app */ extern int DebuggerCallbacksAreSet(void); extern void DebuggerCallback(eDbgCallbackType type, unsigned int param); extern void CoreCompareCallback(void); extern void CoreCompareDataSync(int length, void *ptr); #endif /* API_DEBUGGER_H */ mupen64plus-core-src-2.6.0/src/api/frontend.c000066400000000000000000000416371464506436200210040ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/frontend.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 CasualJames * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the Core front-end functions which will be exported * outside of the core library. */ #include #include #include #include #include #define M64P_CORE_PROTOTYPES 1 #include "callbacks.h" #include "config.h" #include "m64p_config.h" #include "m64p_frontend.h" #include "m64p_types.h" #include "main/cheat.h" #include "main/eventloop.h" #include "main/main.h" #include "main/rom.h" #include "main/savestates.h" #include "main/util.h" #include "main/version.h" #include "main/workqueue.h" #include "main/screenshot.h" #include "main/netplay.h" #include "plugin/plugin.h" #include "vidext.h" /* some local state variables */ static int l_CoreInit = 0; static int l_ROMOpen = 0; static int l_DiskOpen = 0; static int l_CallerUsingSDL = 0; /* functions exported outside of libmupen64plus to front-end application */ EXPORT m64p_error CALL CoreStartup(int APIVersion, const char *ConfigPath, const char *DataPath, void *Context, void (*DebugCallback)(void *, int, const char *), void *Context2, void (*StateCallback)(void *, m64p_core_param, int)) { if (l_CoreInit) return M64ERR_ALREADY_INIT; /* check wether the caller has already initialized SDL */ l_CallerUsingSDL = (SDL_WasInit(0) != 0); /* very first thing is to set the callback functions for debug info and state changing*/ SetDebugCallback(DebugCallback, Context); SetStateCallback(StateCallback, Context2); /* check front-end's API version */ if ((APIVersion & 0xffff0000) != (FRONTEND_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "CoreStartup(): Front-end (API version %i.%i.%i) is incompatible with this core (API %i.%i.%i)", VERSION_PRINTF_SPLIT(APIVersion), VERSION_PRINTF_SPLIT(FRONTEND_API_VERSION)); return M64ERR_INCOMPATIBLE; } /* set up the default (dummy) plugins */ plugin_connect(M64PLUGIN_GFX, NULL); plugin_connect(M64PLUGIN_AUDIO, NULL); plugin_connect(M64PLUGIN_INPUT, NULL); plugin_connect(M64PLUGIN_CORE, NULL); savestates_init(); /* next, start up the configuration handling code by loading and parsing the config file */ if (ConfigInit(ConfigPath, DataPath) != M64ERR_SUCCESS) return M64ERR_INTERNAL; /* set default configuration parameter values for Core */ if (ConfigOpenSection("Core", &g_CoreConfig) != M64ERR_SUCCESS || g_CoreConfig == NULL) return M64ERR_INTERNAL; if (!main_set_core_defaults()) return M64ERR_INTERNAL; /* allocate base memory */ g_mem_base = init_mem_base(); if (g_mem_base == NULL) { return M64ERR_NO_MEMORY; } /* The ROM database contains MD5 hashes, goodnames, and some game-specific parameters */ romdatabase_open(); workqueue_init(); l_CoreInit = 1; return M64ERR_SUCCESS; } EXPORT m64p_error CALL CoreShutdown(void) { if (!l_CoreInit) return M64ERR_NOT_INIT; /* close down some core sub-systems */ romdatabase_close(); ConfigShutdown(); workqueue_shutdown(); savestates_deinit(); /* if the calling code is using SDL, don't shut it down */ if (!l_CallerUsingSDL) SDL_Quit(); /* deallocate base memory */ release_mem_base(g_mem_base); g_mem_base = NULL; l_CoreInit = 0; return M64ERR_SUCCESS; } EXPORT m64p_error CALL CoreAttachPlugin(m64p_plugin_type PluginType, m64p_dynlib_handle PluginLibHandle) { m64p_error rval; if (!l_CoreInit) return M64ERR_NOT_INIT; if (g_EmulatorRunning || (!l_ROMOpen && !l_DiskOpen)) return M64ERR_INVALID_STATE; rval = plugin_connect(PluginType, PluginLibHandle); if (rval != M64ERR_SUCCESS) return rval; rval = plugin_start(PluginType); if (rval != M64ERR_SUCCESS) return rval; return M64ERR_SUCCESS; } EXPORT m64p_error CALL CoreDetachPlugin(m64p_plugin_type PluginType) { if (!l_CoreInit) return M64ERR_NOT_INIT; if (g_EmulatorRunning) return M64ERR_INVALID_STATE; return plugin_connect(PluginType, NULL); } EXPORT m64p_error CALL CoreDoCommand(m64p_command Command, int ParamInt, void *ParamPtr) { m64p_error rval; int keysym, keymod; if (!l_CoreInit) return M64ERR_NOT_INIT; switch(Command) { case M64CMD_NOP: return M64ERR_SUCCESS; case M64CMD_ROM_OPEN: if (g_EmulatorRunning || l_DiskOpen || l_ROMOpen) return M64ERR_INVALID_STATE; // ROM buffer size must be divisible by 4 to avoid out-of-bounds read in swap_copy_rom (v64/n64 formats) if (ParamPtr == NULL || ParamInt < 4096 || ParamInt > CART_ROM_MAX_SIZE) return M64ERR_INPUT_ASSERT; rval = open_rom((const unsigned char *) ParamPtr, ParamInt); if (rval == M64ERR_SUCCESS) { l_ROMOpen = 1; ScreenshotRomOpen(); cheat_init(&g_cheat_ctx); } return rval; case M64CMD_ROM_CLOSE: if (g_EmulatorRunning || !l_ROMOpen) return M64ERR_INVALID_STATE; l_ROMOpen = 0; cheat_delete_all(&g_cheat_ctx); cheat_uninit(&g_cheat_ctx); return close_rom(); case M64CMD_DISK_OPEN: if (g_EmulatorRunning || l_DiskOpen || l_ROMOpen) return M64ERR_INVALID_STATE; if (ParamPtr != NULL) return M64ERR_INPUT_INVALID; rval = open_disk(); if (rval == M64ERR_SUCCESS) { l_DiskOpen = 1; ScreenshotRomOpen(); cheat_init(&g_cheat_ctx); } return rval; case M64CMD_DISK_CLOSE: if (g_EmulatorRunning || !l_DiskOpen) return M64ERR_INVALID_STATE; l_DiskOpen = 0; cheat_delete_all(&g_cheat_ctx); cheat_uninit(&g_cheat_ctx); return close_disk(); case M64CMD_PIF_OPEN: if (g_EmulatorRunning) return M64ERR_INVALID_STATE; if (ParamPtr == NULL || ParamInt < 1984 || ParamInt > 2048 || ParamInt % 4 != 0) return M64ERR_INPUT_ASSERT; return open_pif((const unsigned char *) ParamPtr, ParamInt); case M64CMD_ROM_GET_HEADER: if (!l_ROMOpen && !l_DiskOpen) return M64ERR_INVALID_STATE; if (ParamPtr == NULL) return M64ERR_INPUT_ASSERT; if ((int)sizeof(m64p_rom_header) < ParamInt) ParamInt = sizeof(m64p_rom_header); memcpy(ParamPtr, &ROM_HEADER, ParamInt); // Mupen64Plus used to keep a m64p_rom_header with a clean ROM name // Keep returning a clean ROM name for backwards compatibility if (ParamInt >= 0x20) { int size = (ParamInt >= 0x20 + 20) ? 20 : (ParamInt - 0x20); memcpy((char *)ParamPtr + 0x20, ROM_PARAMS.headername, size); } return M64ERR_SUCCESS; case M64CMD_ROM_GET_SETTINGS: if (!l_ROMOpen && !l_DiskOpen) return M64ERR_INVALID_STATE; if (ParamPtr == NULL) return M64ERR_INPUT_ASSERT; if ((int)sizeof(m64p_rom_settings) < ParamInt) ParamInt = sizeof(m64p_rom_settings); memcpy(ParamPtr, &ROM_SETTINGS, ParamInt); return M64ERR_SUCCESS; case M64CMD_ROM_SET_SETTINGS: if (g_EmulatorRunning || (!l_ROMOpen && !l_DiskOpen)) return M64ERR_INVALID_STATE; if (ParamPtr == NULL) return M64ERR_INPUT_ASSERT; if ((int)sizeof(m64p_rom_settings) < ParamInt) ParamInt = sizeof(m64p_rom_settings); memcpy(&ROM_SETTINGS, ParamPtr, ParamInt); return M64ERR_SUCCESS; case M64CMD_EXECUTE: if (g_EmulatorRunning || (!l_ROMOpen && !l_DiskOpen)) return M64ERR_INVALID_STATE; /* print out plugin-related warning messages */ plugin_check(); /* the main_run() function will not return until the player has quit the game */ rval = main_run(); return rval; case M64CMD_STOP: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; /* this stop function is asynchronous. The emulator may not terminate until later */ return main_core_state_set(M64CORE_EMU_STATE, M64EMU_STOPPED); case M64CMD_PAUSE: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; return main_core_state_set(M64CORE_EMU_STATE, M64EMU_PAUSED); case M64CMD_RESUME: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; return main_core_state_set(M64CORE_EMU_STATE, M64EMU_RUNNING); case M64CMD_CORE_STATE_QUERY: if (ParamPtr == NULL) return M64ERR_INPUT_ASSERT; return main_core_state_query((m64p_core_param) ParamInt, (int *) ParamPtr); case M64CMD_CORE_STATE_SET: if (ParamPtr == NULL) return M64ERR_INPUT_ASSERT; return main_core_state_set((m64p_core_param) ParamInt, *((int *)ParamPtr)); case M64CMD_STATE_LOAD: main_state_load((char *) ParamPtr); return M64ERR_SUCCESS; case M64CMD_STATE_SAVE: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; if (ParamPtr != NULL && (ParamInt < 1 || ParamInt > 3)) return M64ERR_INPUT_INVALID; main_state_save(ParamInt, (char *) ParamPtr); return M64ERR_SUCCESS; case M64CMD_STATE_SET_SLOT: if (ParamInt < 0 || ParamInt > 9) return M64ERR_INPUT_INVALID; return main_core_state_set(M64CORE_SAVESTATE_SLOT, ParamInt); case M64CMD_SEND_SDL_KEYDOWN: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; keysym = ParamInt & 0xffff; keymod = (ParamInt >> 16) & 0xffff; event_sdl_keydown(keysym, keymod); return M64ERR_SUCCESS; case M64CMD_SEND_SDL_KEYUP: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; keysym = ParamInt & 0xffff; keymod = (ParamInt >> 16) & 0xffff; event_sdl_keyup(keysym, keymod); return M64ERR_SUCCESS; case M64CMD_SET_FRAME_CALLBACK: *(void**)&g_FrameCallback = ParamPtr; return M64ERR_SUCCESS; case M64CMD_TAKE_NEXT_SCREENSHOT: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; main_take_next_screenshot(); return M64ERR_SUCCESS; case M64CMD_READ_SCREEN: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; if (ParamPtr == NULL) return M64ERR_INPUT_ASSERT; if (ParamInt < 0 || ParamInt > 1) return M64ERR_INPUT_INVALID; return main_read_screen(ParamPtr, ParamInt); case M64CMD_RESET: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; if (ParamInt < 0 || ParamInt > 1) return M64ERR_INPUT_INVALID; return main_reset(ParamInt); case M64CMD_ADVANCE_FRAME: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; main_advance_one(); return M64ERR_SUCCESS; case M64CMD_SET_MEDIA_LOADER: if (ParamInt != sizeof(m64p_media_loader) || ParamPtr == NULL) return M64ERR_INPUT_INVALID; g_media_loader = *(m64p_media_loader*)ParamPtr; return M64ERR_SUCCESS; case M64CMD_NETPLAY_INIT: if (ParamInt < 1 || ParamPtr == NULL) return M64ERR_INPUT_INVALID; return netplay_start(ParamPtr, ParamInt); case M64CMD_NETPLAY_CONTROL_PLAYER: if (ParamInt < 1 || ParamInt > 4 || ParamPtr == NULL) return M64ERR_INPUT_INVALID; if (netplay_register_player(ParamInt - 1, Controls[netplay_next_controller()].Plugin, Controls[netplay_next_controller()].RawData, *(uint32_t*)ParamPtr)) { netplay_set_controller(ParamInt - 1); return M64ERR_SUCCESS; } else return M64ERR_INPUT_ASSERT; // player already in use case M64CMD_NETPLAY_GET_VERSION: if (ParamPtr == NULL) return M64ERR_INPUT_INVALID; *(uint32_t*)ParamPtr = NETPLAY_CORE_VERSION; if (ParamInt == NETPLAY_API_VERSION) return M64ERR_SUCCESS; else return M64ERR_INCOMPATIBLE; case M64CMD_NETPLAY_CLOSE: return netplay_stop(); default: return M64ERR_INPUT_INVALID; } return M64ERR_INTERNAL; } EXPORT m64p_error CALL CoreOverrideVidExt(m64p_video_extension_functions *VideoFunctionStruct) { if (!l_CoreInit) return M64ERR_NOT_INIT; return OverrideVideoFunctions(VideoFunctionStruct); /* in vidext.c */ } EXPORT m64p_error CALL CoreAddCheat(const char *CheatName, m64p_cheat_code *CodeList, int NumCodes) { if (!l_CoreInit) return M64ERR_NOT_INIT; if (netplay_is_init()) return M64ERR_INVALID_STATE; if (CheatName == NULL || CodeList == NULL) return M64ERR_INPUT_ASSERT; if (strlen(CheatName) < 1 || NumCodes < 1) return M64ERR_INPUT_INVALID; if (cheat_add_new(&g_cheat_ctx, CheatName, CodeList, NumCodes)) return M64ERR_SUCCESS; return M64ERR_INPUT_INVALID; } EXPORT m64p_error CALL CoreCheatEnabled(const char *CheatName, int Enabled) { if (!l_CoreInit) return M64ERR_NOT_INIT; if (netplay_is_init()) return M64ERR_INVALID_STATE; if (CheatName == NULL) return M64ERR_INPUT_ASSERT; if (cheat_set_enabled(&g_cheat_ctx, CheatName, Enabled)) return M64ERR_SUCCESS; return M64ERR_INPUT_INVALID; } EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *RomSettings, int RomSettingsLength, int Crc1, int Crc2) { romdatabase_entry* entry; int i; if (!l_CoreInit) return M64ERR_NOT_INIT; if (RomSettings == NULL) return M64ERR_INPUT_ASSERT; if (RomSettingsLength < (int)sizeof(m64p_rom_settings)) return M64ERR_INPUT_INVALID; /* Look up this ROM in the .ini file and fill in goodname, etc */ entry = ini_search_by_crc(Crc1, Crc2); if (entry == NULL) return M64ERR_INPUT_NOT_FOUND; strncpy(RomSettings->goodname, entry->goodname, 255); RomSettings->goodname[255] = '\0'; for (i = 0; i < 16; i++) sprintf(RomSettings->MD5 + i*2, "%02X", entry->md5[i]); RomSettings->MD5[32] = '\0'; RomSettings->savetype = entry->savetype; RomSettings->status = entry->status; RomSettings->players = entry->players; RomSettings->rumble = entry->rumble; RomSettings->transferpak = entry->transferpak; RomSettings->mempak = entry->mempak; RomSettings->disableextramem = entry->disableextramem; RomSettings->countperop = entry->countperop; RomSettings->savetype = entry->savetype; RomSettings->sidmaduration = entry->sidmaduration; RomSettings->aidmamodifier = entry->aidmamodifier; return M64ERR_SUCCESS; } mupen64plus-core-src-2.6.0/src/api/m64p_common.h000066400000000000000000000071201464506436200213150ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - m64p_common.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file defines typedefs for function pointers to common Core * and plugin functions, for use by the front-end and plugin modules to attach * to the dynamic libraries. */ #if !defined(M64P_COMMON_H) #define M64P_COMMON_H #include "m64p_types.h" #ifdef __cplusplus extern "C" { #endif /* PluginGetVersion() * * This function retrieves version information from a library. This * function is the same for the core library and the plugins. */ typedef m64p_error (*ptr_PluginGetVersion)(m64p_plugin_type *, int *, int *, const char **, int *); #if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *, int *, int *, const char **, int *); #endif /* CoreGetAPIVersions() * * This function retrieves API version information from the core. */ typedef m64p_error (*ptr_CoreGetAPIVersions)(int *, int *, int *, int *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreGetAPIVersions(int *, int *, int *, int *); #endif /* CoreErrorMessage() * * This function returns a pointer to a NULL-terminated string giving a * human-readable description of the error. */ typedef const char * (*ptr_CoreErrorMessage)(m64p_error); #if defined(M64P_CORE_PROTOTYPES) EXPORT const char * CALL CoreErrorMessage(m64p_error); #endif /* PluginStartup() * * This function initializes a plugin for use by allocating memory, creating * data structures, and loading the configuration data. */ typedef m64p_error (*ptr_PluginStartup)(m64p_dynlib_handle, void *, void (*)(void *, int, const char *)); #if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle, void *, void (*)(void *, int, const char *)); #endif /* PluginShutdown() * * This function destroys data structures and releases memory allocated by * the plugin library. */ typedef m64p_error (*ptr_PluginShutdown)(void); #if defined(M64P_PLUGIN_PROTOTYPES) || defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL PluginShutdown(void); #endif #ifdef __cplusplus } #endif #endif /* #define M64P_COMMON_H */ mupen64plus-core-src-2.6.0/src/api/m64p_config.h000066400000000000000000000305411464506436200212750ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - m64p_config.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file defines typedefs for function pointers to the Core's * configuration handling functions. */ #if !defined(M64P_CONFIG_H) #define M64P_CONFIG_H #include "m64p_types.h" #ifdef __cplusplus extern "C" { #endif /* ConfigListSections() * * This function is called to enumerate the list of Sections in the Mupen64Plus * configuration file. It is expected that there will be a section named "Core" * for core-specific configuration data, "Graphics" for common graphics options, * and one or more sections for each plugin library. */ typedef m64p_error (*ptr_ConfigListSections)(void *, void (*)(void *, const char *)); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigListSections(void *, void (*)(void *, const char *)); #endif /* ConfigOpenSection() * * This function is used to give a configuration section handle to the front-end * which may be used to read or write configuration parameter values in a given * section of the configuration file. */ typedef m64p_error (*ptr_ConfigOpenSection)(const char *, m64p_handle *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigOpenSection(const char *, m64p_handle *); #endif /* ConfigListParameters() * * This function is called to enumerate the list of Parameters in a given * Section of the Mupen64Plus configuration file. */ typedef m64p_error (*ptr_ConfigListParameters)(m64p_handle, void *, void (*)(void *, const char *, m64p_type)); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigListParameters(m64p_handle, void *, void (*)(void *, const char *, m64p_type)); #endif /* ConfigSaveFile() * * This function saves the entire current Mupen64Plus configuration to disk. */ typedef m64p_error (*ptr_ConfigSaveFile)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigSaveFile(void); #endif /* ConfigSaveSection() * * This function saves one section of the current Mupen64Plus configuration to disk. */ typedef m64p_error (*ptr_ConfigSaveSection)(const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigSaveSection(const char *); #endif /* ConfigHasUnsavedChanges() * * This function determines if a given Section (or all sections) of the Mupen64Plus Core configuration file has been modified since it was last saved or loaded. */ typedef int (*ptr_ConfigHasUnsavedChanges)(const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT int CALL ConfigHasUnsavedChanges(const char *); #endif /* ConfigDeleteSection() * * This function deletes a section from the Mupen64Plus configuration data. */ typedef m64p_error (*ptr_ConfigDeleteSection)(const char *SectionName); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigDeleteSection(const char *SectionName); #endif /* ConfigRevertChanges() * * This function reverts changes previously made to one section of the configuration file, so that it will match with the configuration at the last time that it was loaded from or saved to disk. */ typedef m64p_error (*ptr_ConfigRevertChanges)(const char *SectionName); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigRevertChanges(const char *SectionName); #endif /* ConfigSetParameter() * * This function sets the value of one of the emulator's configuration * parameters. */ typedef m64p_error (*ptr_ConfigSetParameter)(m64p_handle, const char *, m64p_type, const void *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigSetParameter(m64p_handle, const char *, m64p_type, const void *); #endif /* ConfigSetParameterHelp() * * This function sets the help string of one of the emulator's configuration * parameters. */ typedef m64p_error (*ptr_ConfigSetParameterHelp)(m64p_handle, const char *, const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigSetParameterHelp(m64p_handle, const char *, const char *); #endif /* ConfigGetParameter() * * This function retrieves the value of one of the emulator's parameters. */ typedef m64p_error (*ptr_ConfigGetParameter)(m64p_handle, const char *, m64p_type, void *, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigGetParameter(m64p_handle, const char *, m64p_type, void *, int); #endif /* ConfigGetParameterType() * * This function retrieves the type of one of the emulator's parameters. */ typedef m64p_error (*ptr_ConfigGetParameterType)(m64p_handle, const char *, m64p_type *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigGetParameterType(m64p_handle, const char *, m64p_type *); #endif /* ConfigGetParameterHelp() * * This function retrieves the help information about one of the emulator's * parameters. */ typedef const char * (*ptr_ConfigGetParameterHelp)(m64p_handle, const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT const char * CALL ConfigGetParameterHelp(m64p_handle, const char *); #endif /* ConfigSetDefault***() * * These functions are used to set the value of a configuration parameter if it * is not already present in the configuration file. This may happen if a new * user runs the emulator, or an upgraded module uses a new parameter, or the * user deletes his or her configuration file. If the parameter is already * present in the given section of the configuration file, then no action will * be taken and this function will return successfully. */ typedef m64p_error (*ptr_ConfigSetDefaultInt)(m64p_handle, const char *, int, const char *); typedef m64p_error (*ptr_ConfigSetDefaultFloat)(m64p_handle, const char *, float, const char *); typedef m64p_error (*ptr_ConfigSetDefaultBool)(m64p_handle, const char *, int, const char *); typedef m64p_error (*ptr_ConfigSetDefaultString)(m64p_handle, const char *, const char *, const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigSetDefaultInt(m64p_handle, const char *, int, const char *); EXPORT m64p_error CALL ConfigSetDefaultFloat(m64p_handle, const char *, float, const char *); EXPORT m64p_error CALL ConfigSetDefaultBool(m64p_handle, const char *, int, const char *); EXPORT m64p_error CALL ConfigSetDefaultString(m64p_handle, const char *, const char *, const char *); #endif /* ConfigGetParam***() * * These functions retrieve the value of one of the emulator's parameters in * the given section, and return the value directly to the calling function. If * an errors occurs (such as an invalid Section handle, or invalid * configuration parameter name), then an error will be sent to the front-end * via the DebugCallback() function, and either a 0 (zero) or an empty string * will be returned. */ typedef int (*ptr_ConfigGetParamInt)(m64p_handle, const char *); typedef float (*ptr_ConfigGetParamFloat)(m64p_handle, const char *); typedef int (*ptr_ConfigGetParamBool)(m64p_handle, const char *); typedef const char * (*ptr_ConfigGetParamString)(m64p_handle, const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT int CALL ConfigGetParamInt(m64p_handle, const char *); EXPORT float CALL ConfigGetParamFloat(m64p_handle, const char *); EXPORT int CALL ConfigGetParamBool(m64p_handle, const char *); EXPORT const char * CALL ConfigGetParamString(m64p_handle, const char *); #endif /* ConfigGetSharedDataFilepath() * * This function is provided to allow a plugin to retrieve a full pathname to a * given shared data file. This type of file is intended to be shared among * multiple users on a system, so it is likely to be read-only. */ typedef const char * (*ptr_ConfigGetSharedDataFilepath)(const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT const char * CALL ConfigGetSharedDataFilepath(const char *); #endif /* ConfigGetUserConfigPath() * * This function may be used by the plugins or front-end to get a path to the * directory for storing user-specific configuration files. This will be the * directory where "mupen64plus.cfg" is located. */ typedef const char * (*ptr_ConfigGetUserConfigPath)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT const char * CALL ConfigGetUserConfigPath(void); #endif /* ConfigGetUserDataPath() * * This function may be used by the plugins or front-end to get a path to the * directory for storing user-specific data files. This may be used to store * files such as screenshots, saved game states, or hi-res textures. */ typedef const char * (*ptr_ConfigGetUserDataPath)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT const char * CALL ConfigGetUserDataPath(void); #endif /* ConfigGetUserCachePath() * * This function may be used by the plugins or front-end to get a path to the * directory for storing cached user-specific data files. Files in this * directory may be deleted by the user to save space, so critical information * should not be stored here. This directory may be used to store files such * as the ROM browser cache. */ typedef const char * (*ptr_ConfigGetUserCachePath)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT const char * CALL ConfigGetUserCachePath(void); #endif /* ConfigExternalOpen() * * This function reads the contents of the config file into memory * and returns M64ERR_SUCCESS if successful. */ typedef m64p_error (*ptr_ConfigExternalOpen)(const char *, m64p_handle *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigExternalOpen(const char *, m64p_handle *); #endif /* ConfigExternalClose() * * Frees the memory pointer created by ConfigExternalOpen. */ typedef m64p_error (*ptr_ConfigExternalClose)(m64p_handle); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigExternalClose(m64p_handle); #endif /* ConfigExternalGetParameter() * * This functions allows a plugin to leverage the built-in ini parser to read * any cfg/ini file. It will return M64ERR_SUCCESS if the item was found. */ typedef m64p_error (*ptr_ConfigExternalGetParameter)(m64p_handle, const char *, const char *, char *, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigExternalGetParameter(m64p_handle, const char *, const char *, char *, int); #endif /* ConfigSendNetplayConfig() * * This function allows plugins to take advantage of the netplay TCP connection * to send configuration data to the netplay server. */ typedef m64p_error (*ptr_ConfigSendNetplayConfig)(char*, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigSendNetplayConfig(char*, int); #endif /* ConfigReceiveNetplayConfig() * * This function allows plugins to take advantage of the netplay TCP connection * to receive configuration data from the netplay server. */ typedef m64p_error (*ptr_ConfigReceiveNetplayConfig)(char*, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigReceiveNetplayConfig(char*, int); #endif /* ConfigOverrideUserPaths() * * This function allows overriding the paths returned by * ConfigGetUserDataPath and ConfigGetUserCachePath */ typedef m64p_error (*ptr_ConfigOverrideUserPaths)(const char*, const char*); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL ConfigOverrideUserPaths(const char*, const char*); #endif #ifdef __cplusplus } #endif #endif /* #define M64P_CONFIG_H */ mupen64plus-core-src-2.6.0/src/api/m64p_debugger.h000066400000000000000000000210161464506436200216110ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - m64p_debugger.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file defines typedefs for function pointers to Core Debugger * functions. */ #if !defined(M64P_DEBUGGER_H) #define M64P_DEBUGGER_H #include "m64p_types.h" #ifdef __cplusplus extern "C" { #endif /* DebugSetCallbacks() * * This function is called by the front-end to supply debugger callback * function pointers. If debugger is enabled and then later disabled within the * UI, this function may be called with NULL pointers in order to disable the * callbacks. */ typedef m64p_error (*ptr_DebugSetCallbacks)(void (*)(void), void (*)(unsigned int), void (*)(void)); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL DebugSetCallbacks(void (*)(void), void (*)(unsigned int), void (*)(void)); #endif /* DebugSetCoreCompare() * * This function is called by the front-end to supply callback function pointers * for the Core Comparison feature. */ typedef m64p_error (*ptr_DebugSetCoreCompare)(void (*)(unsigned int), void (*)(int, void *)); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL DebugSetCoreCompare(void (*)(unsigned int), void (*)(int, void *)); #endif /* DebugSetRunState() * * This function sets the run state of the R4300 CPU emulator. */ typedef m64p_error (*ptr_DebugSetRunState)(m64p_dbg_runstate); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL DebugSetRunState(m64p_dbg_runstate); #endif /* DebugGetState() * * This function reads and returns a debugger state variable, which are * enumerated in m64p_types.h. */ typedef int (*ptr_DebugGetState)(m64p_dbg_state); #if defined(M64P_CORE_PROTOTYPES) EXPORT int CALL DebugGetState(m64p_dbg_state); #endif /* DebugStep() * * This function signals the debugger to advance one instruction when in the * stepping mode. */ typedef m64p_error (*ptr_DebugStep)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL DebugStep(void); #endif /* DebugDecodeOp() * * This is a helper function for the debugger front-end. This instruction takes * a PC value and an R4300 instruction opcode and writes the disassembled * instruction mnemonic and arguments into character buffers. This is intended * to be used to display disassembled code. */ typedef void (*ptr_DebugDecodeOp)(unsigned int, char *, char *, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT void CALL DebugDecodeOp(unsigned int, char *, char *, int); #endif /* DebugMemGetRecompInfo() * * This function is used by the front-end to retrieve disassembly information * about recompiled code. For example, the dynamic recompiler may take a single * R4300 instruction and compile it into 10 x86 instructions. This function may * then be used to retrieve the disassembled code of the 10 x86 instructions. */ typedef void * (*ptr_DebugMemGetRecompInfo)(m64p_dbg_mem_info, unsigned int, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT void * CALL DebugMemGetRecompInfo(m64p_dbg_mem_info, unsigned int, int); #endif /* DebugMemGetMemInfo() * * This function returns an integer value regarding the memory location address, * corresponding to the information requested by mem_info_type, which is a type * enumerated in m64p_types.h. */ typedef int (*ptr_DebugMemGetMemInfo)(m64p_dbg_mem_info, unsigned int); #if defined(M64P_CORE_PROTOTYPES) EXPORT int CALL DebugMemGetMemInfo(m64p_dbg_mem_info, unsigned int); #endif /* DebugMemGetPointer() * * This function returns a memory pointer (in x86 memory space) to a block of * emulated N64 memory. This may be used to retrieve a pointer to a special N64 * block (such as the serial, video, or audio registers) or the RDRAM. */ typedef void * (*ptr_DebugMemGetPointer)(m64p_dbg_memptr_type); #if defined(M64P_CORE_PROTOTYPES) EXPORT void * CALL DebugMemGetPointer(m64p_dbg_memptr_type); #endif /* DebugMemRead**() * * These functions retrieve a value from the emulated N64 memory. The returned * value will be correctly byte-swapped for the host architecture. */ typedef unsigned long long (*ptr_DebugMemRead64)(unsigned int); typedef unsigned int (*ptr_DebugMemRead32)(unsigned int); typedef unsigned short (*ptr_DebugMemRead16)(unsigned int); typedef unsigned char (*ptr_DebugMemRead8)(unsigned int); #if defined(M64P_CORE_PROTOTYPES) EXPORT unsigned long long CALL DebugMemRead64(unsigned int); EXPORT unsigned int CALL DebugMemRead32(unsigned int); EXPORT unsigned short CALL DebugMemRead16(unsigned int); EXPORT unsigned char CALL DebugMemRead8(unsigned int); #endif /* DebugMemWrite**() * * These functions write a value into the emulated N64 memory. The given value * will be correctly byte-swapped before storage. */ typedef void (*ptr_DebugMemWrite64)(unsigned int, unsigned long long); typedef void (*ptr_DebugMemWrite32)(unsigned int, unsigned int); typedef void (*ptr_DebugMemWrite16)(unsigned int, unsigned short); typedef void (*ptr_DebugMemWrite8)(unsigned int, unsigned char); #if defined(M64P_CORE_PROTOTYPES) EXPORT void CALL DebugMemWrite64(unsigned int, unsigned long long); EXPORT void CALL DebugMemWrite32(unsigned int, unsigned int); EXPORT void CALL DebugMemWrite16(unsigned int, unsigned short); EXPORT void CALL DebugMemWrite8(unsigned int, unsigned char); #endif /* DebugGetCPUDataPtr() * * This function returns a memory pointer (in x86 memory space) to a specific * register in the emulated R4300 CPU. */ typedef void * (*ptr_DebugGetCPUDataPtr)(m64p_dbg_cpu_data); #if defined(M64P_CORE_PROTOTYPES) EXPORT void * CALL DebugGetCPUDataPtr(m64p_dbg_cpu_data); #endif /* DebugBreakpointLookup() * * This function searches through all current breakpoints in the debugger to * find one that matches the given input parameters. If a matching breakpoint * is found, the index number is returned. If no breakpoints are found, -1 is * returned. */ typedef int (*ptr_DebugBreakpointLookup)(unsigned int, unsigned int, unsigned int); #if defined(M64P_CORE_PROTOTYPES) EXPORT int CALL DebugBreakpointLookup(unsigned int, unsigned int, unsigned int); #endif /* DebugBreakpointCommand() * * This function is used to process common breakpoint commands, such as adding, * removing, or searching the breakpoints. The meanings of the index and ptr * input parameters vary by command. */ typedef int (*ptr_DebugBreakpointCommand)(m64p_dbg_bkp_command, unsigned int, m64p_breakpoint *); #if defined(M64P_CORE_PROTOTYPES) EXPORT int CALL DebugBreakpointCommand(m64p_dbg_bkp_command, unsigned int, m64p_breakpoint *); #endif /* DebugBreakpointTriggeredBy() * * This function is used to retrieve the trigger flags and address for the * most recently triggered breakpoint. */ typedef void (*ptr_DebugBreakpointTriggeredBy)(uint32_t *, uint32_t *); #if defined(M64P_CORE_PROTOTYPES) EXPORT void CALL DebugBreakpointTriggeredBy(uint32_t *, uint32_t *); #endif /* DebugVirtualToPhysical() * * This function is used to translate virtual addresses to physical addresses. * Memory read/write breakpoints operate on physical addresses. */ typedef uint32_t (*ptr_DebugVirtualToPhysical)(uint32_t); #if defined(M64P_CORE_PROTOTYPES) EXPORT uint32_t CALL DebugVirtualToPhysical(uint32_t); #endif #ifdef __cplusplus } #endif #endif /* #define M64P_DEBUGGER_H */ mupen64plus-core-src-2.6.0/src/api/m64p_frontend.h000066400000000000000000000127731464506436200216560ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - m64p_frontend.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file defines typedefs for function pointers to Core functions * designed for use by the front-end user interface. */ #if !defined(M64P_FRONTEND_H) #define M64P_FRONTEND_H #include "m64p_types.h" #ifdef __cplusplus extern "C" { #endif /* pointer types to the callback functions in the front-end application */ typedef void (*ptr_DebugCallback)(void *Context, int level, const char *message); typedef void (*ptr_StateCallback)(void *Context, m64p_core_param param_type, int new_value); #if defined(M64P_CORE_PROTOTYPES) EXPORT void CALL DebugCallback(void *Context, int level, const char *message); EXPORT void CALL StateCallback(void *Context, m64p_core_param param_type, int new_value); #endif /* CoreStartup() * * This function initializes libmupen64plus for use by allocating memory, * creating data structures, and loading the configuration file. */ typedef m64p_error (*ptr_CoreStartup)(int, const char *, const char *, void *, ptr_DebugCallback, void *, ptr_StateCallback); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreStartup(int, const char *, const char *, void *, ptr_DebugCallback, void *, ptr_StateCallback); #endif /* CoreShutdown() * * This function saves the configuration file, then destroys data structures * and releases memory allocated by the core library. */ typedef m64p_error (*ptr_CoreShutdown)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreShutdown(void); #endif /* CoreAttachPlugin() * * This function attaches the given plugin to the emulator core. There can only * be one plugin of each type attached to the core at any given time. */ typedef m64p_error (*ptr_CoreAttachPlugin)(m64p_plugin_type, m64p_dynlib_handle); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreAttachPlugin(m64p_plugin_type, m64p_dynlib_handle); #endif /* CoreDetachPlugin() * * This function detaches the given plugin from the emulator core, and re-attaches * the 'dummy' plugin functions. */ typedef m64p_error (*ptr_CoreDetachPlugin)(m64p_plugin_type); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreDetachPlugin(m64p_plugin_type); #endif /* CoreDoCommand() * * This function sends a command to the emulator core. */ typedef m64p_error (*ptr_CoreDoCommand)(m64p_command, int, void *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreDoCommand(m64p_command, int, void *); #endif /* CoreOverrideVidExt() * * This function overrides the core's internal SDL-based OpenGL functions. This * override functionality allows a front-end to define its own video extension * functions to be used instead of the SDL functions. If any of the function * pointers in the structure are NULL, the override function will be disabled * and the core's internal SDL functions will be used. */ typedef m64p_error (*ptr_CoreOverrideVidExt)(m64p_video_extension_functions *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreOverrideVidExt(m64p_video_extension_functions *); #endif /* CoreAddCheat() * * This function will add a Cheat Function to a list of currently active cheats * which are applied to the open ROM. */ typedef m64p_error (*ptr_CoreAddCheat)(const char *, m64p_cheat_code *, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreAddCheat(const char *, m64p_cheat_code *, int); #endif /* CoreCheatEnabled() * * This function will enable or disable a Cheat Function which is in the list of * currently active cheats. */ typedef m64p_error (*ptr_CoreCheatEnabled)(const char *, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreCheatEnabled(const char *, int); #endif /* CoreGetRomSettings() * * This function will retrieve the ROM settings from the mupen64plus INI file for * the ROM image corresponding to the given CRC values. */ typedef m64p_error (*ptr_CoreGetRomSettings)(m64p_rom_settings *, int, int, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *, int, int, int); #endif #ifdef __cplusplus } #endif #endif /* #define M64P_FRONTEND_H */ mupen64plus-core-src-2.6.0/src/api/m64p_plugin.h000066400000000000000000000262021464506436200213250ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - m64p_plugin.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(M64P_PLUGIN_H) #define M64P_PLUGIN_H #include "m64p_types.h" #ifdef __cplusplus extern "C" { #endif /*** Controller plugin's ****/ #define PLUGIN_NONE 1 #define PLUGIN_MEMPAK 2 #define PLUGIN_RUMBLE_PAK 3 /* not implemented for non raw data */ #define PLUGIN_TRANSFER_PAK 4 /* not implemented for non raw data */ #define PLUGIN_RAW 5 /* the controller plugin is passed in raw data */ #define PLUGIN_BIO_PAK 6 /***** Structures *****/ typedef struct { unsigned char * RDRAM; unsigned char * DMEM; unsigned char * IMEM; unsigned int * MI_INTR_REG; unsigned int * SP_MEM_ADDR_REG; unsigned int * SP_DRAM_ADDR_REG; unsigned int * SP_RD_LEN_REG; unsigned int * SP_WR_LEN_REG; unsigned int * SP_STATUS_REG; unsigned int * SP_DMA_FULL_REG; unsigned int * SP_DMA_BUSY_REG; unsigned int * SP_PC_REG; unsigned int * SP_SEMAPHORE_REG; unsigned int * DPC_START_REG; unsigned int * DPC_END_REG; unsigned int * DPC_CURRENT_REG; unsigned int * DPC_STATUS_REG; unsigned int * DPC_CLOCK_REG; unsigned int * DPC_BUFBUSY_REG; unsigned int * DPC_PIPEBUSY_REG; unsigned int * DPC_TMEM_REG; void (*CheckInterrupts)(void); void (*ProcessDlistList)(void); void (*ProcessAlistList)(void); void (*ProcessRdpList)(void); void (*ShowCFB)(void); } RSP_INFO; typedef struct { unsigned char * HEADER; /* This is the rom header (first 40h bytes of the rom) */ unsigned char * RDRAM; unsigned char * DMEM; unsigned char * IMEM; unsigned int * MI_INTR_REG; unsigned int * DPC_START_REG; unsigned int * DPC_END_REG; unsigned int * DPC_CURRENT_REG; unsigned int * DPC_STATUS_REG; unsigned int * DPC_CLOCK_REG; unsigned int * DPC_BUFBUSY_REG; unsigned int * DPC_PIPEBUSY_REG; unsigned int * DPC_TMEM_REG; unsigned int * VI_STATUS_REG; unsigned int * VI_ORIGIN_REG; unsigned int * VI_WIDTH_REG; unsigned int * VI_INTR_REG; unsigned int * VI_V_CURRENT_LINE_REG; unsigned int * VI_TIMING_REG; unsigned int * VI_V_SYNC_REG; unsigned int * VI_H_SYNC_REG; unsigned int * VI_LEAP_REG; unsigned int * VI_H_START_REG; unsigned int * VI_V_START_REG; unsigned int * VI_V_BURST_REG; unsigned int * VI_X_SCALE_REG; unsigned int * VI_Y_SCALE_REG; void (*CheckInterrupts)(void); /* The GFX_INFO.version parameter was added in version 2.5.1 of the core. Plugins should ensure the core is at least this version before attempting to read GFX_INFO.version. */ unsigned int version; /* SP_STATUS_REG and RDRAM_SIZE were added in version 2 of GFX_INFO.version. Plugins should only attempt to read these values if GFX_INFO.version is at least 2. */ /* The RSP plugin should set (HALT | BROKE | TASKDONE) *before* calling ProcessDList. It should not modify SP_STATUS_REG after ProcessDList has returned. This will allow the GFX plugin to unset these bits if it needs. */ unsigned int * SP_STATUS_REG; const unsigned int * RDRAM_SIZE; } GFX_INFO; typedef struct { unsigned char * RDRAM; unsigned char * DMEM; unsigned char * IMEM; unsigned int * MI_INTR_REG; unsigned int * AI_DRAM_ADDR_REG; unsigned int * AI_LEN_REG; unsigned int * AI_CONTROL_REG; unsigned int * AI_STATUS_REG; unsigned int * AI_DACRATE_REG; unsigned int * AI_BITRATE_REG; void (*CheckInterrupts)(void); } AUDIO_INFO; /*** Controller types ****/ #define CONT_TYPE_STANDARD 0 #define CONT_TYPE_VRU 1 typedef struct { int Present; int RawData; int Plugin; int Type; } CONTROL; typedef union { unsigned int Value; struct { unsigned R_DPAD : 1; unsigned L_DPAD : 1; unsigned D_DPAD : 1; unsigned U_DPAD : 1; unsigned START_BUTTON : 1; unsigned Z_TRIG : 1; unsigned B_BUTTON : 1; unsigned A_BUTTON : 1; unsigned R_CBUTTON : 1; unsigned L_CBUTTON : 1; unsigned D_CBUTTON : 1; unsigned U_CBUTTON : 1; unsigned R_TRIG : 1; unsigned L_TRIG : 1; unsigned Reserved1 : 1; unsigned Reserved2 : 1; signed X_AXIS : 8; signed Y_AXIS : 8; }; } BUTTONS; typedef struct { CONTROL *Controls; /* A pointer to an array of 4 controllers .. eg: CONTROL Controls[4]; */ } CONTROL_INFO; /* common plugin function pointer types */ typedef void (*ptr_RomClosed)(void); typedef int (*ptr_RomOpen)(void); #if defined(M64P_PLUGIN_PROTOTYPES) EXPORT int CALL RomOpen(void); EXPORT void CALL RomClosed(void); #endif /* video plugin function pointer types */ typedef void (*ptr_ChangeWindow)(void); typedef int (*ptr_InitiateGFX)(GFX_INFO Gfx_Info); typedef void (*ptr_MoveScreen)(int x, int y); typedef void (*ptr_ProcessDList)(void); typedef void (*ptr_ProcessRDPList)(void); typedef void (*ptr_ShowCFB)(void); typedef void (*ptr_UpdateScreen)(void); typedef void (*ptr_ViStatusChanged)(void); typedef void (*ptr_ViWidthChanged)(void); typedef void (*ptr_ReadScreen2)(void *dest, int *width, int *height, int front); typedef void (*ptr_SetRenderingCallback)(void (*callback)(int)); typedef void (*ptr_ResizeVideoOutput)(int width, int height); #if defined(M64P_PLUGIN_PROTOTYPES) EXPORT void CALL ChangeWindow(void); EXPORT int CALL InitiateGFX(GFX_INFO Gfx_Info); EXPORT void CALL MoveScreen(int x, int y); EXPORT void CALL ProcessDList(void); EXPORT void CALL ProcessRDPList(void); EXPORT void CALL ShowCFB(void); EXPORT void CALL UpdateScreen(void); EXPORT void CALL ViStatusChanged(void); EXPORT void CALL ViWidthChanged(void); EXPORT void CALL ReadScreen2(void *dest, int *width, int *height, int front); EXPORT void CALL SetRenderingCallback(void (*callback)(int)); EXPORT void CALL ResizeVideoOutput(int width, int height); #endif /* frame buffer plugin spec extension */ typedef struct { unsigned int addr; unsigned int size; unsigned int width; unsigned int height; } FrameBufferInfo; typedef void (*ptr_FBRead)(unsigned int addr); typedef void (*ptr_FBWrite)(unsigned int addr, unsigned int size); typedef void (*ptr_FBGetFrameBufferInfo)(void *p); #if defined(M64P_PLUGIN_PROTOTYPES) EXPORT void CALL FBRead(unsigned int addr); EXPORT void CALL FBWrite(unsigned int addr, unsigned int size); EXPORT void CALL FBGetFrameBufferInfo(void *p); #endif /* audio plugin function pointers */ typedef void (*ptr_AiDacrateChanged)(int SystemType); typedef void (*ptr_AiLenChanged)(void); typedef int (*ptr_InitiateAudio)(AUDIO_INFO Audio_Info); typedef void (*ptr_ProcessAList)(void); typedef void (*ptr_SetSpeedFactor)(int percent); typedef void (*ptr_VolumeUp)(void); typedef void (*ptr_VolumeDown)(void); typedef int (*ptr_VolumeGetLevel)(void); typedef void (*ptr_VolumeSetLevel)(int level); typedef void (*ptr_VolumeMute)(void); typedef const char * (*ptr_VolumeGetString)(void); #if defined(M64P_PLUGIN_PROTOTYPES) EXPORT void CALL AiDacrateChanged(int SystemType); EXPORT void CALL AiLenChanged(void); EXPORT int CALL InitiateAudio(AUDIO_INFO Audio_Info); EXPORT void CALL ProcessAList(void); EXPORT void CALL SetSpeedFactor(int percent); EXPORT void CALL VolumeUp(void); EXPORT void CALL VolumeDown(void); EXPORT int CALL VolumeGetLevel(void); EXPORT void CALL VolumeSetLevel(int level); EXPORT void CALL VolumeMute(void); EXPORT const char * CALL VolumeGetString(void); #endif /* input plugin function pointers */ typedef void (*ptr_ControllerCommand)(int Control, unsigned char *Command); typedef void (*ptr_GetKeys)(int Control, BUTTONS *Keys); typedef void (*ptr_InitiateControllers)(CONTROL_INFO ControlInfo); typedef void (*ptr_ReadController)(int Control, unsigned char *Command); typedef void (*ptr_SDL_KeyDown)(int keymod, int keysym); typedef void (*ptr_SDL_KeyUp)(int keymod, int keysym); typedef void (*ptr_RenderCallback)(void); typedef void (*ptr_SendVRUWord)(uint16_t length, uint16_t *word, uint8_t lang); typedef void (*ptr_SetMicState)(int state); typedef void (*ptr_ReadVRUResults)(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches); typedef void (*ptr_ClearVRUWords)(uint8_t length); typedef void (*ptr_SetVRUWordMask)(uint8_t length, uint8_t *mask); #if defined(M64P_PLUGIN_PROTOTYPES) EXPORT void CALL ControllerCommand(int Control, unsigned char *Command); EXPORT void CALL GetKeys(int Control, BUTTONS *Keys); EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo); EXPORT void CALL ReadController(int Control, unsigned char *Command); EXPORT void CALL SDL_KeyDown(int keymod, int keysym); EXPORT void CALL SDL_KeyUp(int keymod, int keysym); EXPORT void CALL RenderCallback(void); EXPORT void CALL SendVRUWord(uint16_t length, uint16_t *word, uint8_t lang); EXPORT void CALL SetMicState(int state); EXPORT void CALL ReadVRUResults(uint16_t *error_flags, uint16_t *num_results, uint16_t *mic_level, uint16_t *voice_level, uint16_t *voice_length, uint16_t *matches); EXPORT void CALL ClearVRUWords(uint8_t length); EXPORT void CALL SetVRUWordMask(uint8_t length, uint8_t *mask); #endif /* RSP plugin function pointers */ typedef unsigned int (*ptr_DoRspCycles)(unsigned int Cycles); typedef void (*ptr_InitiateRSP)(RSP_INFO Rsp_Info, unsigned int *CycleCount); #if defined(M64P_PLUGIN_PROTOTYPES) EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles); EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount); #endif #ifdef __cplusplus } #endif #endif /* M64P_PLUGIN_H */ mupen64plus-core-src-2.6.0/src/api/m64p_types.h000066400000000000000000000354041464506436200211770ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - m64p_types.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 CasualJames * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(M64P_TYPES_H) #define M64P_TYPES_H /* ----------------------------------------- */ /* Platform-specific stuff */ /* ----------------------------------------- */ /* necessary headers */ #include #if defined(WIN32) #include #endif /* DLL handles and function declaration specifiers */ #if defined(WIN32) #define IMPORT extern "C" __declspec(dllimport) #define EXPORT __declspec(dllexport) #define CALL __cdecl typedef HMODULE m64p_dynlib_handle; #else #define IMPORT extern "C" #define EXPORT __attribute__((visibility("default"))) #define CALL typedef void * m64p_dynlib_handle; #endif /* ----------------------------------------- */ /* Structures and Types for Core library API */ /* ----------------------------------------- */ typedef void * m64p_handle; /* Generic function pointer returned from osal_dynlib_getproc (and the like) * Don't use it directly, cast to proper type before using it. */ typedef void (*m64p_function)(void); typedef void (*m64p_frame_callback)(unsigned int FrameIndex); typedef void (*m64p_input_callback)(void); typedef void (*m64p_audio_callback)(void); typedef void (*m64p_vi_callback)(void); typedef enum { M64TYPE_INT = 1, M64TYPE_FLOAT, M64TYPE_BOOL, M64TYPE_STRING } m64p_type; typedef enum { M64MSG_ERROR = 1, M64MSG_WARNING, M64MSG_INFO, M64MSG_STATUS, M64MSG_VERBOSE } m64p_msg_level; typedef enum { M64ERR_SUCCESS = 0, M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */ M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */ M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */ M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */ M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */ M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */ M64ERR_NO_MEMORY, /* Memory allocation failed */ M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */ M64ERR_INTERNAL, /* Internal error (bug) */ M64ERR_INVALID_STATE, /* Current program state does not allow operation */ M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */ M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */ M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */ M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */ } m64p_error; typedef enum { M64CAPS_DYNAREC = 1, M64CAPS_DEBUGGER = 2, M64CAPS_CORE_COMPARE = 4 } m64p_core_caps; typedef enum { M64PLUGIN_NULL = 0, M64PLUGIN_RSP = 1, M64PLUGIN_GFX, M64PLUGIN_AUDIO, M64PLUGIN_INPUT, M64PLUGIN_CORE } m64p_plugin_type; typedef enum { M64EMU_STOPPED = 1, M64EMU_RUNNING, M64EMU_PAUSED } m64p_emu_state; typedef enum { M64VIDEO_NONE = 1, M64VIDEO_WINDOWED, M64VIDEO_FULLSCREEN } m64p_video_mode; typedef enum { M64VIDEOFLAG_SUPPORT_RESIZING = 1 } m64p_video_flags; typedef enum { M64CORE_EMU_STATE = 1, M64CORE_VIDEO_MODE, M64CORE_SAVESTATE_SLOT, M64CORE_SPEED_FACTOR, M64CORE_SPEED_LIMITER, M64CORE_VIDEO_SIZE, M64CORE_AUDIO_VOLUME, M64CORE_AUDIO_MUTE, M64CORE_INPUT_GAMESHARK, M64CORE_STATE_LOADCOMPLETE, M64CORE_STATE_SAVECOMPLETE, M64CORE_SCREENSHOT_CAPTURED, } m64p_core_param; typedef enum { M64CMD_NOP = 0, M64CMD_ROM_OPEN, M64CMD_ROM_CLOSE, M64CMD_ROM_GET_HEADER, M64CMD_ROM_GET_SETTINGS, M64CMD_EXECUTE, M64CMD_STOP, M64CMD_PAUSE, M64CMD_RESUME, M64CMD_CORE_STATE_QUERY, M64CMD_STATE_LOAD, M64CMD_STATE_SAVE, M64CMD_STATE_SET_SLOT, M64CMD_SEND_SDL_KEYDOWN, M64CMD_SEND_SDL_KEYUP, M64CMD_SET_FRAME_CALLBACK, M64CMD_TAKE_NEXT_SCREENSHOT, M64CMD_CORE_STATE_SET, M64CMD_READ_SCREEN, M64CMD_RESET, M64CMD_ADVANCE_FRAME, M64CMD_SET_MEDIA_LOADER, M64CMD_NETPLAY_INIT, M64CMD_NETPLAY_CONTROL_PLAYER, M64CMD_NETPLAY_GET_VERSION, M64CMD_NETPLAY_CLOSE, M64CMD_PIF_OPEN, M64CMD_ROM_SET_SETTINGS, M64CMD_DISK_OPEN, M64CMD_DISK_CLOSE } m64p_command; typedef struct { uint32_t address; int value; } m64p_cheat_code; typedef struct { /* Frontend-defined callback data. */ void* cb_data; /* Allow the frontend to specify the GB cart ROM file to load * cb_data: points to frontend-defined callback data. * controller_num: (0-3) tell the frontend which controller is about to load a GB cart * Returns a NULL-terminated string owned by the core specifying the GB cart ROM filename to load. * Empty or NULL string results in no GB cart being loaded (eg. empty transferpak). */ char* (*get_gb_cart_rom)(void* cb_data, int controller_num); /* Allow the frontend to specify the GB cart RAM file to load * cb_data: points to frontend-defined callback data. * controller_num: (0-3) tell the frontend which controller is about to load a GB cart * Returns a NULL-terminated string owned by the core specifying the GB cart RAM filename to load * Empty or NULL string results in the core generating a default save file with empty content. */ char* (*get_gb_cart_ram)(void* cb_data, int controller_num); /* Allow the frontend to know what DD IPL ROM region file to load * cb_data: points to frontend-defined callback data. * region: a region from m64p_system_type */ void (*set_dd_rom_region)(void* cb_data, uint8_t region); /* Allow the frontend to specify the DD IPL ROM file to load * cb_data: points to frontend-defined callback data. * Returns a NULL-terminated string owned by the core specifying the DD IPL ROM filename to load * Empty or NULL string results in disabled 64DD. */ char* (*get_dd_rom)(void* cb_data); /* Allow the frontend to specify the DD disk file to load * cb_data: points to frontend-defined callback data. * Returns a NULL-terminated string owned by the core specifying the DD disk filename to load * Empty or NULL string results in no DD disk being loaded (eg. empty disk drive). */ char* (*get_dd_disk)(void* cb_data); } m64p_media_loader; /* ----------------------------------------- */ /* Structures to hold ROM image information */ /* ----------------------------------------- */ typedef enum { SYSTEM_NTSC = 0, SYSTEM_PAL, SYSTEM_MPAL } m64p_system_type; typedef enum { SAVETYPE_EEPROM_4K = 0, SAVETYPE_EEPROM_4KB = 0, // Preserve inaccurate/misleading name SAVETYPE_EEPROM_16K = 1, SAVETYPE_EEPROM_16KB = 1, // Preserve inaccurate/misleading name SAVETYPE_SRAM = 2, SAVETYPE_FLASH_RAM = 3, SAVETYPE_CONTROLLER_PAK = 4, SAVETYPE_CONTROLLER_PACK = 4, // Preserve inaccurate/off-brand name SAVETYPE_NONE = 5, } m64p_rom_save_type; typedef enum { DDREGION_JAPAN = 0, DDREGION_US = 1, DDREGION_DEV = 2, DDREGION_UNKNOWN = 3, } m64p_disk_region; typedef struct { uint8_t init_PI_BSB_DOM1_LAT_REG; /* 0x00 */ uint8_t init_PI_BSB_DOM1_PGS_REG; /* 0x01 */ uint8_t init_PI_BSB_DOM1_PWD_REG; /* 0x02 */ uint8_t init_PI_BSB_DOM1_PGS_REG2; /* 0x03 */ uint32_t ClockRate; /* 0x04 */ uint32_t PC; /* 0x08 */ uint32_t Release; /* 0x0C */ uint32_t CRC1; /* 0x10 */ uint32_t CRC2; /* 0x14 */ uint32_t Unknown[2]; /* 0x18 */ uint8_t Name[20]; /* 0x20 */ uint32_t unknown; /* 0x34 */ uint32_t Manufacturer_ID; /* 0x38 */ uint16_t Cartridge_ID; /* 0x3C - Game serial number */ uint8_t Country_code; /* 0x3E */ uint8_t Version; /* 0x3F */ } m64p_rom_header; typedef struct { char goodname[256]; char MD5[33]; unsigned char savetype; unsigned char status; /* Rom status on a scale from 0-5. */ unsigned char players; /* Local players 0-4, 2/3/4 way Netplay indicated by 5/6/7. */ unsigned char rumble; /* 0 - No, 1 - Yes boolean for rumble support. */ unsigned char transferpak; /* 0 - No, 1 - Yes boolean for transfer pak support. */ unsigned char mempak; /* 0 - No, 1 - Yes boolean for memory pak support. */ unsigned char biopak; /* 0 - No, 1 - Yes boolean for bio pak support. */ unsigned char disableextramem; /* 0 - No, 1 - Yes boolean for disabling 4MB expansion RAM pack */ unsigned int countperop; /* Number of CPU cycles per instruction. */ unsigned int sidmaduration; /* Default SI DMA duration */ unsigned int aidmamodifier; /* Percentage modifier for AI DMA duration */ } m64p_rom_settings; /* ----------------------------------------- */ /* Structures and Types for the Debugger */ /* ----------------------------------------- */ typedef enum { M64P_DBG_RUN_STATE = 1, M64P_DBG_PREVIOUS_PC, M64P_DBG_NUM_BREAKPOINTS, M64P_DBG_CPU_DYNACORE, M64P_DBG_CPU_NEXT_INTERRUPT } m64p_dbg_state; typedef enum { M64P_DBG_RUNSTATE_PAUSED = 0, M64P_DBG_RUNSTATE_STEPPING, M64P_DBG_RUNSTATE_RUNNING } m64p_dbg_runstate; typedef enum { M64P_DBG_MEM_TYPE = 1, M64P_DBG_MEM_FLAGS, M64P_DBG_MEM_HAS_RECOMPILED, M64P_DBG_MEM_NUM_RECOMPILED, M64P_DBG_RECOMP_OPCODE = 16, M64P_DBG_RECOMP_ARGS, M64P_DBG_RECOMP_ADDR } m64p_dbg_mem_info; typedef enum { M64P_MEM_NOMEM = 0, M64P_MEM_NOTHING, M64P_MEM_RDRAM, M64P_MEM_RDRAMREG, M64P_MEM_RSPMEM, M64P_MEM_RSPREG, M64P_MEM_RSP, M64P_MEM_DP, M64P_MEM_DPS, M64P_MEM_VI, M64P_MEM_AI, M64P_MEM_PI, M64P_MEM_RI, M64P_MEM_SI, M64P_MEM_FLASHRAMSTAT, M64P_MEM_ROM, M64P_MEM_PIF, M64P_MEM_MI, M64P_MEM_BREAKPOINT } m64p_dbg_mem_type; typedef enum { M64P_MEM_FLAG_READABLE = 0x01, M64P_MEM_FLAG_WRITABLE = 0x02, M64P_MEM_FLAG_READABLE_EMUONLY = 0x04, /* the EMUONLY flags signify that emulated code can read/write here, but debugger cannot */ M64P_MEM_FLAG_WRITABLE_EMUONLY = 0x08 } m64p_dbg_mem_flags; typedef enum { M64P_DBG_PTR_RDRAM = 1, M64P_DBG_PTR_PI_REG, M64P_DBG_PTR_SI_REG, M64P_DBG_PTR_VI_REG, M64P_DBG_PTR_RI_REG, M64P_DBG_PTR_AI_REG } m64p_dbg_memptr_type; typedef enum { M64P_CPU_PC = 1, M64P_CPU_REG_REG, M64P_CPU_REG_HI, M64P_CPU_REG_LO, M64P_CPU_REG_COP0, M64P_CPU_REG_COP1_DOUBLE_PTR, M64P_CPU_REG_COP1_SIMPLE_PTR, M64P_CPU_REG_COP1_FGR_64, M64P_CPU_TLB } m64p_dbg_cpu_data; typedef enum { M64P_BKP_CMD_ADD_ADDR = 1, M64P_BKP_CMD_ADD_STRUCT, M64P_BKP_CMD_REPLACE, M64P_BKP_CMD_REMOVE_ADDR, M64P_BKP_CMD_REMOVE_IDX, M64P_BKP_CMD_ENABLE, M64P_BKP_CMD_DISABLE, M64P_BKP_CMD_CHECK } m64p_dbg_bkp_command; #define M64P_MEM_INVALID 0xFFFFFFFF /* invalid memory read will return this */ #define BREAKPOINTS_MAX_NUMBER 128 typedef enum { M64P_BKP_FLAG_ENABLED = 0x01, M64P_BKP_FLAG_READ = 0x02, M64P_BKP_FLAG_WRITE = 0x04, M64P_BKP_FLAG_EXEC = 0x08, M64P_BKP_FLAG_LOG = 0x10 /* Log to the console when this breakpoint hits */ } m64p_dbg_bkp_flags; #define BPT_CHECK_FLAG(a, b) ((a.flags & b) == b) #define BPT_SET_FLAG(a, b) a.flags = (a.flags | b); #define BPT_CLEAR_FLAG(a, b) a.flags = (a.flags & (~b)); #define BPT_TOGGLE_FLAG(a, b) a.flags = (a.flags ^ b); typedef struct { uint32_t address; uint32_t endaddr; unsigned int flags; } m64p_breakpoint; /* ------------------------------------------------- */ /* Structures and Types for Core Video Extension API */ /* ------------------------------------------------- */ typedef struct { unsigned int uiWidth; unsigned int uiHeight; } m64p_2d_size; typedef enum { M64P_GL_DOUBLEBUFFER = 1, M64P_GL_BUFFER_SIZE, M64P_GL_DEPTH_SIZE, M64P_GL_RED_SIZE, M64P_GL_GREEN_SIZE, M64P_GL_BLUE_SIZE, M64P_GL_ALPHA_SIZE, M64P_GL_SWAP_CONTROL, M64P_GL_MULTISAMPLEBUFFERS, M64P_GL_MULTISAMPLESAMPLES, M64P_GL_CONTEXT_MAJOR_VERSION, M64P_GL_CONTEXT_MINOR_VERSION, M64P_GL_CONTEXT_PROFILE_MASK } m64p_GLattr; typedef enum { M64P_GL_CONTEXT_PROFILE_CORE, M64P_GL_CONTEXT_PROFILE_COMPATIBILITY, M64P_GL_CONTEXT_PROFILE_ES } m64p_GLContextType; typedef enum { M64P_RENDER_OPENGL = 0, M64P_RENDER_VULKAN } m64p_render_mode; typedef struct { unsigned int Functions; m64p_error (*VidExtFuncInit)(void); m64p_error (*VidExtFuncQuit)(void); m64p_error (*VidExtFuncListModes)(m64p_2d_size *, int *); m64p_error (*VidExtFuncListRates)(m64p_2d_size, int *, int *); m64p_error (*VidExtFuncSetMode)(int, int, int, int, int); m64p_error (*VidExtFuncSetModeWithRate)(int, int, int, int, int, int); m64p_function (*VidExtFuncGLGetProc)(const char*); m64p_error (*VidExtFuncGLSetAttr)(m64p_GLattr, int); m64p_error (*VidExtFuncGLGetAttr)(m64p_GLattr, int *); m64p_error (*VidExtFuncGLSwapBuf)(void); m64p_error (*VidExtFuncSetCaption)(const char *); m64p_error (*VidExtFuncToggleFS)(void); m64p_error (*VidExtFuncResizeWindow)(int, int); uint32_t (*VidExtFuncGLGetDefaultFramebuffer)(void); m64p_error (*VidExtFuncInitWithRenderMode)(m64p_render_mode); m64p_error (*VidExtFuncVKGetSurface)(void**, void*); m64p_error (*VidExtFuncVKGetInstanceExtensions)(const char**[], uint32_t*); } m64p_video_extension_functions; #endif /* define M64P_TYPES_H */ mupen64plus-core-src-2.6.0/src/api/m64p_vidext.h000066400000000000000000000201251464506436200213300ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - m64p_vidext.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This header file defines typedefs for function pointers to the core's * video extension functions. */ #if !defined(M64P_VIDEXT_H) #define M64P_VIDEXT_H #include "m64p_types.h" #ifdef __cplusplus extern "C" { #endif /* VidExt_Init() * * This function should be called from within the InitiateGFX() video plugin * function call. The default SDL implementation of this function simply calls * SDL_InitSubSystem(SDL_INIT_VIDEO). It does not open a rendering window or * switch video modes. */ typedef m64p_error (*ptr_VidExt_Init)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_Init(void); #endif /* VidExt_InitWithRenderMode() * * This function should be called from within the InitiateGFX() video plugin * function call with the specified rendering mode (OpenGL or Vulkan). * The default SDL implementation of this function simply calls * SDL_InitSubSystem(SDL_INIT_VIDEO). It does not open a rendering window or * switch video modes. */ typedef m64p_error (*ptr_VidExt_InitWithRenderMode)(m64p_render_mode); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_InitWithRenderMode(m64p_render_mode); #endif /* VidExt_Quit() * * This function closes any open rendering window and shuts down the video * system. The default SDL implementation of this function calls * SDL_QuitSubSystem(SDL_INIT_VIDEO). This function should be called from * within the RomClose() video plugin function. */ typedef m64p_error (*ptr_VidExt_Quit)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_Quit(void); #endif /* VidExt_ListFullscreenModes() * * This function is used to enumerate the available resolutions for fullscreen * video modes. A pointer to an array is passed into the function, which is * then filled with resolution sizes. */ typedef m64p_error (*ptr_VidExt_ListFullscreenModes)(m64p_2d_size *, int *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *, int *); #endif /* VidExt_ListFullscreenRates() * * This function is used to enumerate the available refresh rates for a fullscreen * video mode. */ typedef m64p_error (*ptr_VidExt_ListFullscreenRates)(m64p_2d_size, int *, int *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_ListFullscreenRates(m64p_2d_size, int *, int *); #endif /* VidExt_SetVideoMode() * * This function creates a rendering window or switches into a fullscreen * video mode. Any desired OpenGL attributes should be set before calling * this function. */ typedef m64p_error (*ptr_VidExt_SetVideoMode)(int, int, int, m64p_video_mode, m64p_video_flags); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_SetVideoMode(int, int, int, m64p_video_mode, m64p_video_flags); #endif /* VidExt_SetVideoModeWithRate() * * This function creates a rendering window or switches into a fullscreen * video mode. Any desired OpenGL attributes should be set before calling * this function. */ typedef m64p_error (*ptr_VidExt_SetVideoModeWithRate)(int, int, int, int, m64p_video_mode, m64p_video_flags); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_SetVideoModeWithRate(int, int, int, int, m64p_video_mode, m64p_video_flags); #endif /* VidExt_ResizeWindow() * * This function resizes the opengl rendering window to match the given size. */ typedef m64p_error (*ptr_VidExt_ResizeWindow)(int, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_ResizeWindow(int, int); #endif /* VidExt_SetCaption() * * This function sets the caption text of the emulator rendering window. */ typedef m64p_error (*ptr_VidExt_SetCaption)(const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_SetCaption(const char *); #endif /* VidExt_ToggleFullScreen() * * This function toggles between fullscreen and windowed rendering modes. */ typedef m64p_error (*ptr_VidExt_ToggleFullScreen)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_ToggleFullScreen(void); #endif /* VidExt_GL_GetProcAddress() * * This function is used to get a pointer to an OpenGL extension function. This * is only necessary on the Windows platform, because the OpenGL implementation * shipped with Windows only supports OpenGL version 1.1. */ typedef m64p_function (*ptr_VidExt_GL_GetProcAddress)(const char *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_function CALL VidExt_GL_GetProcAddress(const char *); #endif /* VidExt_GL_SetAttribute() * * This function is used to set certain OpenGL attributes which must be * specified before creating the rendering window with VidExt_SetVideoMode. */ typedef m64p_error (*ptr_VidExt_GL_SetAttribute)(m64p_GLattr, int); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_GL_SetAttribute(m64p_GLattr, int); #endif /* VidExt_GL_GetAttribute() * * This function is used to get the value of OpenGL attributes. These values may * be changed when calling VidExt_SetVideoMode. */ typedef m64p_error (*ptr_VidExt_GL_GetAttribute)(m64p_GLattr, int *); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_GL_GetAttribute(m64p_GLattr, int *); #endif /* VidExt_GL_SwapBuffers() * * This function is used to swap the front/back buffers after rendering an * output video frame. */ typedef m64p_error (*ptr_VidExt_GL_SwapBuffers)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_GL_SwapBuffers(void); #endif /* VidExt_GL_GetDefaultFramebuffer() * * On some platforms (for instance, iOS) the default framebuffer object * depends on the surface being rendered to, and might be different from 0. * This function should be called after VidExt_SetVideoMode to retrieve the * name of the default FBO. * Calling this function may have performance implications * and it should not be called every time the default FBO is bound. */ typedef uint32_t (*ptr_VidExt_GL_GetDefaultFramebuffer)(void); #if defined(M64P_CORE_PROTOTYPES) EXPORT uint32_t CALL VidExt_GL_GetDefaultFramebuffer(void); #endif /* VidExt_VK_GetSurface() * * This functions gives out a vulkan surface */ typedef m64p_error (*ptr_VidExt_VK_GetSurface)(void**, void*); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_VK_GetSurface(void**, void*); #endif /* VidExt_VK_GetInstanceExtensions() * * This functions gives out a list of supported vulkan * extensions, and the caller will be given the amount * of strings stored in the list */ typedef m64p_error (*ptr_VidExt_VK_GetInstanceExtensions)(const char**[], uint32_t*); #if defined(M64P_CORE_PROTOTYPES) EXPORT m64p_error CALL VidExt_VK_GetInstanceExtensions(const char**[], uint32_t*); #endif #ifdef __cplusplus } #endif #endif /* #define M64P_VIDEXT_H */ mupen64plus-core-src-2.6.0/src/api/vidext.c000066400000000000000000000656741464506436200204770ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/vidext.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the Core video extension functions which will be exported * outside of the core library. */ #include /* we need at least SDL 2.0.6 for vulkan */ #if !SDL_VERSION_ATLEAST(2,0,6) #undef VIDEXT_VULKAN #endif #ifdef VIDEXT_VULKAN #include #include #endif #include #include #define M64P_CORE_PROTOTYPES 1 #include "osal/preproc.h" #include "../osd/osd.h" #include "callbacks.h" #include "m64p_types.h" #include "m64p_vidext.h" #include "vidext.h" #if SDL_VERSION_ATLEAST(2,0,0) #ifndef USE_GLES static int l_ForceCompatibilityContext = 1; #endif #include "vidext_sdl2_compat.h" #endif /* local variables */ static m64p_video_extension_functions l_ExternalVideoFuncTable = {17, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static int l_VideoExtensionActive = 0; static int l_VideoOutputActive = 0; static int l_Fullscreen = 0; static int l_SwapControl = 0; static m64p_render_mode l_RenderMode = M64P_RENDER_OPENGL; static SDL_Surface *l_pScreen = NULL; #ifdef VIDEXT_VULKAN static const char** l_VulkanExtensionNames = NULL; #endif /* global function for use by frontend.c */ m64p_error OverrideVideoFunctions(m64p_video_extension_functions *VideoFunctionStruct) { /* check input data */ if (VideoFunctionStruct == NULL) return M64ERR_INPUT_ASSERT; if (VideoFunctionStruct->Functions < 17) return M64ERR_INPUT_INVALID; /* disable video extension if any of the function pointers are NULL */ if (VideoFunctionStruct->VidExtFuncInit == NULL || VideoFunctionStruct->VidExtFuncInitWithRenderMode == NULL || VideoFunctionStruct->VidExtFuncQuit == NULL || VideoFunctionStruct->VidExtFuncListModes == NULL || VideoFunctionStruct->VidExtFuncListRates == NULL || VideoFunctionStruct->VidExtFuncSetMode == NULL || VideoFunctionStruct->VidExtFuncSetModeWithRate == NULL || VideoFunctionStruct->VidExtFuncGLGetProc == NULL || VideoFunctionStruct->VidExtFuncGLSetAttr == NULL || VideoFunctionStruct->VidExtFuncGLGetAttr == NULL || VideoFunctionStruct->VidExtFuncGLSwapBuf == NULL || VideoFunctionStruct->VidExtFuncSetCaption == NULL || VideoFunctionStruct->VidExtFuncToggleFS == NULL || VideoFunctionStruct->VidExtFuncResizeWindow == NULL || VideoFunctionStruct->VidExtFuncGLGetDefaultFramebuffer == NULL || VideoFunctionStruct->VidExtFuncVKGetSurface == NULL || VideoFunctionStruct->VidExtFuncVKGetInstanceExtensions == NULL) { l_ExternalVideoFuncTable.Functions = 17; memset(&l_ExternalVideoFuncTable.VidExtFuncInit, 0, 17 * sizeof(void *)); l_VideoExtensionActive = 0; return M64ERR_SUCCESS; } /* otherwise copy in the override function pointers */ memcpy(&l_ExternalVideoFuncTable, VideoFunctionStruct, sizeof(m64p_video_extension_functions)); l_VideoExtensionActive = 1; return M64ERR_SUCCESS; } int VidExt_InFullscreenMode(void) { return l_Fullscreen; } int VidExt_VideoRunning(void) { return l_VideoOutputActive; } /* video extension functions to be called by the video plugin */ EXPORT m64p_error CALL VidExt_Init(void) { /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncInit)(); /* redirect to VidExt_InitWithRenderMode with OpenGL render mode */ return VidExt_InitWithRenderMode(M64P_RENDER_OPENGL); } EXPORT m64p_error CALL VidExt_InitWithRenderMode(m64p_render_mode RenderMode) { /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncInitWithRenderMode)(RenderMode); /* set global render mode */ #ifdef VIDEXT_VULKAN l_RenderMode = RenderMode; #endif #if SDL_VERSION_ATLEAST(2,0,0) SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); /* retrieve default swap interval/VSync */ if (RenderMode == M64P_RENDER_OPENGL) { l_SwapControl = SDL_GL_GetSwapInterval(); } #endif #if SDL_VERSION_ATLEAST(2,24,0) /* fix DPI scaling issues on Windows */ SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitorv2"); #endif if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) { DebugMessage(M64MSG_ERROR, "SDL video subsystem init failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } /* attempt to load vulkan library */ if (RenderMode == M64P_RENDER_VULKAN) { #ifdef VIDEXT_VULKAN if (SDL_Vulkan_LoadLibrary(NULL) == -1) { DebugMessage(M64MSG_ERROR, "SDL_Vulkan_LoadLibrary failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } #else return M64ERR_UNSUPPORTED; #endif } return M64ERR_SUCCESS; } EXPORT m64p_error CALL VidExt_Quit(void) { /* call video extension override if necessary */ if (l_VideoExtensionActive) { m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncQuit)(); if (rval == M64ERR_SUCCESS) { l_VideoOutputActive = 0; StateChanged(M64CORE_VIDEO_MODE, M64VIDEO_NONE); } return rval; } if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; SDL_ShowCursor(SDL_ENABLE); #if SDL_VERSION_ATLEAST(2,0,0) SDL2_DestroyWindow(); #endif #ifdef VIDEXT_VULKAN if (l_RenderMode == M64P_RENDER_VULKAN) { SDL_Vulkan_UnloadLibrary(); } if (l_VulkanExtensionNames != NULL) { free(l_VulkanExtensionNames); l_VulkanExtensionNames = NULL; } #endif SDL_QuitSubSystem(SDL_INIT_VIDEO); l_pScreen = NULL; l_VideoOutputActive = 0; StateChanged(M64CORE_VIDEO_MODE, M64VIDEO_NONE); return M64ERR_SUCCESS; } EXPORT m64p_error CALL VidExt_ListFullscreenModes(m64p_2d_size *SizeArray, int *NumSizes) { const SDL_VideoInfo *videoInfo; unsigned int videoFlags; SDL_Rect **modes; int i; /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncListModes)(SizeArray, NumSizes); if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; /* get a list of SDL video modes */ videoFlags = SDL_OPENGL | SDL_FULLSCREEN; if ((videoInfo = SDL_GetVideoInfo()) == NULL) { DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } if(videoInfo->hw_available) videoFlags |= SDL_HWSURFACE; else videoFlags |= SDL_SWSURFACE; modes = SDL_ListModes(NULL, videoFlags); if (modes == (SDL_Rect **) 0 || modes == (SDL_Rect **) -1) { DebugMessage(M64MSG_WARNING, "No fullscreen SDL video modes available"); *NumSizes = 0; return M64ERR_SUCCESS; } i = 0; while (i < *NumSizes && modes[i] != NULL) { SizeArray[i].uiWidth = modes[i]->w; SizeArray[i].uiHeight = modes[i]->h; i++; } *NumSizes = i; return M64ERR_SUCCESS; } EXPORT m64p_error CALL VidExt_ListFullscreenRates(m64p_2d_size Size, int *NumRates, int *Rates) { /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncListRates)(Size, NumRates, Rates); #if SDL_VERSION_ATLEAST(2,0,0) if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; int display = GetVideoDisplay(); int modeCount = SDL_GetNumDisplayModes(display); SDL_DisplayMode displayMode; if (modeCount < 1) { DebugMessage(M64MSG_ERROR, "SDL_GetNumDisplayModes failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } int rateCount = 0; for (int i = 0; (i < modeCount) && (rateCount < *NumRates); i++) { if (SDL_GetDisplayMode(display, i, &displayMode) < 0) { DebugMessage(M64MSG_ERROR, "SDL_GetDisplayMode failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } /* skip when we're not at the right resolution */ if (displayMode.w != (int)Size.uiWidth || displayMode.h != (int)Size.uiHeight) continue; Rates[rateCount] = displayMode.refresh_rate; rateCount++; } *NumRates = rateCount; return M64ERR_SUCCESS; #else // SDL1 doesn't support getting refresh rates return M64ERR_UNSUPPORTED; #endif } EXPORT m64p_error CALL VidExt_SetVideoMode(int Width, int Height, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags) { const SDL_VideoInfo *videoInfo; int videoFlags = 0; /* call video extension override if necessary */ if (l_VideoExtensionActive) { m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncSetMode)(Width, Height, BitsPerPixel, ScreenMode, Flags); l_Fullscreen = (rval == M64ERR_SUCCESS && ScreenMode == M64VIDEO_FULLSCREEN); l_VideoOutputActive = (rval == M64ERR_SUCCESS); if (l_VideoOutputActive) { StateChanged(M64CORE_VIDEO_MODE, ScreenMode); StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height); } return rval; } if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; /* Get SDL video flags to use */ if (l_RenderMode == M64P_RENDER_OPENGL) { videoFlags = SDL_OPENGL; } #ifdef VIDEXT_VULKAN else { videoFlags = SDL_VULKAN; } #endif if (ScreenMode == M64VIDEO_WINDOWED) { if (Flags & M64VIDEOFLAG_SUPPORT_RESIZING) videoFlags |= SDL_RESIZABLE; } else if (ScreenMode == M64VIDEO_FULLSCREEN) { videoFlags |= SDL_FULLSCREEN; } else { return M64ERR_INPUT_INVALID; } if ((videoInfo = SDL_GetVideoInfo()) == NULL) { DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } if (videoInfo->hw_available) videoFlags |= SDL_HWSURFACE; else videoFlags |= SDL_SWSURFACE; /* set the mode */ if (BitsPerPixel > 0) DebugMessage(M64MSG_INFO, "Setting %i-bit video mode: %ix%i", BitsPerPixel, Width, Height); else DebugMessage(M64MSG_INFO, "Setting video mode: %ix%i", Width, Height); l_pScreen = SDL_SetVideoMode(Width, Height, BitsPerPixel, videoFlags); if (l_pScreen == NULL) { DebugMessage(M64MSG_ERROR, "SDL_SetVideoMode failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } SDL_ShowCursor(SDL_DISABLE); #if SDL_VERSION_ATLEAST(2,0,0) /* set swap interval/VSync */ if (l_RenderMode == M64P_RENDER_OPENGL && SDL_GL_SetSwapInterval(l_SwapControl) != 0) { DebugMessage(M64MSG_ERROR, "SDL swap interval (VSync) set failed: %s", SDL_GetError()); } #endif l_Fullscreen = (ScreenMode == M64VIDEO_FULLSCREEN); l_VideoOutputActive = 1; StateChanged(M64CORE_VIDEO_MODE, ScreenMode); StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height); return M64ERR_SUCCESS; } EXPORT m64p_error CALL VidExt_SetVideoModeWithRate(int Width, int Height, int RefreshRate, int BitsPerPixel, m64p_video_mode ScreenMode, m64p_video_flags Flags) { /* call video extension override if necessary */ if (l_VideoExtensionActive) { m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncSetModeWithRate)(Width, Height, RefreshRate, BitsPerPixel, ScreenMode, Flags); l_Fullscreen = (rval == M64ERR_SUCCESS && ScreenMode == M64VIDEO_FULLSCREEN); l_VideoOutputActive = (rval == M64ERR_SUCCESS); if (l_VideoOutputActive) { StateChanged(M64CORE_VIDEO_MODE, ScreenMode); StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height); } return rval; } #if SDL_VERSION_ATLEAST(2,0,0) if (!SDL_WasInit(SDL_INIT_VIDEO) || !SDL_VideoWindow) return M64ERR_NOT_INIT; int videoFlags = 0; int display = GetVideoDisplay(); int modeCount = SDL_GetNumDisplayModes(display); SDL_DisplayMode displayMode; int modeFound = 0; /* Get SDL video flags to use */ if (ScreenMode == M64VIDEO_WINDOWED) videoFlags = 0; else if (ScreenMode == M64VIDEO_FULLSCREEN) videoFlags = SDL_WINDOW_FULLSCREEN; else return M64ERR_INPUT_INVALID; if (modeCount < 1) { DebugMessage(M64MSG_ERROR, "SDL_GetNumDisplayModes failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } /* Attempt to find valid screen mode */ for (int i = 0; i < modeCount; i++) { if (SDL_GetDisplayMode(display, i, &displayMode) < 0) { DebugMessage(M64MSG_ERROR, "SDL_GetDisplayMode failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } /* skip when we're not at the right mode */ if (displayMode.w != Width || displayMode.h != Height || displayMode.refresh_rate != RefreshRate) continue; modeFound = 1; break; } /* return when no modes with specifed size have been found */ if (modeFound == 0) return M64ERR_INPUT_INVALID; /* Set window in specified mode */ if (SDL_SetWindowFullscreen(SDL_VideoWindow, videoFlags) < 0) { DebugMessage(M64MSG_ERROR, "SDL_SetWindowFullscreen failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } if (ScreenMode == M64VIDEO_FULLSCREEN) { if (SDL_SetWindowDisplayMode(SDL_VideoWindow, &displayMode) < 0) { DebugMessage(M64MSG_ERROR, "SDL_SetWindowDisplayMode failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } } SDL_ShowCursor(SDL_DISABLE); /* set swap interval/VSync */ if (SDL_GL_SetSwapInterval(l_SwapControl) != 0) { DebugMessage(M64MSG_ERROR, "SDL swap interval (VSync) set failed: %s", SDL_GetError()); } l_Fullscreen = (ScreenMode == M64VIDEO_FULLSCREEN); l_VideoOutputActive = 1; StateChanged(M64CORE_VIDEO_MODE, ScreenMode); StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height); return M64ERR_SUCCESS; #else // SDL1 doesn't support setting refresh rates return M64ERR_UNSUPPORTED; #endif } EXPORT m64p_error CALL VidExt_ResizeWindow(int Width, int Height) { const SDL_VideoInfo *videoInfo; int videoFlags = 0; /* call video extension override if necessary */ if (l_VideoExtensionActive) { m64p_error rval; // shut down the OSD osd_exit(); // re-create the OGL context rval = (*l_ExternalVideoFuncTable.VidExtFuncResizeWindow)(Width, Height); if (rval == M64ERR_SUCCESS) { StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height); // re-create the On-Screen Display osd_init(Width, Height); } return rval; } if (!l_VideoOutputActive || !SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; if (l_Fullscreen) { DebugMessage(M64MSG_ERROR, "VidExt_ResizeWindow() called in fullscreen mode."); return M64ERR_INVALID_STATE; } /* Get SDL video flags to use */ if (l_RenderMode == M64P_RENDER_OPENGL) videoFlags = SDL_OPENGL; #ifdef VIDEXT_VULKAN else videoFlags = SDL_VULKAN; #endif videoFlags |= SDL_RESIZABLE; if ((videoInfo = SDL_GetVideoInfo()) == NULL) { DebugMessage(M64MSG_ERROR, "SDL_GetVideoInfo query failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } if (videoInfo->hw_available) videoFlags |= SDL_HWSURFACE; else videoFlags |= SDL_SWSURFACE; // destroy the On-Screen Display osd_exit(); /* set the re-sizing the screen will create a new OpenGL context */ l_pScreen = SDL_SetVideoMode(Width, Height, 0, videoFlags); if (l_pScreen == NULL) { DebugMessage(M64MSG_ERROR, "SDL_SetVideoMode failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } StateChanged(M64CORE_VIDEO_SIZE, (Width << 16) | Height); // re-create the On-Screen Display osd_init(Width, Height); return M64ERR_SUCCESS; } EXPORT m64p_error CALL VidExt_SetCaption(const char *Title) { /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncSetCaption)(Title); if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; SDL_WM_SetCaption(Title, "M64+ Video"); return M64ERR_SUCCESS; } EXPORT m64p_error CALL VidExt_ToggleFullScreen(void) { /* call video extension override if necessary */ if (l_VideoExtensionActive) { m64p_error rval = (*l_ExternalVideoFuncTable.VidExtFuncToggleFS)(); if (rval == M64ERR_SUCCESS) { l_Fullscreen = !l_Fullscreen; StateChanged(M64CORE_VIDEO_MODE, l_Fullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED); } return rval; } if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; /* TODO: * SDL_WM_ToggleFullScreen doesn't work under Windows and others * (see http://wiki.libsdl.org/moin.cgi/FAQWindows for explanation). * Instead, we should call SDL_SetVideoMode with the SDL_FULLSCREEN flag. * (see http://sdl.beuc.net/sdl.wiki/SDL_SetVideoMode), but on Windows * this resets the OpenGL context and video plugins don't support it yet. * Uncomment the next line to test it: */ //return VidExt_SetVideoMode(l_pScreen->w, l_pScreen->h, l_pScreen->format->BitsPerPixel, l_Fullscreen ? M64VIDEO_WINDOWED : M64VIDEO_FULLSCREEN); if (SDL_WM_ToggleFullScreen(l_pScreen) == 1) { l_Fullscreen = !l_Fullscreen; StateChanged(M64CORE_VIDEO_MODE, l_Fullscreen ? M64VIDEO_FULLSCREEN : M64VIDEO_WINDOWED); return M64ERR_SUCCESS; } else { DebugMessage(M64MSG_ERROR, "SDL_WM_ToggleFullScreen failed: %s", SDL_GetError()); } return M64ERR_SYSTEM_FAIL; } EXPORT m64p_function CALL VidExt_GL_GetProcAddress(const char* Proc) { /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncGLGetProc)(Proc); if (l_RenderMode != M64P_RENDER_OPENGL) return NULL; if (!SDL_WasInit(SDL_INIT_VIDEO)) return NULL; /* WARN: assume cast to m64p_function is supported by platform and disable warning accordingly */ OSAL_WARNING_PUSH OSAL_NO_WARNING_FPTR_VOIDP_CAST return (m64p_function)SDL_GL_GetProcAddress(Proc); OSAL_WARNING_POP } typedef struct { m64p_GLattr m64Attr; SDL_GLattr sdlAttr; } GLAttrMapNode; static const GLAttrMapNode GLAttrMap[] = { { M64P_GL_DOUBLEBUFFER, SDL_GL_DOUBLEBUFFER }, { M64P_GL_BUFFER_SIZE, SDL_GL_BUFFER_SIZE }, { M64P_GL_DEPTH_SIZE, SDL_GL_DEPTH_SIZE }, { M64P_GL_RED_SIZE, SDL_GL_RED_SIZE }, { M64P_GL_GREEN_SIZE, SDL_GL_GREEN_SIZE }, { M64P_GL_BLUE_SIZE, SDL_GL_BLUE_SIZE }, { M64P_GL_ALPHA_SIZE, SDL_GL_ALPHA_SIZE }, #if !SDL_VERSION_ATLEAST(1,3,0) { M64P_GL_SWAP_CONTROL, SDL_GL_SWAP_CONTROL }, #endif { M64P_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLEBUFFERS }, { M64P_GL_MULTISAMPLESAMPLES, SDL_GL_MULTISAMPLESAMPLES } #if SDL_VERSION_ATLEAST(2,0,0) ,{ M64P_GL_CONTEXT_MAJOR_VERSION, SDL_GL_CONTEXT_MAJOR_VERSION }, { M64P_GL_CONTEXT_MINOR_VERSION, SDL_GL_CONTEXT_MINOR_VERSION }, { M64P_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_MASK } #endif }; static const int mapSize = sizeof(GLAttrMap) / sizeof(GLAttrMapNode); EXPORT m64p_error CALL VidExt_GL_SetAttribute(m64p_GLattr Attr, int Value) { int i; /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncGLSetAttr)(Attr, Value); if (l_RenderMode != M64P_RENDER_OPENGL) return M64ERR_INVALID_STATE; if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; if (Attr == M64P_GL_SWAP_CONTROL) { /* SDL swap interval/vsync needs to be set on current GL context, so save it for later */ l_SwapControl = Value; } /* translate the GL context type mask if necessary */ #if SDL_VERSION_ATLEAST(2,0,0) if (Attr == M64P_GL_CONTEXT_PROFILE_MASK) { switch (Value) { case M64P_GL_CONTEXT_PROFILE_CORE: Value = SDL_GL_CONTEXT_PROFILE_CORE; #ifndef USE_GLES l_ForceCompatibilityContext = 0; #endif break; case M64P_GL_CONTEXT_PROFILE_COMPATIBILITY: Value = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; break; case M64P_GL_CONTEXT_PROFILE_ES: Value = SDL_GL_CONTEXT_PROFILE_ES; break; default: Value = 0; } } #endif for (i = 0; i < mapSize; i++) { if (GLAttrMap[i].m64Attr == Attr) { if (SDL_GL_SetAttribute(GLAttrMap[i].sdlAttr, Value) != 0) return M64ERR_SYSTEM_FAIL; return M64ERR_SUCCESS; } } return M64ERR_INPUT_INVALID; } EXPORT m64p_error CALL VidExt_GL_GetAttribute(m64p_GLattr Attr, int *pValue) { int i; /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncGLGetAttr)(Attr, pValue); if (l_RenderMode != M64P_RENDER_OPENGL) return M64ERR_INVALID_STATE; if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; #if SDL_VERSION_ATLEAST(2,0,0) if (Attr == M64P_GL_SWAP_CONTROL) { *pValue = SDL_GL_GetSwapInterval(); return M64ERR_SUCCESS; } #endif for (i = 0; i < mapSize; i++) { if (GLAttrMap[i].m64Attr == Attr) { int NewValue = 0; if (SDL_GL_GetAttribute(GLAttrMap[i].sdlAttr, &NewValue) != 0) return M64ERR_SYSTEM_FAIL; /* translate the GL context type mask if necessary */ #if SDL_VERSION_ATLEAST(2,0,0) if (Attr == M64P_GL_CONTEXT_PROFILE_MASK) { switch (NewValue) { case SDL_GL_CONTEXT_PROFILE_CORE: NewValue = M64P_GL_CONTEXT_PROFILE_CORE; break; case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY: NewValue = M64P_GL_CONTEXT_PROFILE_COMPATIBILITY; break; case SDL_GL_CONTEXT_PROFILE_ES: NewValue = M64P_GL_CONTEXT_PROFILE_ES; break; default: NewValue = 0; } } #endif *pValue = NewValue; return M64ERR_SUCCESS; } } return M64ERR_INPUT_INVALID; } EXPORT m64p_error CALL VidExt_GL_SwapBuffers(void) { /* call video extension override if necessary */ if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncGLSwapBuf)(); if (l_RenderMode != M64P_RENDER_OPENGL) return M64ERR_INVALID_STATE; if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; SDL_GL_SwapBuffers(); return M64ERR_SUCCESS; } EXPORT uint32_t CALL VidExt_GL_GetDefaultFramebuffer(void) { if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncGLGetDefaultFramebuffer)(); return 0; } EXPORT m64p_error CALL VidExt_VK_GetSurface(void** Surface, void* Instance) { if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncVKGetSurface)(Surface, Instance); #ifdef VIDEXT_VULKAN VkSurfaceKHR vulkanSurface = VK_NULL_HANDLE; if (l_RenderMode != M64P_RENDER_VULKAN) return M64ERR_INVALID_STATE; if (!SDL_WasInit(SDL_INIT_VIDEO) || !SDL_VideoWindow) return M64ERR_NOT_INIT; if (SDL_Vulkan_CreateSurface(SDL_VideoWindow, (VkInstance)Instance, &vulkanSurface) == SDL_FALSE) { DebugMessage(M64MSG_ERROR, "SDL_Vulkan_CreateSurface failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } *Surface = (void*)vulkanSurface; return M64ERR_SUCCESS; #else return M64ERR_UNSUPPORTED; #endif } EXPORT m64p_error CALL VidExt_VK_GetInstanceExtensions(const char** Extensions[], uint32_t* NumExtensions) { if (l_VideoExtensionActive) return (*l_ExternalVideoFuncTable.VidExtFuncVKGetInstanceExtensions)(Extensions, NumExtensions); #ifdef VIDEXT_VULKAN if (l_RenderMode != M64P_RENDER_VULKAN) return M64ERR_INVALID_STATE; if (!SDL_WasInit(SDL_INIT_VIDEO)) return M64ERR_NOT_INIT; unsigned int extensionCount = 0; if (SDL_Vulkan_GetInstanceExtensions(NULL, &extensionCount, NULL) == SDL_FALSE) { DebugMessage(M64MSG_ERROR, "SDL_Vulkan_GetInstanceExtensions failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } /* ensure names have been freed before allocating it again */ if (l_VulkanExtensionNames != NULL) { free(l_VulkanExtensionNames); l_VulkanExtensionNames = NULL; } l_VulkanExtensionNames = malloc(sizeof(const char*) * extensionCount); if (l_VulkanExtensionNames == NULL) { DebugMessage(M64MSG_ERROR, "malloc failed"); return M64ERR_SYSTEM_FAIL; } if (SDL_Vulkan_GetInstanceExtensions(NULL, &extensionCount, l_VulkanExtensionNames) == SDL_FALSE) { DebugMessage(M64MSG_ERROR, "SDL_Vulkan_GetInstanceExtensions failed: %s", SDL_GetError()); return M64ERR_SYSTEM_FAIL; } *NumExtensions = extensionCount; *Extensions = l_VulkanExtensionNames; return M64ERR_SUCCESS; #else return M64ERR_UNSUPPORTED; #endif } mupen64plus-core-src-2.6.0/src/api/vidext.h000066400000000000000000000040151464506436200204620ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - api/vidext.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the video extension functions which * will be called from other Core modules. */ #if !defined(API_VIDEXT_H) #define API_VIDEXT_H #include "m64p_types.h" /* global function for use by frontend.c */ extern m64p_error OverrideVideoFunctions(m64p_video_extension_functions *VideoFunctionStruct); /* these functions are only used by the core */ extern int VidExt_InFullscreenMode(void); extern int VidExt_VideoRunning(void); #endif /* API_VIDEXT_H */ mupen64plus-core-src-2.6.0/src/api/vidext_sdl2_compat.h000066400000000000000000000337651464506436200227670ustar00rootroot00000000000000/* Simple DirectMedia Layer Copyright (C) 1997-2012 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #include #ifndef USE_GLES #ifndef SDL_VIDEO_OPENGL #error SDL is not build with OpenGL support. Try USE_GLES=1 #endif #else // !USE_GLES #ifndef SDL_VIDEO_OPENGL_ES2 #error SDL is not build with OpenGL ES2 support. Try USE_GLES=0 #endif #endif // !USE_GLES typedef struct SDL_VideoInfo { Uint32 hw_available:1; Uint32 wm_available:1; Uint32 UnusedBits1:6; Uint32 UnusedBits2:1; Uint32 blit_hw:1; Uint32 blit_hw_CC:1; Uint32 blit_hw_A:1; Uint32 blit_sw:1; Uint32 blit_sw_CC:1; Uint32 blit_sw_A:1; Uint32 blit_fill:1; Uint32 UnusedBits3:16; Uint32 video_mem; SDL_PixelFormat *vfmt; int current_w; int current_h; } SDL_VideoInfo; #define SDL_FULLSCREEN 0x00800000 #define SDL_RESIZABLE 0x01000000 #define SDL_NOFRAME 0x02000000 #define SDL_OPENGL 0x04000000 #define SDL_VULKAN 0x10000000 #define SDL_HWSURFACE 0x08000001 /**< \note Not used */ #define SDL_BUTTON_WHEELUP 4 #define SDL_BUTTON_WHEELDOWN 5 int initialized_video = 0; static SDL_Window *SDL_VideoWindow = NULL; static SDL_Surface *SDL_VideoSurface = NULL; static SDL_Surface *SDL_PublicSurface = NULL; static SDL_Rect SDL_VideoViewport; static char *wm_title = NULL; static Uint32 SDL_VideoFlags = 0; static SDL_GLContext *SDL_VideoContext = NULL; static SDL_Surface *SDL_VideoIcon; static void SDL_WM_SetCaption(const char *title, const char *icon) { if (wm_title) { SDL_free(wm_title); } if (title) { wm_title = SDL_strdup(title); } else { wm_title = NULL; } SDL_SetWindowTitle(SDL_VideoWindow, wm_title); } static int GetVideoDisplay() { const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY"); if ( !variable ) { variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD"); } if ( variable ) { return SDL_atoi(variable); } else { return 0; } } static const SDL_VideoInfo * SDL_GetVideoInfo(void) { static SDL_VideoInfo info; SDL_DisplayMode mode; /* Memory leak, compatibility code, who cares? */ if (!info.vfmt && SDL_GetDesktopDisplayMode(GetVideoDisplay(), &mode) == 0) { info.vfmt = SDL_AllocFormat(mode.format); info.current_w = mode.w; info.current_h = mode.h; } return &info; } static SDL_Rect ** SDL_ListModes(const SDL_PixelFormat * format, Uint32 flags) { int i, nmodes; SDL_Rect **modes; if (!initialized_video) { return NULL; } if (!(flags & SDL_FULLSCREEN)) { return (SDL_Rect **) (-1); } if (!format) { format = SDL_GetVideoInfo()->vfmt; } /* Memory leak, but this is a compatibility function, who cares? */ nmodes = 0; modes = NULL; for (i = 0; i < SDL_GetNumDisplayModes(GetVideoDisplay()); ++i) { SDL_DisplayMode mode; int bpp; SDL_GetDisplayMode(GetVideoDisplay(), i, &mode); if (!mode.w || !mode.h) { return (SDL_Rect **) (-1); } /* Copied from src/video/SDL_pixels.c:SDL_PixelFormatEnumToMasks */ if (SDL_BYTESPERPIXEL(mode.format) <= 2) { bpp = SDL_BITSPERPIXEL(mode.format); } else { bpp = SDL_BYTESPERPIXEL(mode.format) * 8; } if (bpp != format->BitsPerPixel) { continue; } if (nmodes > 0 && modes[nmodes - 1]->w == mode.w && modes[nmodes - 1]->h == mode.h) { continue; } modes = SDL_realloc(modes, (nmodes + 2) * sizeof(*modes)); if (!modes) { return NULL; } modes[nmodes] = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect)); if (!modes[nmodes]) { return NULL; } modes[nmodes]->x = 0; modes[nmodes]->y = 0; modes[nmodes]->w = mode.w; modes[nmodes]->h = mode.h; ++nmodes; } if (modes) { modes[nmodes] = NULL; } return modes; } static void SDL_GL_SwapBuffers(void) { SDL_GL_SwapWindow(SDL_VideoWindow); } static int SDL_WM_ToggleFullScreen(SDL_Surface * surface) { int window_w; int window_h; if ( #ifdef VIDEXT_VULKAN (SDL_VideoFlags & SDL_VULKAN && !SDL_VideoWindow) || #endif (SDL_VideoFlags & SDL_OPENGL && !SDL_PublicSurface)) { SDL_SetError("SDL_SetVideoMode() hasn't been called"); return 0; } /* Do the physical mode switch */ if (SDL_GetWindowFlags(SDL_VideoWindow) & SDL_WINDOW_FULLSCREEN) { if (SDL_SetWindowFullscreen(SDL_VideoWindow, 0) < 0) { return 0; } if (SDL_VideoFlags & SDL_OPENGL) { SDL_PublicSurface->flags &= ~SDL_FULLSCREEN; } } else { if (SDL_SetWindowFullscreen(SDL_VideoWindow, 1) < 0) { return 0; } if (SDL_VideoFlags & SDL_OPENGL) { SDL_PublicSurface->flags |= SDL_FULLSCREEN; } } /* Center the public surface in the window surface */ SDL_GetWindowSize(SDL_VideoWindow, &window_w, &window_h); SDL_VideoViewport.x = 0; SDL_VideoViewport.y = 0; SDL_VideoViewport.w = window_w; SDL_VideoViewport.h = window_h; /* We're done! */ return 1; } static int SDL_ResizeVideoMode(int width, int height, int bpp, Uint32 flags) { int w, h; /* We can't resize something we don't have... */ if ( #ifdef VIDEXT_VULKAN (SDL_VideoFlags & SDL_VULKAN && !SDL_VideoWindow) || #endif (SDL_VideoFlags & SDL_OPENGL && !SDL_PublicSurface)) { return -1; } /* We probably have to recreate the window in fullscreen mode */ if (flags & SDL_FULLSCREEN) { return -1; } /* I don't think there's any change we can gracefully make in flags */ if (flags != SDL_VideoFlags) { return -1; } if (bpp != SDL_VideoSurface->format->BitsPerPixel) { return -1; } /* Resize the window */ SDL_GetWindowSize(SDL_VideoWindow, &w, &h); if (w != width || h != height) { SDL_SetWindowSize(SDL_VideoWindow, width, height); } SDL_VideoSurface->w = width; SDL_VideoSurface->h = height; return 0; } static int SDL_CompatEventFilter(void *userdata, SDL_Event * event) { SDL_Event fake; switch (event->type) { case SDL_WINDOWEVENT: switch (event->window.event) { case SDL_WINDOWEVENT_CLOSE: fake.type = SDL_QUIT; SDL_PushEvent(&fake); break; } case SDL_TEXTINPUT: { /* FIXME: Generate an old style key repeat event if needed */ //printf("TEXTINPUT: '%s'\n", event->text.text); break; } case SDL_MOUSEMOTION: { event->motion.x -= SDL_VideoViewport.x; event->motion.y -= SDL_VideoViewport.y; break; } case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { event->button.x -= SDL_VideoViewport.x; event->button.y -= SDL_VideoViewport.y; break; } case SDL_MOUSEWHEEL: { Uint8 button; int x, y; if (event->wheel.y == 0) { break; } SDL_GetMouseState(&x, &y); if (event->wheel.y > 0) { button = SDL_BUTTON_WHEELUP; } else { button = SDL_BUTTON_WHEELDOWN; } fake.button.button = button; fake.button.x = x; fake.button.y = y; fake.button.windowID = event->wheel.windowID; fake.type = SDL_MOUSEBUTTONDOWN; fake.button.state = SDL_PRESSED; SDL_PushEvent(&fake); fake.type = SDL_MOUSEBUTTONUP; fake.button.state = SDL_RELEASED; SDL_PushEvent(&fake); break; } } return 1; } static void GetEnvironmentWindowPosition(int w, int h, int *x, int *y) { int display = GetVideoDisplay(); const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS"); const char *center = SDL_getenv("SDL_VIDEO_CENTERED"); if (window) { if (SDL_sscanf(window, "%d,%d", x, y) == 2) { return; } if (SDL_strcmp(window, "center") == 0) { center = window; } } if (center) { *x = SDL_WINDOWPOS_CENTERED_DISPLAY(display); *y = SDL_WINDOWPOS_CENTERED_DISPLAY(display); } } static void SDL2_DestroyWindow(void) { /* Destroy existing window */ SDL_PublicSurface = NULL; if (SDL_VideoSurface) { SDL_VideoSurface->flags &= ~SDL_DONTFREE; SDL_FreeSurface(SDL_VideoSurface); SDL_VideoSurface = NULL; } if (SDL_VideoContext) { /* SDL_GL_MakeCurrent(0, NULL); *//* Doesn't do anything */ SDL_GL_DeleteContext(SDL_VideoContext); SDL_VideoContext = NULL; } if (SDL_VideoWindow) { SDL_DestroyWindow(SDL_VideoWindow); SDL_VideoWindow = NULL; } } static SDL_Surface * SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) { SDL_DisplayMode desktop_mode; int display = GetVideoDisplay(); int window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display); int window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display); Uint32 window_flags; Uint32 surface_flags; if (!initialized_video) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) { return NULL; } initialized_video = 1; } SDL_GetDesktopDisplayMode(display, &desktop_mode); if (width == 0) { width = desktop_mode.w; } if (height == 0) { height = desktop_mode.h; } if (bpp == 0) { bpp = SDL_BITSPERPIXEL(desktop_mode.format); } /* See if we can simply resize the existing window and surface */ if (SDL_ResizeVideoMode(width, height, bpp, flags) == 0) { return SDL_PublicSurface; } /* Destroy existing window */ if (SDL_VideoWindow) SDL_GetWindowPosition(SDL_VideoWindow, &window_x, &window_y); SDL2_DestroyWindow(); /* Set up the event filter */ if (!SDL_GetEventFilter(NULL, NULL)) { SDL_SetEventFilter(SDL_CompatEventFilter, NULL); } #ifndef USE_GLES if (flags & SDL_OPENGL && l_ForceCompatibilityContext) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); } #else // !USE_GLES if (flags & SDL_OPENGL) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); } #endif // !USE_GLES /* Create a new window */ window_flags = SDL_WINDOW_SHOWN; if (flags & SDL_FULLSCREEN) { window_flags |= SDL_WINDOW_FULLSCREEN; } if (flags & SDL_OPENGL) { window_flags |= SDL_WINDOW_OPENGL; } #ifdef VIDEXT_VULKAN if (flags & SDL_VULKAN) { window_flags |= SDL_WINDOW_VULKAN; } #endif if (flags & SDL_RESIZABLE) { window_flags |= SDL_WINDOW_RESIZABLE; } if (flags & SDL_NOFRAME) { window_flags |= SDL_WINDOW_BORDERLESS; } GetEnvironmentWindowPosition(width, height, &window_x, &window_y); SDL_VideoWindow = SDL_CreateWindow(wm_title, window_x, window_y, width, height, window_flags); if (!SDL_VideoWindow) { return NULL; } SDL_SetWindowIcon(SDL_VideoWindow, SDL_VideoIcon); window_flags = SDL_GetWindowFlags(SDL_VideoWindow); surface_flags = 0; if (window_flags & SDL_WINDOW_FULLSCREEN) { surface_flags |= SDL_FULLSCREEN; } if ((window_flags & SDL_WINDOW_OPENGL) && (flags & SDL_OPENGL)) { surface_flags |= SDL_OPENGL; } #ifdef VIDEXT_VULKAN if ((window_flags & SDL_WINDOW_VULKAN) && (flags & SDL_VULKAN)) { surface_flags |= SDL_VULKAN; } #endif if (window_flags & SDL_WINDOW_RESIZABLE) { surface_flags |= SDL_RESIZABLE; } if (window_flags & SDL_WINDOW_BORDERLESS) { surface_flags |= SDL_NOFRAME; } SDL_VideoFlags = flags; /* If we're in OpenGL mode, just create a stub surface and we're done! */ if (flags & SDL_OPENGL) { SDL_VideoContext = SDL_GL_CreateContext(SDL_VideoWindow); if (!SDL_VideoContext) { return NULL; } if (SDL_GL_MakeCurrent(SDL_VideoWindow, SDL_VideoContext) < 0) { return NULL; } /* Pitch: size of of line in bytes */ /* Add 7 to bpp before division, to ensure correct rounding towards infinity * in cases where bits per pixel do not cleanly divide by 8 (such as 15) */ int pitch = (bpp + 7) / 8 * width; SDL_VideoSurface = SDL_CreateRGBSurfaceFrom(NULL, width, height, bpp, pitch, 0, 0, 0, 0); if (!SDL_VideoSurface) { return NULL; } SDL_VideoSurface->flags |= surface_flags; SDL_PublicSurface = SDL_VideoSurface; return SDL_PublicSurface; } #ifdef VIDEXT_VULKAN else if (flags & SDL_VULKAN) { /* Vulkan doesn't have a video surface, * so just return a stub */ return (SDL_Surface*)0x1; } #endif /* We're finally done! */ return NULL; } mupen64plus-core-src-2.6.0/src/asm_defines/000077500000000000000000000000001464506436200205125ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/asm_defines/asm_defines.c000066400000000000000000000125511464506436200231370ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - asm_defines.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * This file is to be compiled with the same compilation flags as the * mupen64plus-core, but without LTO / Global Optimizations * (those tends to inhibit effective creation of required symbols). * It's purpose is to help generate asm_defines headers * suitable for inclusion in assembly files. * This allow to effectively share struct definitions between C and assembly * files. */ #include "device/device.h" #include "device/r4300/new_dynarec/new_dynarec.h" #include "device/r4300/r4300_core.h" #include #define HEX(n) ((n) >= 10 ? ('a' + ((n) - 10)) : ('0' + (n))) /* Creates a structure whose bytes form a string like * "\n@ASM_DEFINE offsetof_blah_blah 0xdeadbeef\n" * * This should appear somewhere in the object file, and is distinctive enough * that it shouldn't appear by chance. Thus we can pipe the object file * directly to awk, and extract the values without having to use * platform-specific tools (e.g. objdump, dumpbin, nm). */ #define _DEFINE(str, sym, val) \ const struct { \ char before[sizeof(str)-1]; \ char hexval[8]; \ char after; \ char ensure_32bit[(val) > UINT64_C(0xffffffff) ? -1 : 1]; \ } sym = { \ str, \ { \ HEX(((val) >> 28) & 0xf), \ HEX(((val) >> 24) & 0xf), \ HEX(((val) >> 20) & 0xf), \ HEX(((val) >> 16) & 0xf), \ HEX(((val) >> 12) & 0xf), \ HEX(((val) >> 8) & 0xf), \ HEX(((val) >> 4) & 0xf), \ HEX(((val) >> 0) & 0xf) \ }, \ '\n', \ {0} \ } /* Export member m of structure s. * Suitable parsing of corresponding object file (with strings) can be used to * generate header suitable for inclusion in assembly files. */ #define DEFINE(s, m) \ _DEFINE("\n@ASM_DEFINE offsetof_struct_" #s "_" #m " 0x", \ __offsetof_struct_##s##_##m, \ offsetof(struct s, m)) /* Structure members definitions */ DEFINE(device, r4300); #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ DEFINE(r4300_core, regs); DEFINE(r4300_core, hi); DEFINE(r4300_core, lo); DEFINE(r4300_core, stop); #endif #if !defined(NEW_DYNAREC) DEFINE(r4300_core, recomp); #if defined(__x86_64__) DEFINE(recomp, save_rsp); DEFINE(recomp, save_rip); #else DEFINE(recomp, save_ebp); DEFINE(recomp, save_esp); DEFINE(recomp, save_ebx); DEFINE(recomp, save_esi); DEFINE(recomp, save_edi); DEFINE(recomp, save_eip); #endif DEFINE(recomp, return_address); #endif /* !NEW_DYNAREC */ DEFINE(r4300_core, cp0); #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ DEFINE(cp0, regs); DEFINE(cp0, next_interrupt); #endif DEFINE(cp0, last_addr); DEFINE(cp0, count_per_op); DEFINE(cp0, tlb); DEFINE(tlb, entries); DEFINE(tlb, LUT_r); DEFINE(tlb, LUT_w); DEFINE(r4300_core, cached_interp); DEFINE(cached_interp, invalid_code); #ifdef NEW_DYNAREC DEFINE(r4300_core, new_dynarec_hot_state); DEFINE(r4300_core, extra_memory); DEFINE(new_dynarec_hot_state, dynarec_local); DEFINE(new_dynarec_hot_state, cycle_count); DEFINE(new_dynarec_hot_state, pending_exception); DEFINE(new_dynarec_hot_state, pcaddr); DEFINE(new_dynarec_hot_state, stop); DEFINE(new_dynarec_hot_state, invc_ptr); DEFINE(new_dynarec_hot_state, cp1_fcr0); DEFINE(new_dynarec_hot_state, cp1_fcr31); DEFINE(new_dynarec_hot_state, regs); DEFINE(new_dynarec_hot_state, hi); DEFINE(new_dynarec_hot_state, lo); DEFINE(new_dynarec_hot_state, cp0_regs); DEFINE(new_dynarec_hot_state, cp1_regs_simple); DEFINE(new_dynarec_hot_state, cp1_regs_double); DEFINE(new_dynarec_hot_state, rounding_modes); DEFINE(new_dynarec_hot_state, branch_target); DEFINE(new_dynarec_hot_state, pc); DEFINE(new_dynarec_hot_state, fake_pc); DEFINE(new_dynarec_hot_state, rs); DEFINE(new_dynarec_hot_state, rt); DEFINE(new_dynarec_hot_state, rd); DEFINE(new_dynarec_hot_state, mini_ht); DEFINE(new_dynarec_hot_state, memory_map); #endif mupen64plus-core-src-2.6.0/src/backends/000077500000000000000000000000001464506436200200075ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/backends/api/000077500000000000000000000000001464506436200205605ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/backends/api/audio_out_backend.h000066400000000000000000000036551464506436200244010ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - audio_out_backend.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_API_AUDIO_OUT_BACKEND_H #define M64P_BACKENDS_API_AUDIO_OUT_BACKEND_H #include struct audio_out_backend_interface { /* Allow the backend to be notified of sample frequency. */ void (*set_frequency)(void* aout, unsigned int frequency); /* Push samples to be played by the backend */ void (*push_samples)(void* aout, const void* samples, size_t size); }; #endif mupen64plus-core-src-2.6.0/src/backends/api/clock_backend.h000066400000000000000000000033471464506436200235020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - clock_backend.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_API_CLOCK_BACKEND_H #define M64P_BACKENDS_API_CLOCK_BACKEND_H #include struct clock_backend_interface { /* Returns the current time */ time_t (*get_time)(void* clock); }; #endif mupen64plus-core-src-2.6.0/src/backends/api/controller_input_backend.h000066400000000000000000000052101464506436200260000ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - controller_input_backend.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_API_CONTROLLER_INPUT_BACKEND_H #define M64P_BACKENDS_API_CONTROLLER_INPUT_BACKEND_H #include "api/m64p_types.h" #include enum standard_controller_input { CI_STD_R_DPAD = 0x0001, CI_STD_L_DPAD = 0x0002, CI_STD_D_DPAD = 0x0004, CI_STD_U_DPAD = 0x0008, CI_STD_START = 0x0010, CI_STD_Z = 0x0020, CI_STD_B = 0x0040, CI_STD_A = 0x0080, CI_STD_R_CBTN = 0x0100, CI_STD_L_CBTN = 0x0200, CI_STD_D_CBTN = 0x0400, CI_STD_U_CBTN = 0x0800, CI_STD_R = 0x1000, CI_STD_L = 0x2000, /* bits 14 and 15 are reserved */ /* bits 23-16 are for X-axis */ /* bits 31-24 are for Y-axis */ }; enum mouse_controller_input { CI_MOUSE_RIGHT = 0x0040, CI_MOUSE_LEFT = 0x0080, /* bits 23-16 are for X-axis */ /* bits 31-24 are for Y-axis */ }; struct controller_input_backend_interface { /* Get emulated controller input status (32-bit) * Encoding of the input status depends on the emulated controller flavor. * Returns M64ERR_SUCCESS on success */ m64p_error (*get_input)(void* cin, uint32_t* input); }; #endif mupen64plus-core-src-2.6.0/src/backends/api/joybus.h000066400000000000000000000066021464506436200222500ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - joybus.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_API_JOYBUS_H #define M64P_BACKENDS_API_JOYBUS_H #include enum joybus_commands { JCMD_STATUS = 0x00, JCMD_CONTROLLER_READ = 0x01, JCMD_PAK_READ = 0x02, JCMD_PAK_WRITE = 0x03, JCMD_EEPROM_READ = 0x04, JCMD_EEPROM_WRITE = 0x05, JCMD_AF_RTC_STATUS = 0x06, JCMD_AF_RTC_READ = 0x07, JCMD_AF_RTC_WRITE = 0x08, JCMD_VRU_READ = 0x09, JCMD_VRU_WRITE = 0x0A, JCMD_VRU_READ_STATUS = 0x0B, JCMD_VRU_WRITE_CONFIG = 0x0C, JCMD_VRU_WRITE_INIT = 0x0D, JCMD_RESET = 0xff, }; enum joybus_device_types { JDT_NONE = 0x0000, JDT_JOY_ABS_COUNTERS = 0x0001, /* joystick with absolute coordinates */ JDT_JOY_REL_COUNTERS = 0x0002, /* joystick with relative coordinates (= mouse) */ JDT_JOY_PORT = 0x0004, /* has port for external paks */ JDT_VRU = 0x0100, /* VRU */ JDT_AF_RTC = 0x1000, /* RTC */ JDT_EEPROM_4K = 0x8000, /* 4k EEPROM */ JDT_EEPROM_16K = 0xc000, /* 16k EEPROM */ }; /* snippet which helps validate command format */ #define JOYBUS_CHECK_COMMAND_FORMAT(expected_tx, expected_rx) \ if (*tx != expected_tx || *rx != expected_rx) { \ DebugMessage(M64MSG_WARNING, "Unexpected command format %02x %02x %02x ", \ *tx, *rx, cmd); \ *rx |= 0x40; \ break; \ } struct joybus_device_interface { /* Optional. Called at device poweron. * Allow the joybus device to initialze itself. */ void (*poweron)(void* jbd); /* Required. Perform command processing. */ void (*process)(void* jbd, const uint8_t* tx, const uint8_t* tx_buf, uint8_t* rx, uint8_t* rx_buf); /* Optional. Called after channel setup. */ void (*post_setup)(void* jbd, uint8_t* tx, const uint8_t* tx_buf, const uint8_t* rx, const uint8_t* rx_buf); }; #endif mupen64plus-core-src-2.6.0/src/backends/api/rumble_backend.h000066400000000000000000000034731464506436200236750ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rumble_backend.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_API_RUMBLE_BACKEND_H #define M64P_BACKENDS_API_RUMBLE_BACKEND_H #include enum rumble_action { RUMBLE_STOP, RUMBLE_START }; struct rumble_backend_interface { /* Start or stop rumbling */ void (*exec)(void* rumble, enum rumble_action action); }; #endif mupen64plus-core-src-2.6.0/src/backends/api/storage_backend.h000066400000000000000000000037601464506436200240520ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - storage_backend.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_API_STORAGE_BACKEND_H #define M64P_BACKENDS_API_STORAGE_BACKEND_H #include #include struct storage_backend_interface { /* Returns a pointer to storage data */ uint8_t* (*data)(const void* storage); /* Returns the size of the storage */ size_t (*size)(const void* storage); /* Notify the storage backend that data should be persisted */ void (*save)(void* storage, size_t start, size_t size); }; #endif mupen64plus-core-src-2.6.0/src/backends/api/video_capture_backend.c000066400000000000000000000050661464506436200252330ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - video_capture_backend.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2018 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "video_capture_backend.h" #include /* exported video capture backends */ extern const struct video_capture_backend_interface g_idummy_video_capture_backend; #if defined(M64P_OPENCV) extern const struct video_capture_backend_interface g_iopencv_video_capture_backend; #endif const struct video_capture_backend_interface* g_video_capture_backend_interfaces[] = { #if defined(M64P_OPENCV) &g_iopencv_video_capture_backend, #endif &g_idummy_video_capture_backend, NULL /* sentinel - must be last element */ }; const struct video_capture_backend_interface* get_video_capture_backend(const char* name) { const struct video_capture_backend_interface** i; /* passing NULL or empty string gives the dummy video input backend interface */ if (!name || strlen(name) == 0) { return &g_idummy_video_capture_backend; } /* iterate through interfaces to find matching name */ for (i = g_video_capture_backend_interfaces; (*i) != NULL; ++i) { if (strcmp((*i)->name, name) == 0) { return (*i); } } return NULL; } mupen64plus-core-src-2.6.0/src/backends/api/video_capture_backend.h000066400000000000000000000062201464506436200252310ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - video_capture_backend.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_API_VIDEO_CAPTURE_BACKEND_H #define M64P_BACKENDS_API_VIDEO_CAPTURE_BACKEND_H #include "api/m64p_types.h" /* Define default video capture backend * if not defined by Makefile/msvc */ #if !defined(DEFAULT_VIDEO_CAPTURE_BACKEND) #if defined(M64P_OPENCV) #define DEFAULT_VIDEO_CAPTURE_BACKEND "opencv" #else #define DEFAULT_VIDEO_CAPTURE_BACKEND "" #endif #endif struct video_capture_backend_interface { /* Backend class name. * Must be unique. */ const char* name; /* Initialize backend instance (*vin) * using (when provided) parameters from config section. * * Returns M64ERR_SUCCESS on success. * * You must call corresponding release method to release any allocated resources. */ m64p_error (*init)(void** vin, const char* section); /* Release backend instance and any associated resouces. */ void (*release)(void* vin); /* Open a video stream with following properties (width, height) * Returns M64ERR_SUCCESS on success. */ m64p_error (*open)(void* vin, unsigned int width, unsigned int height); /* Close a previsouly opened video stream. */ void (*close)(void* vin); /* Grab a BGR image on an open stream * Returns M64ERR_SUCCESS on success. */ m64p_error (*grab_image)(void* vin, void* data); }; /* collection of available video capture backends */ extern const struct video_capture_backend_interface* g_video_capture_backend_interfaces[]; /* helper function which find backend by name (or dummy when NULL/empty) */ const struct video_capture_backend_interface* get_video_capture_backend(const char* name); #endif mupen64plus-core-src-2.6.0/src/backends/clock_ctime_plus_delta.c000066400000000000000000000035121464506436200246440ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - get_time_using_time_plus_delta.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "clock_ctime_plus_delta.h" #include time_t ctime_plus_delta_get_time(void* clock) { time_t user_delta = (clock == NULL) ? 0 : *(time_t*)clock; return user_delta + time(NULL); } const struct clock_backend_interface g_iclock_ctime_plus_delta = { ctime_plus_delta_get_time }; mupen64plus-core-src-2.6.0/src/backends/clock_ctime_plus_delta.h000066400000000000000000000033351464506436200246540ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - clock_ctime_plus_delta.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_CLOCK_CTIME_PLUS_DELTA_H #define M64P_BACKENDS_CLOCK_CTIME_PLUS_DELTA_H #include "backends/api/clock_backend.h" extern const struct clock_backend_interface g_iclock_ctime_plus_delta; #endif mupen64plus-core-src-2.6.0/src/backends/dummy_video_capture.c000066400000000000000000000055151464506436200242250ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_video_capture.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "backends/api/video_capture_backend.h" #include #include /* Dummy video capture backend * * Returns a black frame */ struct dummy_video_capture { /* BGR frame size (no stride) */ size_t size; }; static m64p_error dummy_init(void** vcap, const char* config) { struct dummy_video_capture* dummy = malloc(sizeof(*dummy)); if (dummy == NULL) { *vcap = NULL; return M64ERR_NO_MEMORY; } memset(dummy, 0, sizeof(*dummy)); *vcap = dummy; return M64ERR_SUCCESS; } static void dummy_release(void* vcap) { free(vcap); } static m64p_error dummy_open(void* vcap, unsigned int width, unsigned int height) { struct dummy_video_capture* dummy = (struct dummy_video_capture*)vcap; dummy->size = 3 * width * height; return M64ERR_SUCCESS; } static void dummy_close(void* vcap) { struct dummy_video_capture* dummy = (struct dummy_video_capture*)vcap; dummy->size = 0; } static m64p_error dummy_grab_image(void* vcap, void* data) { struct dummy_video_capture* dummy = (struct dummy_video_capture*)vcap; memset(data, 0, dummy->size); return M64ERR_SUCCESS; } const struct video_capture_backend_interface g_idummy_video_capture_backend = { "dummy", dummy_init, dummy_release, dummy_open, dummy_close, dummy_grab_image }; mupen64plus-core-src-2.6.0/src/backends/file_storage.c000066400000000000000000000115701464506436200226220ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - file_storage.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "file_storage.h" #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "backends/api/storage_backend.h" #include "device/dd/dd_controller.h" #include "main/util.h" #include "main/netplay.h" int open_file_storage(struct file_storage* fstorage, size_t size, const char* filename) { /* ! Take ownership of filename ! */ fstorage->filename = filename; fstorage->size = size; fstorage->first_access = 1; /* allocate memory for holding data */ fstorage->data = malloc(fstorage->size); if (fstorage->data == NULL) { return -1; } /* try to load storage file content */ if (!netplay_is_init()) { return read_from_file(fstorage->filename, fstorage->data, fstorage->size); } else { return netplay_read_storage(fstorage->filename, fstorage->data, fstorage->size); } } int open_rom_file_storage(struct file_storage* fstorage, const char* filename) { fstorage->data = NULL; fstorage->size = 0; fstorage->filename = NULL; fstorage->first_access = 1; file_status_t err = load_file(filename, (void**)&fstorage->data, &fstorage->size); if (err == file_ok) { /* ! take ownsership of filename ! */ fstorage->filename = filename; } return err; } void close_file_storage(struct file_storage* fstorage) { free((void*)fstorage->data); free((void*)fstorage->filename); } static uint8_t* file_storage_data(const void* storage) { struct file_storage* fstorage = (struct file_storage*)storage; return fstorage->data; } static size_t file_storage_size(const void* storage) { struct file_storage* fstorage = (struct file_storage*)storage; return fstorage->size; } static void file_storage_save(void* storage, size_t start, size_t size) { if (netplay_is_init() && netplay_get_controller(0) == -1) return; struct file_storage* fstorage = (struct file_storage*)storage; file_status_t err; /* On first save access ignore start/size and write full storage content, * otherwise write only updated chunk */ if (fstorage->first_access) { fstorage->first_access = 0; err = write_to_file(fstorage->filename, fstorage->data, fstorage->size); } else { err = write_chunk_to_file(fstorage->filename, fstorage->data + start, size, start); } switch(err) { case file_open_error: DebugMessage(M64MSG_WARNING, "couldn't open storage file '%s' for writing", fstorage->filename); break; case file_write_error: DebugMessage(M64MSG_WARNING, "failed to write storage file '%s'", fstorage->filename); break; default: break; } } static void file_storage_parent_save(void* storage, size_t start, size_t size) { struct file_storage* fstorage = (struct file_storage*)((struct file_storage*)storage)->filename; file_storage_save(fstorage, start, size); } static void dummy_save(void* storage, size_t start, size_t size) { /* do nothing */ } const struct storage_backend_interface g_ifile_storage = { file_storage_data, file_storage_size, file_storage_save }; const struct storage_backend_interface g_ifile_storage_ro = { file_storage_data, file_storage_size, dummy_save }; const struct storage_backend_interface g_isubfile_storage = { file_storage_data, file_storage_size, file_storage_parent_save }; mupen64plus-core-src-2.6.0/src/backends/file_storage.h000066400000000000000000000042131464506436200226230ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - file_storage.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_MAIN_FILE_STORAGE_H #define M64P_MAIN_FILE_STORAGE_H #include #include struct file_storage { uint8_t* data; size_t size; const char* filename; int first_access; }; int open_file_storage(struct file_storage* storage, size_t size, const char* filename); int open_rom_file_storage(struct file_storage* storage, const char* filename); void close_file_storage(struct file_storage* storage); extern const struct storage_backend_interface g_ifile_storage; extern const struct storage_backend_interface g_ifile_storage_ro; extern const struct storage_backend_interface g_isubfile_storage; #endif mupen64plus-core-src-2.6.0/src/backends/opencv_video_capture.cpp000066400000000000000000000146211464506436200247220ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - opencv_video_capture.cpp * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "opencv2/core/version.hpp" #if CV_MAJOR_VERSION >= 3 /* this is for opencv >= 3.0 (new style headers + videoio/highgui split) */ #include #include #include #include #elif CV_MAJOR_VERSION >= 2 /* otherwise go the safe way and let opencv include all its headers */ #include #else #error "Unsupported version of OpenCV" #endif #include struct opencv_video_capture { unsigned int width; unsigned int height; std::string device; cv::VideoCapture cap; }; extern "C" { #include "backends/api/video_capture_backend.h" #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "api/m64p_config.h" #include "api/m64p_types.h" #include "main/util.h" extern "C" const struct video_capture_backend_interface g_iopencv_video_capture_backend; static m64p_error opencv_init_full(struct opencv_video_capture** cv, const char* dev) { try { std::string device; if (dev != NULL) { device = dev; } *cv = new opencv_video_capture(); (*cv)->width = 0; (*cv)->height = 0; (*cv)->device = std::move(device); return M64ERR_SUCCESS; } /* C++ exception must not cross C-API boundaries */ catch(...) { return M64ERR_INTERNAL; } } static m64p_error opencv_init(void** vcap, const char* section) { try { /* default parameters */ const char* device = "0"; if (section && strlen(section) > 0) { m64p_handle config = NULL; ConfigOpenSection(section, &config); /* set default parameters */ ConfigSetDefaultString(config, "device", device, "Device to use for capture or \"0\" for default."); /* get parameters */ device = ConfigGetParamString(config, "device"); } return opencv_init_full(reinterpret_cast(vcap), device); } /* C++ exception must not cross C-API boundaries */ catch(...) { return M64ERR_INTERNAL; } } static void opencv_release(void* vcap) { try { struct opencv_video_capture* cv = static_cast(vcap); if (cv == NULL) { return; } delete cv; } /* C++ exception must not cross C-API boundaries */ catch(...) { return; } } static m64p_error opencv_open(void* vcap, unsigned int width, unsigned int height) { try { int dev_num; struct opencv_video_capture* cv = static_cast(vcap); /* open device (we support both device number or path */ if (string_to_int(cv->device.c_str(), &dev_num)) { cv->cap.open(dev_num); } else { cv->cap.open(cv->device); } if (!cv->cap.isOpened()) { DebugMessage(M64MSG_ERROR, "Failed to open video device %s", cv->device.c_str()); return M64ERR_SYSTEM_FAIL; } /* TODO: adapt capture resolution to the desired resolution */ DebugMessage(M64MSG_INFO, "Video successfully opened: %s", cv->device.c_str()); cv->width = width; cv->height = height; return M64ERR_SUCCESS; } /* C++ exception must not cross C-API boundaries */ catch(...) { return M64ERR_INTERNAL; } } static void opencv_close(void* vcap) { try { struct opencv_video_capture* cv = static_cast(vcap); cv->cap.release(); DebugMessage(M64MSG_INFO, "Video closed"); } /* C++ exception must not cross C-API boundaries */ catch(...) { return; } } static m64p_error opencv_grab_image(void* vcap, void* data) { try { struct opencv_video_capture* cv = static_cast(vcap); /* read next frame */ cv::Mat frame; if (!cv->cap.read(frame)) { DebugMessage(M64MSG_ERROR, "Failed to grab frame !"); return M64ERR_SYSTEM_FAIL; } /* resize image to desired resolution */ cv::Mat output = cv::Mat(cv->height, cv->width, CV_8UC3, data); cv::resize(frame, output, output.size(), 0, 0, cv::INTER_AREA); return M64ERR_SUCCESS; } /* C++ exception must not cross C-API boundaries */ catch(...) { return M64ERR_INTERNAL; } } #if 0 void cv_imshow(const char* name, unsigned int width, unsigned int height, int channels, void* data) { try { int type = (channels == 1) ? CV_8UC1 : CV_8UC3; cv::Mat frame = cv::Mat(height, width, type, data); cv::imshow(name, frame); cv::waitKey(1); } /* C++ exception must not cross C-API boundaries */ catch(...) { return; } } #endif extern "C" const struct video_capture_backend_interface g_iopencv_video_capture_backend = { "opencv", opencv_init, opencv_release, opencv_open, opencv_close, opencv_grab_image }; } mupen64plus-core-src-2.6.0/src/backends/plugins_compat/000077500000000000000000000000001464506436200230335ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/backends/plugins_compat/audio_plugin_compat.c000066400000000000000000000057101464506436200272240ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - audio_plugin_compat.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "backends/api/audio_out_backend.h" #include "device/rcp/ai/ai_controller.h" #include "device/rcp/ri/ri_controller.h" #include "device/rcp/vi/vi_controller.h" #include "device/rdram/rdram.h" #include "main/rom.h" #include "plugin/plugin.h" static void audio_plugin_set_frequency(void* aout, unsigned int frequency) { struct ai_controller* ai = (struct ai_controller*)aout; uint32_t saved_ai_dacrate = ai->regs[AI_DACRATE_REG]; ai->regs[AI_DACRATE_REG] = ai->vi->clock / frequency - 1; audio.aiDacrateChanged(ROM_PARAMS.systemtype); ai->regs[AI_DACRATE_REG] = saved_ai_dacrate; } static void audio_plugin_push_samples(void* aout, const void* buffer, size_t size) { /* abuse core & audio plugin implementation to approximate desired effect */ struct ai_controller* ai = (struct ai_controller*)aout; uint32_t saved_ai_length = ai->regs[AI_LEN_REG]; uint32_t saved_ai_dram = ai->regs[AI_DRAM_ADDR_REG]; /* exploit the fact that buffer points in g_dev.rdram.dram to retreive dram_addr_reg value */ ai->regs[AI_DRAM_ADDR_REG] = (uint32_t)((uint8_t*)buffer - (uint8_t*)ai->ri->rdram->dram); ai->regs[AI_LEN_REG] = (uint32_t)size; audio.aiLenChanged(); ai->regs[AI_LEN_REG] = saved_ai_length; ai->regs[AI_DRAM_ADDR_REG] = saved_ai_dram; } const struct audio_out_backend_interface g_iaudio_out_backend_plugin_compat = { audio_plugin_set_frequency, audio_plugin_push_samples }; mupen64plus-core-src-2.6.0/src/backends/plugins_compat/input_plugin_compat.c000066400000000000000000000170131464506436200272610ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - input_plugin_compat.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "plugins_compat.h" #include "api/m64p_plugin.h" #include "backends/api/controller_input_backend.h" #include "backends/api/rumble_backend.h" #include "plugin/plugin.h" #include "main/main.h" #include "main/netplay.h" #include #include #include #include /* XXX: this is an abuse of the Zilmar Spec normally this value is reserved */ enum { PAK_SWITCH_BUTTON = 0x4000, GB_CART_SWITCH_BUTTON = 0x8000 }; /* Pak switching delay * If you put too low value, * some games (for instance Perfect Dark) won't be able to detect the pak change * causing incorrect pak accesses */ enum { PAK_SWITCH_DELAY = 20 }; enum { GB_CART_SWITCH_DELAY = 20 }; static int is_button_released(uint32_t input, uint32_t last_input, uint32_t mask) { return ((input & mask) == 0) && ((last_input & mask) != 0); } static m64p_error input_plugin_get_input(void* opaque, uint32_t* input_) { struct controller_input_compat* cin_compat = (struct controller_input_compat*)opaque; BUTTONS keys = { 0 }; int pak_change_requested = 0; /* first poll controller */ if (!netplay_is_init()) { if (input.getKeys) input.getKeys(cin_compat->control_id, &keys); } else { int netplay_controller = netplay_get_controller(cin_compat->control_id); if (netplay_controller >= 0) { //Here we "trick" the input plugin //by passing it the controller number that is controlling the player during netplay uint8_t plugin = Controls[netplay_controller].Plugin; uint8_t present = Controls[netplay_controller].Present; if (input.getKeys) input.getKeys(netplay_controller, &keys); Controls[netplay_controller].Plugin = plugin; Controls[netplay_controller].Present = present; } cin_compat->last_input = keys.Value; //disable pak switching for netplay cin_compat->last_pak_type = Controls[cin_compat->control_id].Plugin; //disable pak switching for netplay } /* return an error if controller is not plugged */ if (!Controls[cin_compat->control_id].Present) { return M64ERR_SYSTEM_FAIL; } /* has Controls[i].Plugin changed since last call */ if (cin_compat->last_pak_type != Controls[cin_compat->control_id].Plugin) { pak_change_requested = 1; cin_compat->main_switch_pak = main_switch_plugin_pak; } /* or has the PAK_SWITCH_BUTTON been released */ if (is_button_released(keys.Value, cin_compat->last_input, PAK_SWITCH_BUTTON)) { pak_change_requested = 1; cin_compat->main_switch_pak = main_switch_next_pak; } /* if so, immediately disconnect current pak (if any) * and start the pak switch delay */ if (pak_change_requested) { change_pak(cin_compat->cont, NULL, NULL); cin_compat->pak_switch_delay = PAK_SWITCH_DELAY; } /* switch to next/selected pak after switch delay has expired */ if (cin_compat->pak_switch_delay > 0 && --cin_compat->pak_switch_delay == 0) { cin_compat->main_switch_pak(cin_compat->control_id); cin_compat->main_switch_pak = NULL; } if (cin_compat->gb_cart_switch_enabled) { /* disconnect current GB cart (if any) immediately after "GB cart switch" button is released */ if (is_button_released(keys.Value, cin_compat->last_input, GB_CART_SWITCH_BUTTON)) { change_gb_cart(cin_compat->tpk, NULL); cin_compat->gb_switch_delay = GB_CART_SWITCH_DELAY; } /* switch to new GB cart after switch delay has expired */ if (cin_compat->gb_switch_delay > 0 && --cin_compat->gb_switch_delay == 0) { main_change_gb_cart(cin_compat->control_id); } } cin_compat->last_pak_type = Controls[cin_compat->control_id].Plugin; cin_compat->last_input = keys.Value; *input_ = keys.Value; return M64ERR_SUCCESS; } const struct controller_input_backend_interface g_icontroller_input_backend_plugin_compat = { input_plugin_get_input }; static void input_plugin_rumble_exec(void* opaque, enum rumble_action action) { int control_id = *(int*)opaque; if (input.controllerCommand == NULL) { return; } //This is for netplay, -1 means there is no local controller controlling this player if (control_id == -1) { return; } static const uint8_t rumble_cmd_header[] = { 0x23, 0x01, /* T=0x23, R=0x01 */ JCMD_PAK_WRITE, 0xc0, 0x1b, /* address=0xc000 | crc=0x1b */ }; uint8_t cmd[0x26]; uint8_t rumble_data = (action == RUMBLE_START) ? 0x01 : 0x00; /* build rumble command */ memcpy(cmd, rumble_cmd_header, 5); memset(cmd + 5, rumble_data, 0x20); cmd[0x25] = 0; /* dummy data CRC */ input.controllerCommand(control_id, cmd); } const struct rumble_backend_interface g_irumble_backend_plugin_compat = { input_plugin_rumble_exec }; static void input_plugin_read_controller(void* opaque, const uint8_t* tx, const uint8_t* tx_buf, uint8_t* rx, uint8_t* rx_buf) { int control_id = *(int*)opaque; if (input.readController == NULL) { return; } //This is for netplay, -1 means there is no local controller controlling this player if (control_id == -1) { return; } /* UGLY: use negative offsets to get access to non-const tx pointer */ input.readController(control_id, rx - 1); } void input_plugin_controller_command(void* opaque, uint8_t* tx, const uint8_t* tx_buf, const uint8_t* rx, const uint8_t* rx_buf) { int control_id = *(int*)opaque; if (input.controllerCommand == NULL) { return; } //This is for netplay, -1 means there is no local controller controlling this player if (control_id == -1) { return; } input.controllerCommand(control_id, tx); } const struct joybus_device_interface g_ijoybus_device_plugin_compat = { NULL, input_plugin_read_controller, input_plugin_controller_command, }; mupen64plus-core-src-2.6.0/src/backends/plugins_compat/plugins_compat.h000066400000000000000000000052731464506436200262370ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - plugins_compat.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_BACKENDS_PLUGINS_COMPAT_PLUGINS_COMPAT_H #define M64P_BACKENDS_PLUGINS_COMPAT_PLUGINS_COMPAT_H #include "backends/api/audio_out_backend.h" #include "backends/api/controller_input_backend.h" #include "backends/api/rumble_backend.h" #include "backends/api/joybus.h" #include /* Audio Out backend interface */ extern const struct audio_out_backend_interface g_iaudio_out_backend_plugin_compat; /* Controller Input backend interface */ struct controller_input_compat { int control_id; struct game_controller* cont; struct transferpak* tpk; uint32_t last_input; int last_pak_type; void (*main_switch_pak)(int control_id); unsigned int pak_switch_delay; unsigned int gb_switch_delay; unsigned int gb_cart_switch_enabled; uint32_t netplay_count; struct netplay_event* event_first; }; extern const struct controller_input_backend_interface g_icontroller_input_backend_plugin_compat; /* Rumble backend interface */ extern const struct rumble_backend_interface g_irumble_backend_plugin_compat; /* PIF data processing functions */ extern const struct joybus_device_interface g_ijoybus_device_plugin_compat; #endif mupen64plus-core-src-2.6.0/src/debugger/000077500000000000000000000000001464506436200200215ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/debugger/dbg_breakpoints.c000066400000000000000000000175711464506436200233350ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dbg_breakpoints.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 DarkJeztr HyperHacker * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "dbg_breakpoints.h" #include "dbg_debugger.h" #include "device/memory/memory.h" #ifdef DBG int g_NumBreakpoints=0; m64p_breakpoint g_Breakpoints[BREAKPOINTS_MAX_NUMBER]; int add_breakpoint(struct memory* mem, uint32_t address) { if (g_NumBreakpoints == BREAKPOINTS_MAX_NUMBER) { DebugMessage(M64MSG_ERROR, "BREAKPOINTS_MAX_NUMBER have been reached."); return -1; } g_Breakpoints[g_NumBreakpoints].address=address; g_Breakpoints[g_NumBreakpoints].endaddr=address; BPT_SET_FLAG(g_Breakpoints[g_NumBreakpoints], M64P_BKP_FLAG_EXEC); enable_breakpoint(mem, g_NumBreakpoints); return g_NumBreakpoints++; } int add_breakpoint_struct(struct memory* mem, m64p_breakpoint *newbp) { if (g_NumBreakpoints == BREAKPOINTS_MAX_NUMBER) { DebugMessage(M64MSG_ERROR, "BREAKPOINTS_MAX_NUMBER have been reached."); return -1; } memcpy(&g_Breakpoints[g_NumBreakpoints], newbp, sizeof(m64p_breakpoint)); if (BPT_CHECK_FLAG(g_Breakpoints[g_NumBreakpoints], M64P_BKP_FLAG_ENABLED)) { BPT_CLEAR_FLAG(g_Breakpoints[g_NumBreakpoints], M64P_BKP_FLAG_ENABLED); enable_breakpoint(mem, g_NumBreakpoints); } return g_NumBreakpoints++; } void enable_breakpoint(struct memory* mem, int bpt) { m64p_breakpoint *curBpt = g_Breakpoints + bpt; uint64_t bptAddr; if (BPT_CHECK_FLAG((*curBpt), M64P_BKP_FLAG_READ)) { for (bptAddr = curBpt->address; bptAddr <= (curBpt->endaddr | 0xFFFF); bptAddr+=0x10000) if (lookup_breakpoint((uint32_t) bptAddr & 0xFFFF0000, 0x10000, M64P_BKP_FLAG_ENABLED | M64P_BKP_FLAG_READ) == -1) activate_memory_break_read(mem, (uint32_t) bptAddr); } if (BPT_CHECK_FLAG((*curBpt), M64P_BKP_FLAG_WRITE)) { for (bptAddr = curBpt->address; bptAddr <= (curBpt->endaddr | 0xFFFF); bptAddr+=0x10000) if (lookup_breakpoint((uint32_t) bptAddr & 0xFFFF0000, 0x10000, M64P_BKP_FLAG_ENABLED | M64P_BKP_FLAG_WRITE) == -1) activate_memory_break_write(mem, (uint32_t) bptAddr); } BPT_SET_FLAG(g_Breakpoints[bpt], M64P_BKP_FLAG_ENABLED); } void disable_breakpoint(struct memory* mem, int bpt) { m64p_breakpoint *curBpt = g_Breakpoints + bpt; uint64_t bptAddr; BPT_CLEAR_FLAG(g_Breakpoints[bpt], M64P_BKP_FLAG_ENABLED); if (BPT_CHECK_FLAG((*curBpt), M64P_BKP_FLAG_READ)) { for (bptAddr = curBpt->address; bptAddr <= ((unsigned long)(curBpt->endaddr | 0xFFFF)); bptAddr+=0x10000) if (lookup_breakpoint((uint32_t) bptAddr & 0xFFFF0000, 0x10000, M64P_BKP_FLAG_ENABLED | M64P_BKP_FLAG_READ) == -1) deactivate_memory_break_read(mem, (uint32_t) bptAddr); } if (BPT_CHECK_FLAG((*curBpt), M64P_BKP_FLAG_WRITE)) { for (bptAddr = curBpt->address; bptAddr <= ((unsigned long)(curBpt->endaddr | 0xFFFF)); bptAddr+=0x10000) if (lookup_breakpoint((uint32_t) bptAddr & 0xFFFF0000, 0x10000, M64P_BKP_FLAG_ENABLED | M64P_BKP_FLAG_WRITE) == -1) deactivate_memory_break_write(mem, (uint32_t) bptAddr); } BPT_CLEAR_FLAG(g_Breakpoints[bpt], M64P_BKP_FLAG_ENABLED); } void remove_breakpoint_by_num(struct memory* mem, int bpt) { int curBpt; if (BPT_CHECK_FLAG(g_Breakpoints[bpt], M64P_BKP_FLAG_ENABLED)) disable_breakpoint(mem, bpt); for (curBpt=bpt+1; curBpt= g_Breakpoints[i].address) || (address <= g_Breakpoints[i].endaddr)) return i; } else // endaddr >= address { if((endaddr >= g_Breakpoints[i].address) && (address <= g_Breakpoints[i].endaddr)) return i; } } } return -1; } int check_breakpoints(uint32_t address) { return lookup_breakpoint(address, 1, M64P_BKP_FLAG_ENABLED | M64P_BKP_FLAG_EXEC); } int check_breakpoints_on_mem_access(uint32_t pc, uint32_t address, uint32_t size, uint32_t flags) { //This function handles memory read/write breakpoints. size specifies the address //range to check, flags specifies the flags that all need to be set. //It automatically stops and updates the debugger on hit, so the memory access //functions only need to call it and can discard the result. int bpt; if (g_dbg_runstate == M64P_DBG_RUNSTATE_RUNNING) { bpt = lookup_breakpoint(address, size, flags); if (bpt != -1) { breakpointAccessed = address; breakpointFlag = flags; if (BPT_CHECK_FLAG(g_Breakpoints[bpt], M64P_BKP_FLAG_LOG)) log_breakpoint(pc, flags, address); g_dbg_runstate = M64P_DBG_RUNSTATE_PAUSED; update_debugger(pc); return bpt; } } return -1; } int log_breakpoint(uint32_t PC, uint32_t Flag, uint32_t Access) { char msg[32]; if (Flag & M64P_BKP_FLAG_READ) sprintf(msg, "0x%08X read 0x%08X", PC, Access); else if (Flag & M64P_BKP_FLAG_WRITE) sprintf(msg, "0x%08X wrote 0x%08X", PC, Access); else sprintf(msg, "0x%08X executed", PC); DebugMessage(M64MSG_INFO, "BPT: %s", msg); return 0; } #endif mupen64plus-core-src-2.6.0/src/debugger/dbg_breakpoints.h000066400000000000000000000047041464506436200233340ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dbg_breakpoints.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 DarkJeztr HyperHacker * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __BREAKPOINTS_H__ #define __BREAKPOINTS_H__ #include "../api/m64p_types.h" #include struct memory; extern int g_NumBreakpoints; extern m64p_breakpoint g_Breakpoints[]; int add_breakpoint(struct memory* mem, uint32_t address); int add_breakpoint_struct(struct memory* mem, m64p_breakpoint *newbp); void remove_breakpoint_by_address(struct memory* mem, uint32_t address); void remove_breakpoint_by_num(struct memory* mem, int bpt); void enable_breakpoint(struct memory* mem, int breakpoint); void disable_breakpoint(struct memory* mem, int breakpoint); int check_breakpoints(uint32_t address); int check_breakpoints_on_mem_access(uint32_t pc, uint32_t address, uint32_t size, uint32_t flags); int lookup_breakpoint(uint32_t address, uint32_t size, uint32_t flags); int log_breakpoint(uint32_t PC, uint32_t Flag, uint32_t Access); void replace_breakpoint_num(struct memory* mem, int, m64p_breakpoint*); #endif /* __BREAKPOINTS_H__ */ mupen64plus-core-src-2.6.0/src/debugger/dbg_debugger.c000066400000000000000000000073621464506436200225750ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - debugger.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 DarkJeztr * * Copyright (C) 2002 davFr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "api/callbacks.h" #include "api/debugger.h" #include "dbg_breakpoints.h" #include "dbg_debugger.h" #include "dbg_memory.h" #ifdef DBG int g_DebuggerActive = 0; // whether the debugger is enabled or not m64p_dbg_runstate g_dbg_runstate; // Holds the number of pending steps the debugger needs to perform. static SDL_sem *sem_pending_steps; uint32_t previousPC; uint32_t breakpointAccessed; uint32_t breakpointFlag; //]=-=-=-=-=-=-=-=-=-=-=[ Initialisation du Debugger ]=-=-=-=-=-=-=-=-=-=-=-=[ void init_debugger() { if (!DebuggerCallbacksAreSet()) { DebugMessage(M64MSG_WARNING, "Front-end debugger callbacks are not set, so debugger will remain disabled."); return; } g_DebuggerActive = 1; g_dbg_runstate = M64P_DBG_RUNSTATE_PAUSED; DebuggerCallback(DEBUG_UI_INIT, 0); /* call front-end to initialize user interface */ init_host_disassembler(); sem_pending_steps = SDL_CreateSemaphore(0); } void destroy_debugger() { SDL_DestroySemaphore(sem_pending_steps); sem_pending_steps = NULL; g_DebuggerActive = 0; } //]=-=-=-=-=-=-=-=-=-=-=-=-=[ Mise-a-Jour Debugger ]=-=-=-=-=-=-=-=-=-=-=-=-=[ void update_debugger(uint32_t pc) // Update debugger state and display. // Should be called after each R4300 instruction // Checks for breakpoint hits on PC { int bpt; if (g_dbg_runstate != M64P_DBG_RUNSTATE_PAUSED) { bpt = check_breakpoints(pc); if (bpt != -1) { g_dbg_runstate = M64P_DBG_RUNSTATE_PAUSED; breakpointAccessed = 0; breakpointFlag = M64P_BKP_FLAG_EXEC; if (BPT_CHECK_FLAG(g_Breakpoints[bpt], M64P_BKP_FLAG_LOG)) log_breakpoint(pc, M64P_BKP_FLAG_EXEC, 0); } } if (g_dbg_runstate != M64P_DBG_RUNSTATE_RUNNING) { DebuggerCallback(DEBUG_UI_UPDATE, pc); /* call front-end to notify user interface to update */ } if (g_dbg_runstate == M64P_DBG_RUNSTATE_PAUSED) { // The emulation thread is blocked until a step call via the API. SDL_SemWait(sem_pending_steps); } previousPC = pc; } void debugger_step() { SDL_SemPost(sem_pending_steps); } #endif mupen64plus-core-src-2.6.0/src/debugger/dbg_debugger.h000066400000000000000000000040221464506436200225700ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dbg_debugger.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 DarkJeztr * * Copyright (C) 2002 davFr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __DBG_DEBUGGER_H__ #define __DBG_DEBUGGER_H__ #include "api/m64p_types.h" extern int g_DebuggerActive; /* True if the debugger is running */ extern m64p_dbg_runstate g_dbg_runstate; extern uint32_t previousPC; extern uint32_t breakpointAccessed; extern uint32_t breakpointFlag; void init_debugger(void); void update_debugger(uint32_t pc); void destroy_debugger(void); void debugger_step(void); #endif /* __DBG_DEBUGGER_H__ */ mupen64plus-core-src-2.6.0/src/debugger/dbg_decoder.c000066400000000000000000000640251464506436200224150ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus -- dbg_decoder.c * * Copyright (c) 2010 Marshall B. Rogers * * http://64.vg/ * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * This is a heavily modified reentrant version of the MIPS disassembler found * in the NetBSD operating system. I chose to use this as a base due to the * small, compact, and easily manageable code. * * Original copyright/license information is contained below. */ /* $NetBSD: db_disasm.c,v 1.21 2009/12/14 00:46:06 matt Exp $ */ #include /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93 */ #include #include #include #include #ifndef MIPS32 #define MIPS32 #endif #include "dbg_decoder.h" #include "dbg_decoder_local.h" #include "osal/preproc.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Data types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ typedef uint32_t db_addr_t; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Local variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static const char * const r4k_str_op_name[64] = { /* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz", /* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", /*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", /*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", /*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", /*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", /*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", /*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" }; static const char * const r4k_str_spec_name[64] = { /* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav", /* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync", /*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", /*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", /*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", /*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", /*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", /*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" }; static const char * const r4k_str_spec2_name[4] = /* QED RM4650, R5000, etc. */ { /* 0 */ "mad", "madu", "mul", "spec3" }; static const char * const r4k_str_bcond_name[32] = { /* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", /* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", /*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", /*24 */ "?", "?", "?", "?", "?", "?", "?", "?", }; static const char * const r4k_str_cop1_name[64] = { /* 0 */ "add", "sub", "mul", "div", "sqrt","abs", "mov", "neg", /* 8 */ "fop08", "trunc.l","fop0a","fop0b","fop0c","trunc.w","fop0e","fop0f", /*16 */ "fop10", "fop11","fop12","fop13","fop14","fop15","fop16","fop17", /*24 */ "fop18", "fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", /*32 */ "cvt.s", "cvt.d","fop22","fop23","cvt.w","cvt.l","fop26","fop27", /*40 */ "fop28", "fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", /*48 */ "c.f", "c.un","c.eq","c.ueq","c.olt","c.ult", "c.ole", "c.ule", /*56 */ "c.sf", "c.ngle","c.seq","c.ngl","c.lt","c.nge", "c.le", "c.ngt" }; static const char * const r4k_str_fmt_name[16] = { "s", "d", "e", "fmt3", "w", "l", "fmt6", "fmt7", "fmt8", "fmt9", "fmta", "fmtb", "fmtc", "fmtd", "fmte", "fmtf" }; static const char * const r4k_str_reg_name[32] = { "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$s8", "$ra" }; static const char * const r4k_str_c0_opname[64] = { "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", }; static const char * const r4k_str_c0_reg[32] = { "C0_INX", "C0_RAND", "C0_ENTRYLO0", "C0_ENTRYLO1", "C0_CONTEXT", "C0_PAGEMASK", "C0_WIRED", "cp0r7", "C0_BADVADDR", "C0_COUNT", "C0_ENTRYHI", "C0_COMPARE", "C0_SR", "C0_CAUSE", "C0_EPC", "C0_PRID", "C0_CONFIG", "C0_LLADDR", "C0_WATCHLO", "C0_WATCHHI", "xcontext", "cp0r21", "cp0r22", "debug", "depc", "perfcnt", "C0_ECC", "C0_CACHE_ERR", "C0_TAGLO", "C0_TAGHI", "C0_ERROR_EPC", "desave" }; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Local functions - lookup ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Look up a symbol */ static char * lookup_sym ( struct r4k_dis_t * state, uint32_t address ) { if( state->lookup_sym ) return state->lookup_sym( address, state->lookup_sym_d ); return NULL; } /* Look up an upper 16-bits relocation */ static char * lookup_rel_hi16 ( struct r4k_dis_t * state, uint32_t address ) { if( state->lookup_rel_hi16 ) return state->lookup_rel_hi16( address, state->lookup_rel_hi16_d ); return NULL; } /* Look up a lower 16-bits relocation */ static char * lookup_rel_lo16 ( struct r4k_dis_t * state, uint32_t address ) { if( state->lookup_rel_lo16 ) return state->lookup_rel_lo16( address, state->lookup_rel_lo16_d ); return NULL; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Local functions - disassembler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Print text into the destination buffer */ static int db_printf ( struct r4k_dis_t * state, char * fmt, ... ) { int l; va_list ap; char buffer[1024]; /* Prepare user provided */ va_start( ap, fmt ); l = vsnprintf( buffer, sizeof(buffer), fmt, ap ); va_end( ap ); /* Add it to our string */ state->dest += sprintf( state->dest, "%s", buffer ); state->length += l; return l; } /* Print an address to a string. If there's a symbol, the name will be printed */ static int print_addr ( struct r4k_dis_t * state, uint32_t address ) { int len; char * sym; /* Try to lookup symbol */ if( (sym = lookup_sym(state, address)) ) { len = db_printf( state, "%s", sym ); } else { len = db_printf( state, "0x%08X", address ); } return len; } /* Disassemble an instruction */ static db_addr_t db_disasm_insn ( struct r4k_dis_t * state, int insn, db_addr_t loc, bool altfmt ) { char * rel; InstFmt i; i.word = insn; switch (i.JType.op) { case OP_SPECIAL: if (i.word == 0) { db_printf(state, "nop"); break; } /* XXX * "addu" is a "move" only in 32-bit mode. What's the correct * answer - never decode addu/daddu as "move"? */ if (i.RType.func == OP_ADDU && i.RType.rt == 0) { db_printf(state, "%-16s%s,%s", "move", r4k_str_reg_name[i.RType.rd], r4k_str_reg_name[i.RType.rs]); break; } db_printf(state, "%-16s", r4k_str_spec_name[i.RType.func]); switch (i.RType.func) { case OP_SLL: case OP_SRL: case OP_SRA: case OP_DSLL: case OP_DSRL: case OP_DSRA: case OP_DSLL32: case OP_DSRL32: case OP_DSRA32: db_printf(state, "%s,%s,%d", r4k_str_reg_name[i.RType.rd], r4k_str_reg_name[i.RType.rt], i.RType.shamt); break; case OP_SLLV: case OP_SRLV: case OP_SRAV: case OP_DSLLV: case OP_DSRLV: case OP_DSRAV: db_printf(state, "%s,%s,%s", r4k_str_reg_name[i.RType.rd], r4k_str_reg_name[i.RType.rt], r4k_str_reg_name[i.RType.rs]); break; case OP_MFHI: case OP_MFLO: db_printf(state, "%s", r4k_str_reg_name[i.RType.rd]); break; case OP_JR: case OP_JALR: db_printf(state, "%s", r4k_str_reg_name[i.RType.rs]); break; case OP_MTLO: case OP_MTHI: db_printf(state, "%s", r4k_str_reg_name[i.RType.rs]); break; case OP_MULT: case OP_MULTU: case OP_DMULT: case OP_DMULTU: db_printf(state, "%s,%s", r4k_str_reg_name[i.RType.rs], r4k_str_reg_name[i.RType.rt]); break; case OP_DIV: case OP_DIVU: case OP_DDIV: case OP_DDIVU: db_printf(state, "%s,%s,%s", r4k_str_reg_name[0], r4k_str_reg_name[i.RType.rs], r4k_str_reg_name[i.RType.rt]); break; case OP_SYSCALL: case OP_SYNC: break; case OP_BREAK: db_printf(state, "%d", (i.RType.rs << 5) | i.RType.rt); break; default: db_printf(state, "%s,%s,%s", r4k_str_reg_name[i.RType.rd], r4k_str_reg_name[i.RType.rs], r4k_str_reg_name[i.RType.rt]); } break; case OP_SPECIAL2: if (i.RType.func == OP_MUL) db_printf(state, "%s\t%s,%s,%s", r4k_str_spec2_name[i.RType.func & 0x3], r4k_str_reg_name[i.RType.rd], r4k_str_reg_name[i.RType.rs], r4k_str_reg_name[i.RType.rt]); else db_printf(state, "%s\t%s,%s", r4k_str_spec2_name[i.RType.func & 0x3], r4k_str_reg_name[i.RType.rs], r4k_str_reg_name[i.RType.rt]); break; case OP_BCOND: db_printf(state, "%-16s%s,", r4k_str_bcond_name[i.IType.rt], r4k_str_reg_name[i.IType.rs]); goto pr_displ; case OP_BLEZ: case OP_BLEZL: case OP_BGTZ: case OP_BGTZL: db_printf(state, "%-16s%s,", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rs]); goto pr_displ; case OP_BEQ: case OP_BEQL: if (i.IType.rs == 0 && i.IType.rt == 0) { db_printf(state, "%-16s", "b"); goto pr_displ; } /* FALLTHROUGH */ case OP_BNE: case OP_BNEL: db_printf(state, "%-16s%s,%s,", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rs], r4k_str_reg_name[i.IType.rt]); pr_displ: print_addr( state, loc + 4 + ((short)i.IType.imm << 2) ); break; case OP_COP0: switch (i.RType.rs) { case OP_BCx: case OP_BCy: db_printf(state, "bc0%c\t", "ft"[i.RType.rt & COPz_BC_TF_MASK]); goto pr_displ; case OP_MT: db_printf(state, "%-16s%s,%s", "mtc0", r4k_str_reg_name[i.RType.rt], r4k_str_c0_reg[i.RType.rd]); break; case OP_DMT: db_printf(state, "%-16s%s,%s", "dmtc0", r4k_str_reg_name[i.RType.rt], r4k_str_c0_reg[i.RType.rd]); break; case OP_MF: db_printf(state, "%-16s%s,%s", "mfc0", r4k_str_reg_name[i.RType.rt], r4k_str_c0_reg[i.RType.rd]); break; case OP_DMF: db_printf(state, "%-16s%s,%s","dmfc0", r4k_str_reg_name[i.RType.rt], r4k_str_c0_reg[i.RType.rd]); break; default: db_printf(state, "%s", r4k_str_c0_opname[i.FRType.func]); } break; case OP_COP1: switch (i.RType.rs) { case OP_BCx: case OP_BCy: db_printf(state, "bc1%c%s\t\t", "ft"[i.RType.rt & COPz_BC_TF_MASK], (insn >> 16 & 0x1F) == 2 || (insn >> 16 & 0x1F) == 3 ? "l" : ""); goto pr_displ; case OP_MT: db_printf(state, "mtc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; case OP_MF: db_printf(state, "mfc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; case OP_CT: db_printf(state, "ctc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; case OP_CF: db_printf(state, "cfc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; case OP_DMT: db_printf(state, "dmtc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; case OP_DMF: db_printf(state, "dmfc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; case OP_MTH: db_printf(state, "mthc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; case OP_MFH: db_printf(state, "mfhc1\t\t%s,$f%d", r4k_str_reg_name[i.RType.rt], i.RType.rd); break; default: if( i.FRType.func == 0x21 || i.FRType.func == 0x20 || i.FRType.func == 0x24 || i.FRType.func == 0x25 || i.FRType.func == 7 || i.FRType.func == 6 || i.FRType.func == 0xd || i.FRType.func == 4 || i.FRType.func == 5 || i.FRType.func == 9 ) {/*NEG.fmt fd, fs*/ db_printf(state, "%s.%s\t\t$f%d,$f%d", r4k_str_cop1_name[i.FRType.func], r4k_str_fmt_name[i.FRType.fmt], i.FRType.fd, i.FRType.fs); } else if( i.FRType.func != 1 && i.FRType.func != 2 && (insn & 0x3F) && !(insn >> 6 & 0x1F) ) /* C */ { db_printf(state, "%s.%s\t\t$f%d,$f%d", r4k_str_cop1_name[i.FRType.func], r4k_str_fmt_name[i.FRType.fmt], i.FRType.fs, i.FRType.ft); } else { db_printf(state, "%s.%s\t\t$f%d,$f%d,$f%d", r4k_str_cop1_name[i.FRType.func], r4k_str_fmt_name[i.FRType.fmt], i.FRType.fd, i.FRType.fs, i.FRType.ft); } } break; case OP_J: case OP_JAL: db_printf(state, "%-16s", r4k_str_op_name[i.JType.op]); print_addr(state, (loc & 0xF0000000) | (i.JType.target << 2)); break; case OP_LDC1: case OP_LWC1: case OP_SWC1: case OP_SDC1: db_printf(state, "%-16s$f%d,", r4k_str_op_name[i.IType.op], i.IType.rt); goto loadstore; case OP_LB: case OP_LH: case OP_LW: case OP_LWL: case OP_LWR: case OP_LD: case OP_LBU: case OP_LHU: case OP_LWU: case OP_SB: case OP_SH: case OP_SW: case OP_SWL: case OP_SWR: case OP_SD: db_printf(state, "%-16s%s,", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt]); loadstore: /* Part of a relocation? */ if( (rel = lookup_rel_lo16(state, loc)) ) { /* Yes. */ db_printf(state, "%%lo(%s)(%s)", rel, r4k_str_reg_name[i.IType.rs] ); break; } db_printf(state, "%d(%s)", (short)i.IType.imm, r4k_str_reg_name[i.IType.rs]); break; case OP_ORI: case OP_XORI: if( i.IType.op == OP_ORI ) { /* Part of a relocation? */ if( (rel = lookup_rel_lo16(state, loc)) ) { /* Yes. */ db_printf(state, "%-16s%s,%s,%%lo(%s)", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt], r4k_str_reg_name[i.IType.rs], rel ); break; } else { db_printf(state, "%-16s%s,%s,0x%x", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt], r4k_str_reg_name[i.IType.rs], i.IType.imm); break; } } else if (i.IType.rs == 0) { db_printf(state, "%-16s%s,0x%x", "li", r4k_str_reg_name[i.IType.rt], i.IType.imm); break; } /* FALLTHROUGH */ case OP_ANDI: db_printf(state, "%-16s%s,%s,0x%x", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt], r4k_str_reg_name[i.IType.rs], i.IType.imm); break; case OP_LUI: { /* Part of a relocation? */ if( (rel = lookup_rel_hi16(state, loc)) ) { /* Yes. */ db_printf(state, "%-16s%s,%%hi(%s)", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt], rel ); } else { db_printf(state, "%-16s%s,0x%x", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt], i.IType.imm); } } break; case OP_CACHE: db_printf(state, "%-16s0x%x,0x%x(%s)", r4k_str_op_name[i.IType.op], i.IType.rt, i.IType.imm, r4k_str_reg_name[i.IType.rs]); break; case OP_ADDI: case OP_DADDI: case OP_ADDIU: case OP_DADDIU: { /* Part of a relocation? */ if( (rel = lookup_rel_lo16(state, loc)) ) { /* Yes. */ db_printf(state, "%-16s%s,%s,%%lo(%s)", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt], r4k_str_reg_name[i.IType.rs], rel ); break; } if (i.IType.rs == 0) { db_printf(state, "%-16s%s,%d", "li", r4k_str_reg_name[i.IType.rt], (short)i.IType.imm); break; } /* FALLTHROUGH */ default: db_printf(state, "%-16s%s,%s,%d", r4k_str_op_name[i.IType.op], r4k_str_reg_name[i.IType.rt], r4k_str_reg_name[i.IType.rs], (short)i.IType.imm); } } /*db_printf(state, "\n");*/ return (loc + 4); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Global functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Disassemble an instruction with state */ static int r4k_disassemble ( struct r4k_dis_t * state, uint32_t instruction, uint32_t location, char * dest ) { state->dest = dest; db_disasm_insn( state, instruction, location, 0 ); return state->length; } /* Disassemble an instruction but split the opcode/operands into two char *'s */ static int r4k_disassemble_split ( struct r4k_dis_t * state, uint32_t instruction, uint32_t location, char ** opcode, char ** operands ) { int v, i; char buff[128], * dupd; v = r4k_disassemble( state, instruction, location, buff ); dupd = strdup( buff ); *opcode = &dupd[0]; for( i = 0; buff[i] && buff[i] != ' ' && buff[i] != '\t'; i++ ); dupd[i] = '\0'; for( ; buff[i] && (buff[i] == ' ' || buff[i] == '\t'); i++ ); *operands = &dupd[i]; return v; } /* Disassemble an instruction with a blank state but split op/operands */ static int r4k_disassemble_split_quick ( uint32_t instruction, uint32_t location, char ** opcode, char ** operands ) { struct r4k_dis_t state; /* Init state */ memset( &state, 0, sizeof(state) ); /* Perform */ return r4k_disassemble_split( &state, instruction, location, opcode, operands ); } //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[ DECODE_OP ]=-=-=-=-=-=-=-=-=-=-=-=-=-=-=[// void r4300_decode_op ( uint32_t instr, char * opcode, char * arguments, uint32_t counter ) { char * _op, * _args; _op = NULL; _args = NULL; r4k_disassemble_split_quick( instr, counter, &_op, &_args ); strcpy( opcode, _op ); strcpy( arguments, _args ); free( _op ); } mupen64plus-core-src-2.6.0/src/debugger/dbg_decoder.h000066400000000000000000000043421464506436200224160ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dbg_decoder.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2010 Marshall B. Rogers * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __DECODER_H__ #define __DECODER_H__ #if defined(WIN32) typedef unsigned int uint32_t; typedef unsigned char bool; #define false 0 #define true 1 #else #include #include #endif /* Disassembler lookup handler */ typedef char * (*r4k_lookup_func)(uint32_t, void *); /* Disassembler state */ typedef struct r4k_dis_t { r4k_lookup_func lookup_sym; void * lookup_sym_d; r4k_lookup_func lookup_rel_hi16; void * lookup_rel_hi16_d; r4k_lookup_func lookup_rel_lo16; void * lookup_rel_lo16_d; /* Private */ char * dest; int length; } R4kDis; extern void r4300_decode_op (uint32_t, char *, char *, uint32_t); #endif /* __DECODER_H__ */ mupen64plus-core-src-2.6.0/src/debugger/dbg_decoder_local.h000066400000000000000000001431771464506436200236020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dbg_debugger_local.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2010 Marshall B. Rogers * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __DECODER_LOCAL_H__ #define __DECODER_LOCAL_H__ #include /* $NetBSD: cpuregs.h,v 1.77 2009/12/14 00:46:04 matt Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)machConst.h 8.1 (Berkeley) 6/10/93 * * machConst.h -- * * Machine dependent constants. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machConst.h, * v 9.2 89/10/21 15:55:22 jhh Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAddrs.h, * v 1.2 89/08/15 18:28:21 rab Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/vm/ds3100.md/RCS/vmPmaxConst.h, * v 9.1 89/09/18 17:33:00 shirriff Exp SPRITE (DECWRL) */ #ifndef _MIPS_CPUREGS_H_ #define _MIPS_CPUREGS_H_ /* * Address space. * 32-bit mips CPUS partition their 32-bit address space into four segments: * * kuseg 0x00000000 - 0x7fffffff User virtual mem, mapped * kseg0 0x80000000 - 0x9fffffff Physical memory, cached, unmapped * kseg1 0xa0000000 - 0xbfffffff Physical memory, uncached, unmapped * kseg2 0xc0000000 - 0xffffffff kernel-virtual, mapped * * mips1 physical memory is limited to 512Mbytes, which is * doubly mapped in kseg0 (cached) and kseg1 (uncached.) * Caching of mapped addresses is controlled by bits in the TLB entry. */ #ifdef _LP64 #define MIPS_XUSEG_START (0L << 62) #define MIPS_XUSEG_P(x) (((uint64_t)(x) >> 62) == 0) #define MIPS_USEG_P(x) ((uintptr_t)(x) < 0x80000000L) #define MIPS_XSSEG_START (1L << 62) #define MIPS_XSSEG_P(x) (((uint64_t)(x) >> 62) == 1) #endif /* * MIPS addresses are signed and we defining as negative so that * in LP64 kern they get sign-extended correctly. */ #ifndef _LOCORE #define MIPS_KSEG0_START (-0x7fffffffL-1) /* 0x80000000 */ #define MIPS_KSEG1_START -0x60000000L /* 0xa0000000 */ #define MIPS_KSEG2_START -0x40000000L /* 0xc0000000 */ #define MIPS_MAX_MEM_ADDR -0x42000000L /* 0xbe000000 */ #define MIPS_RESERVED_ADDR -0x40380000L /* 0xbfc80000 */ #endif #define MIPS_PHYS_MASK 0x1fffffff #define MIPS_KSEG0_TO_PHYS(x) ((uintptr_t)(x) & MIPS_PHYS_MASK) #define MIPS_PHYS_TO_KSEG0(x) ((uintptr_t)(x) | (intptr_t)MIPS_KSEG0_START) #define MIPS_KSEG1_TO_PHYS(x) ((uintptr_t)(x) & MIPS_PHYS_MASK) #define MIPS_PHYS_TO_KSEG1(x) ((uintptr_t)(x) | (intptr_t)MIPS_KSEG1_START) #define MIPS_KSEG0_P(x) (((intptr_t)(x) & ~MIPS_PHYS_MASK) == MIPS_KSEG0_START) #define MIPS_KSEG1_P(x) (((intptr_t)(x) & ~MIPS_PHYS_MASK) == MIPS_KSEG1_START) #define MIPS_KSEG2_P(x) ((uintptr_t)MIPS_KSEG2_START <= (uintptr_t)(x)) /* Map virtual address to index in mips3 r4k virtually-indexed cache */ #define MIPS3_VA_TO_CINDEX(x) \ (((intptr_t)(x) & 0xffffff) | MIPS_KSEG0_START) #ifndef _LOCORE #define MIPS_XSEG_MASK (0x3fffffffffffffffLL) #define MIPS_XKSEG_START (0x3ULL << 62) #define MIPS_XKSEG_P(x) (((uint64_t)(x) >> 62) == 3) #define MIPS_XKPHYS_START (0x2ULL << 62) #define MIPS_PHYS_TO_XKPHYS_UNCACHED(x) \ (MIPS_XKPHYS_START | ((uint64_t)(CCA_UNCACHED) << 59) | (x)) #define MIPS_PHYS_TO_XKPHYS_CACHED(x) \ (mips3_xkphys_cached | (x)) #define MIPS_PHYS_TO_XKPHYS(cca,x) \ (MIPS_XKPHYS_START | ((uint64_t)(cca) << 59) | (x)) #define MIPS_XKPHYS_TO_PHYS(x) ((uint64_t)(x) & 0x07ffffffffffffffLL) #define MIPS_XKPHYS_TO_CCA(x) (((uint64_t)(x) >> 59) & 7) #define MIPS_XKPHYS_P(x) (((uint64_t)(x) >> 62) == 2) #endif /* _LOCORE */ #define CCA_UNCACHED 2 #define CCA_CACHEABLE 3 /* cacheable non-coherent */ /* CPU dependent mtc0 hazard hook */ #define COP0_SYNC /* nothing */ #define COP0_HAZARD_FPUENABLE nop; nop; nop; nop; /* * The bits in the cause register. * * Bits common to r3000 and r4000: * * MIPS_CR_BR_DELAY Exception happened in branch delay slot. * MIPS_CR_COP_ERR Coprocessor error. * MIPS_CR_IP Interrupt pending bits defined below. * (same meaning as in CAUSE register). * MIPS_CR_EXC_CODE The exception type (see exception codes below). * * Differences: * r3k has 4 bits of execption type, r4k has 5 bits. */ #define MIPS_CR_BR_DELAY 0x80000000 #define MIPS_CR_COP_ERR 0x30000000 #define MIPS1_CR_EXC_CODE 0x0000003C /* four bits */ #define MIPS3_CR_EXC_CODE 0x0000007C /* five bits */ #define MIPS_CR_IP 0x0000FF00 #define MIPS_CR_EXC_CODE_SHIFT 2 /* * The bits in the status register. All bits are active when set to 1. * * R3000 status register fields: * MIPS_SR_COP_USABILITY Control the usability of the four coprocessors. * MIPS_SR_TS TLB shutdown. * * MIPS_SR_INT_IE Master (current) interrupt enable bit. * * Differences: * r3k has cache control is via frobbing SR register bits, whereas the * r4k cache control is via explicit instructions. * r3k has a 3-entry stack of kernel/user bits, whereas the * r4k has kernel/supervisor/user. */ #define MIPS_SR_COP_USABILITY 0xf0000000 #define MIPS_SR_COP_0_BIT 0x10000000 #define MIPS_SR_COP_1_BIT 0x20000000 /* r4k and r3k differences, see below */ #define MIPS_SR_MX 0x01000000 /* MIPS64 */ #define MIPS_SR_PX 0x00800000 /* MIPS64 */ #define MIPS_SR_BEV 0x00400000 /* Use boot exception vector */ #define MIPS_SR_TS 0x00200000 /* r4k and r3k differences, see below */ #define MIPS_SR_INT_IE 0x00000001 /*#define MIPS_SR_MBZ 0x0f8000c0*/ /* Never used, true for r3k */ /*#define MIPS_SR_INT_MASK 0x0000ff00*/ /* * The R2000/R3000-specific status register bit definitions. * all bits are active when set to 1. * * MIPS_SR_PARITY_ERR Parity error. * MIPS_SR_CACHE_MISS Most recent D-cache load resulted in a miss. * MIPS_SR_PARITY_ZERO Zero replaces outgoing parity bits. * MIPS_SR_SWAP_CACHES Swap I-cache and D-cache. * MIPS_SR_ISOL_CACHES Isolate D-cache from main memory. * Interrupt enable bits defined below. * MIPS_SR_KU_OLD Old kernel/user mode bit. 1 => user mode. * MIPS_SR_INT_ENA_OLD Old interrupt enable bit. * MIPS_SR_KU_PREV Previous kernel/user mode bit. 1 => user mode. * MIPS_SR_INT_ENA_PREV Previous interrupt enable bit. * MIPS_SR_KU_CUR Current kernel/user mode bit. 1 => user mode. */ #define MIPS1_PARITY_ERR 0x00100000 #define MIPS1_CACHE_MISS 0x00080000 #define MIPS1_PARITY_ZERO 0x00040000 #define MIPS1_SWAP_CACHES 0x00020000 #define MIPS1_ISOL_CACHES 0x00010000 #define MIPS1_SR_KU_OLD 0x00000020 /* 2nd stacked KU/IE*/ #define MIPS1_SR_INT_ENA_OLD 0x00000010 /* 2nd stacked KU/IE*/ #define MIPS1_SR_KU_PREV 0x00000008 /* 1st stacked KU/IE*/ #define MIPS1_SR_INT_ENA_PREV 0x00000004 /* 1st stacked KU/IE*/ #define MIPS1_SR_KU_CUR 0x00000002 /* current KU */ /* backwards compatibility */ #define MIPS_SR_PARITY_ERR MIPS1_PARITY_ERR #define MIPS_SR_CACHE_MISS MIPS1_CACHE_MISS #define MIPS_SR_PARITY_ZERO MIPS1_PARITY_ZERO #define MIPS_SR_SWAP_CACHES MIPS1_SWAP_CACHES #define MIPS_SR_ISOL_CACHES MIPS1_ISOL_CACHES #define MIPS_SR_KU_OLD MIPS1_SR_KU_OLD #define MIPS_SR_INT_ENA_OLD MIPS1_SR_INT_ENA_OLD #define MIPS_SR_KU_PREV MIPS1_SR_KU_PREV #define MIPS_SR_KU_CUR MIPS1_SR_KU_CUR #define MIPS_SR_INT_ENA_PREV MIPS1_SR_INT_ENA_PREV /* * R4000 status register bit definitons, * where different from r2000/r3000. */ #define MIPS3_SR_XX 0x80000000 #define MIPS3_SR_RP 0x08000000 #define MIPS3_SR_FR 0x04000000 #define MIPS3_SR_RE 0x02000000 #define MIPS3_SR_DIAG_DL 0x01000000 /* QED 52xx */ #define MIPS3_SR_DIAG_IL 0x00800000 /* QED 52xx */ #define MIPS3_SR_PX 0x00800000 /* MIPS64 */ #define MIPS3_SR_SR 0x00100000 #define MIPS3_SR_NMI 0x00080000 /* MIPS32/64 */ #define MIPS3_SR_DIAG_CH 0x00040000 #define MIPS3_SR_DIAG_CE 0x00020000 #define MIPS3_SR_DIAG_PE 0x00010000 #define MIPS3_SR_EIE 0x00010000 /* TX79/R5900 */ #define MIPS3_SR_KX 0x00000080 #define MIPS3_SR_SX 0x00000040 #define MIPS3_SR_UX 0x00000020 #define MIPS3_SR_KSU_MASK 0x00000018 #define MIPS3_SR_KSU_USER 0x00000010 #define MIPS3_SR_KSU_SUPER 0x00000008 #define MIPS3_SR_KSU_KERNEL 0x00000000 #define MIPS3_SR_ERL 0x00000004 #define MIPS3_SR_EXL 0x00000002 #ifdef MIPS3_5900 #undef MIPS_SR_INT_IE #define MIPS_SR_INT_IE 0x00010001 /* XXX */ #endif #define MIPS_SR_SOFT_RESET MIPS3_SR_SOFT_RESET #define MIPS_SR_DIAG_CH MIPS3_SR_DIAG_CH #define MIPS_SR_DIAG_CE MIPS3_SR_DIAG_CE #define MIPS_SR_DIAG_PE MIPS3_SR_DIAG_PE #define MIPS_SR_KX MIPS3_SR_KX #define MIPS_SR_SX MIPS3_SR_SX #define MIPS_SR_UX MIPS3_SR_UX #define MIPS_SR_KSU_MASK MIPS3_SR_KSU_MASK #define MIPS_SR_KSU_USER MIPS3_SR_KSU_USER #define MIPS_SR_KSU_SUPER MIPS3_SR_KSU_SUPER #define MIPS_SR_KSU_KERNEL MIPS3_SR_KSU_KERNEL #define MIPS_SR_ERL MIPS3_SR_ERL #define MIPS_SR_EXL MIPS3_SR_EXL /* * The interrupt masks. * If a bit in the mask is 1 then the interrupt is enabled (or pending). */ #define MIPS_INT_MASK 0xff00 #define MIPS_INT_MASK_5 0x8000 #define MIPS_INT_MASK_4 0x4000 #define MIPS_INT_MASK_3 0x2000 #define MIPS_INT_MASK_2 0x1000 #define MIPS_INT_MASK_1 0x0800 #define MIPS_INT_MASK_0 0x0400 #define MIPS_HARD_INT_MASK 0xfc00 #define MIPS_SOFT_INT_MASK_1 0x0200 #define MIPS_SOFT_INT_MASK_0 0x0100 /* * mips3 CPUs have on-chip timer at INT_MASK_5. Each platform can * choose to enable this interrupt. */ #if defined(MIPS3_ENABLE_CLOCK_INTR) #define MIPS3_INT_MASK MIPS_INT_MASK #define MIPS3_HARD_INT_MASK MIPS_HARD_INT_MASK #else #define MIPS3_INT_MASK (MIPS_INT_MASK & ~MIPS_INT_MASK_5) #define MIPS3_HARD_INT_MASK (MIPS_HARD_INT_MASK & ~MIPS_INT_MASK_5) #endif /* * The bits in the context register. */ #define MIPS1_CNTXT_PTE_BASE 0xFFE00000 #define MIPS1_CNTXT_BAD_VPN 0x001FFFFC #define MIPS3_CNTXT_PTE_BASE 0xFF800000 #define MIPS3_CNTXT_BAD_VPN2 0x007FFFF0 /* * The bits in the MIPS3 config register. * * bit 0..5: R/W, Bit 6..31: R/O */ /* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ #define MIPS3_CONFIG_K0_MASK 0x00000007 /* * R/W Update on Store Conditional * 0: Store Conditional uses coherency algorithm specified by TLB * 1: Store Conditional uses cacheable coherent update on write */ #define MIPS3_CONFIG_CU 0x00000008 #define MIPS3_CONFIG_DB 0x00000010 /* Primary D-cache line size */ #define MIPS3_CONFIG_IB 0x00000020 /* Primary I-cache line size */ #define MIPS3_CONFIG_CACHE_L1_LSIZE(config, bit) \ (((config) & (bit)) ? 32 : 16) #define MIPS3_CONFIG_DC_MASK 0x000001c0 /* Primary D-cache size */ #define MIPS3_CONFIG_DC_SHIFT 6 #define MIPS3_CONFIG_IC_MASK 0x00000e00 /* Primary I-cache size */ #define MIPS3_CONFIG_IC_SHIFT 9 #define MIPS3_CONFIG_C_DEFBASE 0x1000 /* default base 2^12 */ /* Cache size mode indication: available only on Vr41xx CPUs */ #define MIPS3_CONFIG_CS 0x00001000 #define MIPS3_CONFIG_C_4100BASE 0x0400 /* base is 2^10 if CS=1 */ #define MIPS3_CONFIG_CACHE_SIZE(config, mask, base, shift) \ ((base) << (((config) & (mask)) >> (shift))) /* External cache enable: Controls L2 for R5000/Rm527x and L3 for Rm7000 */ #define MIPS3_CONFIG_SE 0x00001000 /* Block ordering: 0: sequential, 1: sub-block */ #define MIPS3_CONFIG_EB 0x00002000 /* ECC mode - 0: ECC mode, 1: parity mode */ #define MIPS3_CONFIG_EM 0x00004000 /* BigEndianMem - 0: kernel and memory are little endian, 1: big endian */ #define MIPS3_CONFIG_BE 0x00008000 /* Dirty Shared coherency state - 0: enabled, 1: disabled */ #define MIPS3_CONFIG_SM 0x00010000 /* Secondary Cache - 0: present, 1: not present */ #define MIPS3_CONFIG_SC 0x00020000 /* System Port width - 0: 64-bit, 1: 32-bit (QED RM523x), 2,3: reserved */ #define MIPS3_CONFIG_EW_MASK 0x000c0000 #define MIPS3_CONFIG_EW_SHIFT 18 /* Secondary Cache port width - 0: 128-bit data path to S-cache, 1: reserved */ #define MIPS3_CONFIG_SW 0x00100000 /* Split Secondary Cache Mode - 0: I/D mixed, 1: I/D separated by SCAddr(17) */ #define MIPS3_CONFIG_SS 0x00200000 /* Secondary Cache line size */ #define MIPS3_CONFIG_SB_MASK 0x00c00000 #define MIPS3_CONFIG_SB_SHIFT 22 #define MIPS3_CONFIG_CACHE_L2_LSIZE(config) \ (0x10 << (((config) & MIPS3_CONFIG_SB_MASK) >> MIPS3_CONFIG_SB_SHIFT)) /* Write back data rate */ #define MIPS3_CONFIG_EP_MASK 0x0f000000 #define MIPS3_CONFIG_EP_SHIFT 24 /* System clock ratio - this value is CPU dependent */ #define MIPS3_CONFIG_EC_MASK 0x70000000 #define MIPS3_CONFIG_EC_SHIFT 28 /* Master-Checker Mode - 1: enabled */ #define MIPS3_CONFIG_CM 0x80000000 /* * The bits in the MIPS4 config register. */ /* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ #define MIPS4_CONFIG_K0_MASK MIPS3_CONFIG_K0_MASK #define MIPS4_CONFIG_DN_MASK 0x00000018 /* Device number */ #define MIPS4_CONFIG_CT 0x00000020 /* CohPrcReqTar */ #define MIPS4_CONFIG_PE 0x00000040 /* PreElmReq */ #define MIPS4_CONFIG_PM_MASK 0x00000180 /* PreReqMax */ #define MIPS4_CONFIG_EC_MASK 0x00001e00 /* SysClkDiv */ #define MIPS4_CONFIG_SB 0x00002000 /* SCBlkSize */ #define MIPS4_CONFIG_SK 0x00004000 /* SCColEn */ #define MIPS4_CONFIG_BE 0x00008000 /* MemEnd */ #define MIPS4_CONFIG_SS_MASK 0x00070000 /* SCSize */ #define MIPS4_CONFIG_SC_MASK 0x00380000 /* SCClkDiv */ #define MIPS4_CONFIG_RESERVED 0x03c00000 /* Reserved wired 0 */ #define MIPS4_CONFIG_DC_MASK 0x1c000000 /* Primary D-Cache size */ #define MIPS4_CONFIG_IC_MASK 0xe0000000 /* Primary I-Cache size */ #define MIPS4_CONFIG_DC_SHIFT 26 #define MIPS4_CONFIG_IC_SHIFT 29 #define MIPS4_CONFIG_CACHE_SIZE(config, mask, base, shift) \ ((base) << (((config) & (mask)) >> (shift))) #define MIPS4_CONFIG_CACHE_L2_LSIZE(config) \ (((config) & MIPS4_CONFIG_SB) ? 128 : 64) /* * Location of exception vectors. * * Common vectors: reset and UTLB miss. */ #define MIPS_RESET_EXC_VEC MIPS_PHYS_TO_KSEG1(0x1FC00000) #define MIPS_UTLB_MISS_EXC_VEC MIPS_PHYS_TO_KSEG0(0) /* * MIPS-1 general exception vector (everything else) */ #define MIPS1_GEN_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0080) /* * MIPS-III exception vectors */ #define MIPS3_XTLB_MISS_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0080) #define MIPS3_CACHE_ERR_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0100) #define MIPS3_GEN_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0180) /* * TX79 (R5900) exception vectors */ #define MIPS_R5900_COUNTER_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0080) #define MIPS_R5900_DEBUG_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0100) /* * MIPS32/MIPS64 (and some MIPS3) dedicated interrupt vector. */ #define MIPS3_INTR_EXC_VEC MIPS_PHYS_TO_KSEG0(0x0200) /* * Coprocessor 0 registers: * * v--- width for mips I,III,32,64 * (3=32bit, 6=64bit, i=impl dep) * 0 MIPS_COP_0_TLB_INDEX 3333 TLB Index. * 1 MIPS_COP_0_TLB_RANDOM 3333 TLB Random. * 2 MIPS_COP_0_TLB_LOW 3... r3k TLB entry low. * 2 MIPS_COP_0_TLB_LO0 .636 r4k TLB entry low. * 3 MIPS_COP_0_TLB_LO1 .636 r4k TLB entry low, extended. * 4 MIPS_COP_0_TLB_CONTEXT 3636 TLB Context. * 5 MIPS_COP_0_TLB_PG_MASK .333 TLB Page Mask register. * 6 MIPS_COP_0_TLB_WIRED .333 Wired TLB number. * 8 MIPS_COP_0_BAD_VADDR 3636 Bad virtual address. * 9 MIPS_COP_0_COUNT .333 Count register. * 10 MIPS_COP_0_TLB_HI 3636 TLB entry high. * 11 MIPS_COP_0_COMPARE .333 Compare (against Count). * 12 MIPS_COP_0_STATUS 3333 Status register. * 13 MIPS_COP_0_CAUSE 3333 Exception cause register. * 14 MIPS_COP_0_EXC_PC 3636 Exception PC. * 15 MIPS_COP_0_PRID 3333 Processor revision identifier. * 15/1 MIPS_COP_0_EBASE ..33 Exception Base * 16 MIPS_COP_0_CONFIG 3333 Configuration register. * 16/1 MIPS_COP_0_CONFIG1 ..33 Configuration register 1. * 16/2 MIPS_COP_0_CONFIG2 ..33 Configuration register 2. * 16/3 MIPS_COP_0_CONFIG3 ..33 Configuration register 3. * 17 MIPS_COP_0_LLADDR .336 Load Linked Address. * 18 MIPS_COP_0_WATCH_LO .336 WatchLo register. * 19 MIPS_COP_0_WATCH_HI .333 WatchHi register. * 20 MIPS_COP_0_TLB_XCONTEXT .6.6 TLB XContext register. * 23 MIPS_COP_0_DEBUG .... Debug JTAG register. * 24 MIPS_COP_0_DEPC .... DEPC JTAG register. * 25 MIPS_COP_0_PERFCNT ..36 Performance Counter register. * 26 MIPS_COP_0_ECC .3ii ECC / Error Control register. * 27 MIPS_COP_0_CACHE_ERR .3ii Cache Error register. * 28/0 MIPS_COP_0_TAG_LO .3ii Cache TagLo register (instr). * 28/1 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (instr). * 28/2 MIPS_COP_0_TAG_LO ..ii Cache TagLo register (data). * 28/3 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (data). * 29/0 MIPS_COP_0_TAG_HI .3ii Cache TagHi register (instr). * 29/1 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (instr). * 29/2 MIPS_COP_0_TAG_HI ..ii Cache TagHi register (data). * 29/3 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (data). * 30 MIPS_COP_0_ERROR_PC .636 Error EPC register. * 31 MIPS_COP_0_DESAVE .... DESAVE JTAG register. */ #ifdef _LOCORE #define _(n) __CONCAT($,n) #else #define _(n) n #endif #define MIPS_COP_0_TLB_INDEX _(0) #define MIPS_COP_0_TLB_RANDOM _(1) /* Name and meaning of TLB bits for $2 differ on r3k and r4k. */ #define MIPS_COP_0_TLB_CONTEXT _(4) /* $5 and $6 new with MIPS-III */ #define MIPS_COP_0_BAD_VADDR _(8) #define MIPS_COP_0_TLB_HI _(10) #define MIPS_COP_0_STATUS _(12) #define MIPS_COP_0_CAUSE _(13) #define MIPS_COP_0_EXC_PC _(14) #define MIPS_COP_0_PRID _(15) /* MIPS-I */ #define MIPS_COP_0_TLB_LOW _(2) /* MIPS-III */ #define MIPS_COP_0_TLB_LO0 _(2) #define MIPS_COP_0_TLB_LO1 _(3) #define MIPS_COP_0_TLB_PG_MASK _(5) #define MIPS_COP_0_TLB_WIRED _(6) #define MIPS_COP_0_COUNT _(9) #define MIPS_COP_0_COMPARE _(11) #define MIPS_COP_0_CONFIG _(16) #define MIPS_COP_0_LLADDR _(17) #define MIPS_COP_0_WATCH_LO _(18) #define MIPS_COP_0_WATCH_HI _(19) #define MIPS_COP_0_TLB_XCONTEXT _(20) #define MIPS_COP_0_ECC _(26) #define MIPS_COP_0_CACHE_ERR _(27) #define MIPS_COP_0_TAG_LO _(28) #define MIPS_COP_0_TAG_HI _(29) #define MIPS_COP_0_ERROR_PC _(30) /* MIPS32/64 */ #define MIPS_COP_0_DEBUG _(23) #define MIPS_COP_0_DEPC _(24) #define MIPS_COP_0_PERFCNT _(25) #define MIPS_COP_0_DATA_LO _(28) #define MIPS_COP_0_DATA_HI _(29) #define MIPS_COP_0_DESAVE _(31) /* * Values for the code field in a break instruction. */ #define MIPS_BREAK_INSTR 0x0000000d #define MIPS_BREAK_VAL_MASK 0x03ff0000 #define MIPS_BREAK_VAL_SHIFT 16 #define MIPS_BREAK_KDB_VAL 512 #define MIPS_BREAK_SSTEP_VAL 513 #define MIPS_BREAK_BRKPT_VAL 514 #define MIPS_BREAK_SOVER_VAL 515 #define MIPS_BREAK_KDB (MIPS_BREAK_INSTR | \ (MIPS_BREAK_KDB_VAL << MIPS_BREAK_VAL_SHIFT)) #define MIPS_BREAK_SSTEP (MIPS_BREAK_INSTR | \ (MIPS_BREAK_SSTEP_VAL << MIPS_BREAK_VAL_SHIFT)) #define MIPS_BREAK_BRKPT (MIPS_BREAK_INSTR | \ (MIPS_BREAK_BRKPT_VAL << MIPS_BREAK_VAL_SHIFT)) #define MIPS_BREAK_SOVER (MIPS_BREAK_INSTR | \ (MIPS_BREAK_SOVER_VAL << MIPS_BREAK_VAL_SHIFT)) /* * Mininum and maximum cache sizes. */ #define MIPS_MIN_CACHE_SIZE (16 * 1024) #define MIPS_MAX_CACHE_SIZE (256 * 1024) #define MIPS3_MAX_PCACHE_SIZE (32 * 1024) /* max. primary cache size */ /* * The floating point version and status registers. */ #define MIPS_FPU_ID $0 #define MIPS_FPU_CSR $31 /* * The floating point coprocessor status register bits. */ #define MIPS_FPU_ROUNDING_BITS 0x00000003 #define MIPS_FPU_ROUND_RN 0x00000000 #define MIPS_FPU_ROUND_RZ 0x00000001 #define MIPS_FPU_ROUND_RP 0x00000002 #define MIPS_FPU_ROUND_RM 0x00000003 #define MIPS_FPU_STICKY_BITS 0x0000007c #define MIPS_FPU_STICKY_INEXACT 0x00000004 #define MIPS_FPU_STICKY_UNDERFLOW 0x00000008 #define MIPS_FPU_STICKY_OVERFLOW 0x00000010 #define MIPS_FPU_STICKY_DIV0 0x00000020 #define MIPS_FPU_STICKY_INVALID 0x00000040 #define MIPS_FPU_ENABLE_BITS 0x00000f80 #define MIPS_FPU_ENABLE_INEXACT 0x00000080 #define MIPS_FPU_ENABLE_UNDERFLOW 0x00000100 #define MIPS_FPU_ENABLE_OVERFLOW 0x00000200 #define MIPS_FPU_ENABLE_DIV0 0x00000400 #define MIPS_FPU_ENABLE_INVALID 0x00000800 #define MIPS_FPU_EXCEPTION_BITS 0x0003f000 #define MIPS_FPU_EXCEPTION_INEXACT 0x00001000 #define MIPS_FPU_EXCEPTION_UNDERFLOW 0x00002000 #define MIPS_FPU_EXCEPTION_OVERFLOW 0x00004000 #define MIPS_FPU_EXCEPTION_DIV0 0x00008000 #define MIPS_FPU_EXCEPTION_INVALID 0x00010000 #define MIPS_FPU_EXCEPTION_UNIMPL 0x00020000 #define MIPS_FPU_COND_BIT 0x00800000 #define MIPS_FPU_FLUSH_BIT 0x01000000 /* r4k, MBZ on r3k */ #define MIPS1_FPC_MBZ_BITS 0xff7c0000 #define MIPS3_FPC_MBZ_BITS 0xfe7c0000 /* * Constants to determine if have a floating point instruction. */ #define MIPS_OPCODE_SHIFT 26 #define MIPS_OPCODE_C1 0x11 /* * The low part of the TLB entry. */ #define MIPS1_TLB_PFN 0xfffff000 #define MIPS1_TLB_NON_CACHEABLE_BIT 0x00000800 #define MIPS1_TLB_DIRTY_BIT 0x00000400 #define MIPS1_TLB_VALID_BIT 0x00000200 #define MIPS1_TLB_GLOBAL_BIT 0x00000100 #define MIPS3_TLB_PFN 0x3fffffc0 #define MIPS3_TLB_ATTR_MASK 0x00000038 #define MIPS3_TLB_ATTR_SHIFT 3 #define MIPS3_TLB_DIRTY_BIT 0x00000004 #define MIPS3_TLB_VALID_BIT 0x00000002 #define MIPS3_TLB_GLOBAL_BIT 0x00000001 #define MIPS1_TLB_PHYS_PAGE_SHIFT 12 #define MIPS3_TLB_PHYS_PAGE_SHIFT 6 #define MIPS1_TLB_PF_NUM MIPS1_TLB_PFN #define MIPS3_TLB_PF_NUM MIPS3_TLB_PFN #define MIPS1_TLB_MOD_BIT MIPS1_TLB_DIRTY_BIT #define MIPS3_TLB_MOD_BIT MIPS3_TLB_DIRTY_BIT /* * MIPS3_TLB_ATTR values - coherency algorithm: * 0: cacheable, noncoherent, write-through, no write allocate * 1: cacheable, noncoherent, write-through, write allocate * 2: uncached * 3: cacheable, noncoherent, write-back (noncoherent) * 4: cacheable, coherent, write-back, exclusive (exclusive) * 5: cacheable, coherent, write-back, exclusive on write (sharable) * 6: cacheable, coherent, write-back, update on write (update) * 7: uncached, accelerated (gather STORE operations) */ #define MIPS3_TLB_ATTR_WT 0 /* IDT */ #define MIPS3_TLB_ATTR_WT_WRITEALLOCATE 1 /* IDT */ #define MIPS3_TLB_ATTR_UNCACHED 2 /* R4000/R4400, IDT */ #define MIPS3_TLB_ATTR_WB_NONCOHERENT 3 /* R4000/R4400, IDT */ #define MIPS3_TLB_ATTR_WB_EXCLUSIVE 4 /* R4000/R4400 */ #define MIPS3_TLB_ATTR_WB_SHARABLE 5 /* R4000/R4400 */ #define MIPS3_TLB_ATTR_WB_UPDATE 6 /* R4000/R4400 */ #define MIPS4_TLB_ATTR_UNCACHED_ACCELERATED 7 /* R10000 */ /* * The high part of the TLB entry. */ #define MIPS1_TLB_VPN 0xfffff000 #define MIPS1_TLB_PID 0x00000fc0 #define MIPS1_TLB_PID_SHIFT 6 #define MIPS3_TLB_VPN2 0xffffe000 #define MIPS3_TLB_ASID 0x000000ff #define MIPS1_TLB_VIRT_PAGE_NUM MIPS1_TLB_VPN #define MIPS3_TLB_VIRT_PAGE_NUM MIPS3_TLB_VPN2 #define MIPS3_TLB_PID MIPS3_TLB_ASID #define MIPS_TLB_VIRT_PAGE_SHIFT 12 /* * r3000: shift count to put the index in the right spot. */ #define MIPS1_TLB_INDEX_SHIFT 8 /* * The first TLB that write random hits. */ #define MIPS1_TLB_FIRST_RAND_ENTRY 8 #define MIPS3_TLB_WIRED_UPAGES 1 /* * The number of process id entries. */ #define MIPS1_TLB_NUM_PIDS 64 #define MIPS3_TLB_NUM_ASIDS 256 /* * Patch codes to hide CPU design differences between MIPS1 and MIPS3. */ /* XXX simonb: this is before MIPS3_PLUS is defined (and is ugly!) */ #if !(defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ && defined(MIPS1) /* XXX simonb must be neater! */ #define MIPS_TLB_PID_SHIFT MIPS1_TLB_PID_SHIFT #define MIPS_TLB_NUM_PIDS MIPS1_TLB_NUM_PIDS #endif #if (defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ && !defined(MIPS1) /* XXX simonb must be neater! */ #define MIPS_TLB_PID_SHIFT 0 #define MIPS_TLB_NUM_PIDS MIPS3_TLB_NUM_ASIDS #endif #if !defined(MIPS_TLB_PID_SHIFT) #define MIPS_TLB_PID_SHIFT \ ((MIPS_HAS_R4K_MMU) ? 0 : MIPS1_TLB_PID_SHIFT) #define MIPS_TLB_NUM_PIDS \ ((MIPS_HAS_R4K_MMU) ? MIPS3_TLB_NUM_ASIDS : MIPS1_TLB_NUM_PIDS) #endif /* * CPU processor revision IDs for company ID == 0 (non mips32/64 chips) */ #define MIPS_R2000 0x01 /* MIPS R2000 ISA I */ #define MIPS_R3000 0x02 /* MIPS R3000 ISA I */ #define MIPS_R6000 0x03 /* MIPS R6000 ISA II */ #define MIPS_R4000 0x04 /* MIPS R4000/R4400 ISA III */ #define MIPS_R3LSI 0x05 /* LSI Logic R3000 derivative ISA I */ #define MIPS_R6000A 0x06 /* MIPS R6000A ISA II */ #define MIPS_R3IDT 0x07 /* IDT R3041 or RC36100 ISA I */ #define MIPS_R10000 0x09 /* MIPS R10000 ISA IV */ #define MIPS_R4200 0x0a /* NEC VR4200 ISA III */ #define MIPS_R4300 0x0b /* NEC VR4300 ISA III */ #define MIPS_R4100 0x0c /* NEC VR4100 ISA III */ #define MIPS_R12000 0x0e /* MIPS R12000 ISA IV */ #define MIPS_R14000 0x0f /* MIPS R14000 ISA IV */ #define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ #define MIPS_RC32300 0x18 /* IDT RC32334,332,355 ISA 32 */ #define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ #define MIPS_R4700 0x21 /* QED R4700 Orion ISA III */ #define MIPS_R3SONY 0x21 /* Sony R3000 based ISA I */ #define MIPS_R4650 0x22 /* QED R4650 ISA III */ #define MIPS_TX3900 0x22 /* Toshiba TX39 family ISA I */ #define MIPS_R5000 0x23 /* MIPS R5000 ISA IV */ #define MIPS_R3NKK 0x23 /* NKK R3000 based ISA I */ #define MIPS_RC32364 0x26 /* IDT RC32364 ISA 32 */ #define MIPS_RM7000 0x27 /* QED RM7000 ISA IV */ #define MIPS_RM5200 0x28 /* QED RM5200s ISA IV */ #define MIPS_TX4900 0x2d /* Toshiba TX49 family ISA III */ #define MIPS_R5900 0x2e /* Toshiba R5900 (EECore) ISA --- */ #define MIPS_RC64470 0x30 /* IDT RC64474/RC64475 ISA III */ #define MIPS_TX7900 0x38 /* Toshiba TX79 ISA III+*/ #define MIPS_R5400 0x54 /* NEC VR5400 ISA IV */ #define MIPS_R5500 0x55 /* NEC VR5500 ISA IV */ #define MIPS_LOONGSON2 0x63 /* ICT Loongson-2 ISA III */ /* * CPU revision IDs for some prehistoric processors. */ /* For MIPS_R3000 */ #define MIPS_REV_R2000A 0x16 /* R2000A uses R3000 proc revision */ #define MIPS_REV_R3000 0x20 #define MIPS_REV_R3000A 0x30 /* For MIPS_TX3900 */ #define MIPS_REV_TX3912 0x10 #define MIPS_REV_TX3922 0x30 #define MIPS_REV_TX3927 0x40 /* For MIPS_R4000 */ #define MIPS_REV_R4000_A 0x00 #define MIPS_REV_R4000_B 0x22 #define MIPS_REV_R4000_C 0x30 #define MIPS_REV_R4400_A 0x40 #define MIPS_REV_R4400_B 0x50 #define MIPS_REV_R4400_C 0x60 /* For MIPS_TX4900 */ #define MIPS_REV_TX4927 0x22 /* For MIPS_LOONGSON2 */ #define MIPS_REV_LOONGSON2E 0x02 #define MIPS_REV_LOONGSON2F 0x03 /* * CPU processor revision IDs for company ID == 1 (MIPS) */ #define MIPS_4Kc 0x80 /* MIPS 4Kc ISA 32 */ #define MIPS_5Kc 0x81 /* MIPS 5Kc ISA 64 */ #define MIPS_20Kc 0x82 /* MIPS 20Kc ISA 64 */ #define MIPS_4Kmp 0x83 /* MIPS 4Km/4Kp ISA 32 */ #define MIPS_4KEc 0x84 /* MIPS 4KEc ISA 32 */ #define MIPS_4KEmp 0x85 /* MIPS 4KEm/4KEp ISA 32 */ #define MIPS_4KSc 0x86 /* MIPS 4KSc ISA 32 */ #define MIPS_M4K 0x87 /* MIPS M4K ISA 32 Rel 2 */ #define MIPS_25Kf 0x88 /* MIPS 25Kf ISA 64 */ #define MIPS_5KE 0x89 /* MIPS 5KE ISA 64 Rel 2 */ #define MIPS_4KEc_R2 0x90 /* MIPS 4KEc_R2 ISA 32 Rel 2 */ #define MIPS_4KEmp_R2 0x91 /* MIPS 4KEm/4KEp_R2 ISA 32 Rel 2 */ #define MIPS_4KSd 0x92 /* MIPS 4KSd ISA 32 Rel 2 */ #define MIPS_24K 0x93 /* MIPS 24Kc/24Kf ISA 32 Rel 2 */ #define MIPS_34K 0x95 /* MIPS 34K ISA 32 R2 MT */ #define MIPS_24KE 0x96 /* MIPS 24KEc ISA 32 Rel 2 */ #define MIPS_74K 0x97 /* MIPS 74Kc/74Kf ISA 32 Rel 2 */ /* * Alchemy (company ID 3) use the processor ID field to donote the CPU core * revision and the company options field do donate the SOC chip type. */ /* CPU processor revision IDs */ #define MIPS_AU_REV1 0x01 /* Alchemy Au1000 (Rev 1) ISA 32 */ #define MIPS_AU_REV2 0x02 /* Alchemy Au1000 (Rev 2) ISA 32 */ /* CPU company options IDs */ #define MIPS_AU1000 0x00 #define MIPS_AU1500 0x01 #define MIPS_AU1100 0x02 #define MIPS_AU1550 0x03 /* * CPU processor revision IDs for company ID == 4 (SiByte) */ #define MIPS_SB1 0x01 /* SiByte SB1 ISA 64 */ /* * CPU processor revision IDs for company ID == 5 (SandCraft) */ #define MIPS_SR7100 0x04 /* SandCraft SR7100 ISA 64 */ /* * CPU processor revision IDs for company ID == 12 (RMI) */ #define MIPS_XLR732 0x00 /* RMI XLR732-C ISA 64 */ #define MIPS_XLR716 0x02 /* RMI XLR716-C ISA 64 */ #define MIPS_XLR532 0x08 /* RMI XLR532-C ISA 64 */ #define MIPS_XLR516 0x0a /* RMI XLR516-C ISA 64 */ #define MIPS_XLR508 0x0b /* RMI XLR508-C ISA 64 */ #define MIPS_XLR308 0x0f /* RMI XLR308-C ISA 64 */ #define MIPS_XLS616 0x40 /* RMI XLS616 ISA 64 */ #define MIPS_XLS416 0x44 /* RMI XLS416 ISA 64 */ #define MIPS_XLS608 0x4A /* RMI XLS608 ISA 64 */ #define MIPS_XLS408 0x4E /* RMI XLS406 ISA 64 */ #define MIPS_XLS404 0x4F /* RMI XLS404 ISA 64 */ #define MIPS_XLS408LITE 0x88 /* RMI XLS408-Lite ISA 64 */ #define MIPS_XLS404LITE 0x8C /* RMI XLS404-Lite ISA 64 */ #define MIPS_XLS208 0x8E /* RMI XLS208 ISA 64 */ #define MIPS_XLS204 0x8F /* RMI XLS204 ISA 64 */ #define MIPS_XLS108 0xCE /* RMI XLS108 ISA 64 */ #define MIPS_XLS104 0xCF /* RMI XLS104 ISA 64 */ /* * FPU processor revision ID */ #define MIPS_SOFT 0x00 /* Software emulation ISA I */ #define MIPS_R2360 0x01 /* MIPS R2360 FPC ISA I */ #define MIPS_R2010 0x02 /* MIPS R2010 FPC ISA I */ #define MIPS_R3010 0x03 /* MIPS R3010 FPC ISA I */ #define MIPS_R6010 0x04 /* MIPS R6010 FPC ISA II */ #define MIPS_R4010 0x05 /* MIPS R4010 FPC ISA II */ #define MIPS_R31LSI 0x06 /* LSI Logic derivate ISA I */ #define MIPS_R3TOSH 0x22 /* Toshiba R3000 based FPU ISA I */ #endif /* _MIPS_CPUREGS_H_ */ /* $NetBSD: cpu.h,v 1.94 2009/12/14 00:46:04 matt Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cpu.h 8.4 (Berkeley) 1/4/94 */ #ifndef _CPU_H_ #define _CPU_H_ /* * bitfield defines for cpu_cp0flags */ #define MIPS_CP0FL_USE __BIT(0) /* use these flags */ #define MIPS_CP0FL_ECC __BIT(1) #define MIPS_CP0FL_CACHE_ERR __BIT(2) #define MIPS_CP0FL_EIRR __BIT(3) #define MIPS_CP0FL_EIMR __BIT(4) #define MIPS_CP0FL_EBASE __BIT(5) #define MIPS_CP0FL_CONFIG __BIT(6) #define MIPS_CP0FL_CONFIGn(n) (__BIT(7) << ((n) & 7)) /* * cpu_cidflags defines, by company */ /* * RMI company-specific cpu_cidflags */ #define MIPS_CIDFL_RMI_TYPE __BITS(0,2) #define CIDFL_RMI_TYPE_XLR 0 #define CIDFL_RMI_TYPE_XLS 1 #define CIDFL_RMI_TYPE_XLP 2 #define CPU_INFO_ITERATOR int #define CPU_INFO_FOREACH(cii, ci) \ (void)(cii), ci = &cpu_info_store; ci != NULL; ci = ci->ci_next /* * CTL_MACHDEP definitions. */ #define CPU_CONSDEV 1 /* dev_t: console terminal device */ #define CPU_BOOTED_KERNEL 2 /* string: booted kernel name */ #define CPU_ROOT_DEVICE 3 /* string: root device name */ #define CPU_LLSC 4 /* OS/CPU supports LL/SC instruction */ /* * Platform can override, but note this breaks userland compatibility * with other mips platforms. */ #ifndef CPU_MAXID #define CPU_MAXID 5 /* number of valid machdep ids */ #endif #ifdef _KERNEL #if defined(_LKM) || defined(_STANDALONE) /* Assume all CPU architectures are valid for LKM's and standlone progs */ #define MIPS1 1 #define MIPS3 1 #define MIPS4 1 #define MIPS32 1 #define MIPS64 1 #endif #if (MIPS1 + MIPS3 + MIPS4 + MIPS32 + MIPS64) == 0 #error at least one of MIPS1, MIPS3, MIPS4, MIPS32 or MIPS64 must be specified #endif /* Shortcut for MIPS3 or above defined */ #if defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64) #define MIPS3_PLUS 1 #else #undef MIPS3_PLUS #endif /* * Macros to find the CPU architecture we're on at run-time, * or if possible, at compile-time. */ #define CPU_ARCH_MIPSx 0 /* XXX unknown */ #define CPU_ARCH_MIPS1 (1 << 0) #define CPU_ARCH_MIPS2 (1 << 1) #define CPU_ARCH_MIPS3 (1 << 2) #define CPU_ARCH_MIPS4 (1 << 3) #define CPU_ARCH_MIPS5 (1 << 4) #define CPU_ARCH_MIPS32 (1 << 5) #define CPU_ARCH_MIPS64 (1 << 6) /* Note: must be kept in sync with -ffixed-?? Makefile.mips. */ #define MIPS_CURLWP $23 #define MIPS_CURLWP_QUOTED "$23" #define MIPS_CURLWP_CARD 23 #define MIPS_CURLWP_FRAME(x) FRAME_S7(x) #ifndef _LOCORE #define curlwp mips_curlwp #define curcpu() (curlwp->l_cpu) #define curpcb ((struct pcb *)lwp_getpcb(curlwp)) #define fpcurlwp (curcpu()->ci_fpcurlwp) #define cpu_number() (0) #define cpu_proc_fork(p1, p2) ((void)((p2)->p_md.md_abi = (p1)->p_md.md_abi)) /* XXX simonb * Should the following be in a cpu_info type structure? * And how many of these are per-cpu vs. per-system? (Ie, * we can assume that all cpus have the same mmu-type, but * maybe not that all cpus run at the same clock speed. * Some SGI's apparently support R12k and R14k in the same * box.) */ #define CPU_MIPS_R4K_MMU 0x0001 #define CPU_MIPS_NO_LLSC 0x0002 #define CPU_MIPS_CAUSE_IV 0x0004 #define CPU_MIPS_HAVE_SPECIAL_CCA 0x0008 /* Defaults to '3' if not set. */ #define CPU_MIPS_CACHED_CCA_MASK 0x0070 #define CPU_MIPS_CACHED_CCA_SHIFT 4 #define CPU_MIPS_DOUBLE_COUNT 0x0080 /* 1 cp0 count == 2 clock cycles */ #define CPU_MIPS_USE_WAIT 0x0100 /* Use "wait"-based cpu_idle() */ #define CPU_MIPS_NO_WAIT 0x0200 /* Inverse of previous, for mips32/64 */ #define CPU_MIPS_D_CACHE_COHERENT 0x0400 /* D-cache is fully coherent */ #define CPU_MIPS_I_D_CACHE_COHERENT 0x0800 /* I-cache funcs don't need to flush the D-cache */ #define CPU_MIPS_NO_LLADDR 0x1000 #define CPU_MIPS_HAVE_MxCR 0x2000 /* have mfcr, mtcr insns */ #define MIPS_NOT_SUPP 0x8000 #endif /* !_LOCORE */ #if ((MIPS1 + MIPS3 + MIPS4 + MIPS32 + MIPS64) == 1) || defined(_LOCORE) #if defined(MIPS1) # define CPUISMIPS3 0 # define CPUIS64BITS 0 # define CPUISMIPS32 0 # define CPUISMIPS64 0 # define CPUISMIPSNN 0 # define MIPS_HAS_R4K_MMU 0 # define MIPS_HAS_CLOCK 0 # define MIPS_HAS_LLSC 0 # define MIPS_HAS_LLADDR 0 #elif defined(MIPS3) || defined(MIPS4) # define CPUISMIPS3 1 # define CPUIS64BITS 1 # define CPUISMIPS32 0 # define CPUISMIPS64 0 # define CPUISMIPSNN 0 # define MIPS_HAS_R4K_MMU 1 # define MIPS_HAS_CLOCK 1 # if defined(_LOCORE) # if !defined(MIPS3_5900) && !defined(MIPS3_4100) # define MIPS_HAS_LLSC 1 # else # define MIPS_HAS_LLSC 0 # endif # else /* _LOCORE */ # define MIPS_HAS_LLSC (mips_has_llsc) # endif /* _LOCORE */ # define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) #elif defined(MIPS32) # define CPUISMIPS3 1 # define CPUIS64BITS 0 # define CPUISMIPS32 1 # define CPUISMIPS64 0 # define CPUISMIPSNN 1 # define MIPS_HAS_R4K_MMU 1 # define MIPS_HAS_CLOCK 1 # define MIPS_HAS_LLSC 1 # define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) #elif defined(MIPS64) # define CPUISMIPS3 1 # define CPUIS64BITS 1 # define CPUISMIPS32 0 # define CPUISMIPS64 1 # define CPUISMIPSNN 1 # define MIPS_HAS_R4K_MMU 1 # define MIPS_HAS_CLOCK 1 # define MIPS_HAS_LLSC 1 # define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) #endif #else /* run-time test */ #ifndef _LOCORE #define MIPS_HAS_R4K_MMU (mips_has_r4k_mmu) #define MIPS_HAS_LLSC (mips_has_llsc) #define MIPS_HAS_LLADDR ((mips_cpu_flags & CPU_MIPS_NO_LLADDR) == 0) /* This test is ... rather bogus */ #define CPUISMIPS3 ((cpu_arch & \ (CPU_ARCH_MIPS3 | CPU_ARCH_MIPS4 | CPU_ARCH_MIPS32 | CPU_ARCH_MIPS64)) != 0) /* And these aren't much better while the previous test exists as is... */ #define CPUISMIPS32 ((cpu_arch & CPU_ARCH_MIPS32) != 0) #define CPUISMIPS64 ((cpu_arch & CPU_ARCH_MIPS64) != 0) #define CPUISMIPSNN ((cpu_arch & (CPU_ARCH_MIPS32 | CPU_ARCH_MIPS64)) != 0) #define CPUIS64BITS ((cpu_arch & \ (CPU_ARCH_MIPS3 | CPU_ARCH_MIPS4 | CPU_ARCH_MIPS64)) != 0) #define MIPS_HAS_CLOCK (cpu_arch >= CPU_ARCH_MIPS3) #else /* !_LOCORE */ #define MIPS_HAS_LLSC 0 #endif /* !_LOCORE */ #endif /* run-time test */ #ifndef _LOCORE /* * A port must provde CLKF_USERMODE() for use in machine-independent code. * These differ on r4000 and r3000 systems; provide them in the * port-dependent file that includes this one, using the macros below. */ /* mips1 versions */ #define MIPS1_CLKF_USERMODE(framep) ((framep)->sr & MIPS_SR_KU_PREV) /* mips3 versions */ #define MIPS3_CLKF_USERMODE(framep) ((framep)->sr & MIPS_SR_KSU_USER) #define CLKF_PC(framep) ((framep)->pc) #define CLKF_INTR(framep) (0) #if defined(MIPS3_PLUS) && !defined(MIPS1) /* XXX bogus! */ #define CLKF_USERMODE(framep) MIPS3_CLKF_USERMODE(framep) #endif #if !defined(MIPS3_PLUS) && defined(MIPS1) /* XXX bogus! */ #define CLKF_USERMODE(framep) MIPS1_CLKF_USERMODE(framep) #endif #if defined(MIPS3_PLUS) && defined(MIPS1) /* XXX bogus! */ #define CLKF_USERMODE(framep) \ ((CPUISMIPS3) ? MIPS3_CLKF_USERMODE(framep): MIPS1_CLKF_USERMODE(framep)) #endif /* * This is used during profiling to integrate system time. It can safely * assume that the process is resident. */ #define PROC_PC(p) \ (((struct frame *)(p)->p_md.md_regs)->f_regs[37]) /* XXX PC */ /* * Preempt the current process if in interrupt from user mode, * or after the current trap/syscall if in system mode. */ /* * Give a profiling tick to the current process when the user profiling * buffer pages are invalid. On the MIPS, request an ast to send us * through trap, marking the proc as needing a profiling tick. */ #define cpu_need_proftick(l) \ do { \ (l)->l_pflag |= LP_OWEUPC; \ aston(l); \ } while (/*CONSTCOND*/0) /* * Notify the current lwp (l) that it has a signal pending, * process as soon as possible. */ #define cpu_signotify(l) aston(l) #define aston(l) ((l)->l_md.md_astpending = 1) #endif /* ! _LOCORE */ #endif /* _KERNEL */ #endif /* _CPU_H_ */ /* $NetBSD: mips_opcode.h,v 1.13 2009/08/06 04:34:50 msaitoh Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)mips_opcode.h 8.1 (Berkeley) 6/10/93 */ /* * Define the instruction formats and opcode values for the * MIPS instruction set. */ /* * Define the instruction formats. */ #if defined(M64P_BIG_ENDIAN) /* Big Endian */ typedef union { unsigned word; struct { unsigned op: 6; unsigned rs: 5; unsigned rt: 5; unsigned imm: 16; } IType; struct { unsigned op: 6; unsigned target: 26; } JType; struct { unsigned op: 6; unsigned rs: 5; unsigned rt: 5; unsigned rd: 5; unsigned shamt: 5; unsigned func: 6; } RType; struct { unsigned op: 6; /* always '0x11' */ unsigned : 1; /* always '1' */ unsigned fmt: 4; unsigned ft: 5; unsigned fs: 5; unsigned fd: 5; unsigned func: 6; } FRType; } InstFmt; #else /* Little Endian */ typedef union { unsigned word; struct { unsigned imm: 16; unsigned rt: 5; unsigned rs: 5; unsigned op: 6; } IType; struct { unsigned target: 26; unsigned op: 6; } JType; struct { unsigned func: 6; unsigned shamt: 5; unsigned rd: 5; unsigned rt: 5; unsigned rs: 5; unsigned op: 6; } RType; struct { unsigned func: 6; unsigned fd: 5; unsigned fs: 5; unsigned ft: 5; unsigned fmt: 4; unsigned : 1; /* always '1' */ unsigned op: 6; /* always '0x11' */ } FRType; } InstFmt; #endif /* * Values for the 'op' field. */ #define OP_SPECIAL 000 #define OP_BCOND 001 #define OP_J 002 #define OP_JAL 003 #define OP_BEQ 004 #define OP_BNE 005 #define OP_BLEZ 006 #define OP_BGTZ 007 #define OP_ADDI 010 #define OP_ADDIU 011 #define OP_SLTI 012 #define OP_SLTIU 013 #define OP_ANDI 014 #define OP_ORI 015 #define OP_XORI 016 #define OP_LUI 017 #define OP_COP0 020 #define OP_COP1 021 #define OP_COP2 022 #define OP_COP3 023 #define OP_BEQL 024 /* MIPS-II, for r4000 port */ #define OP_BNEL 025 /* MIPS-II, for r4000 port */ #define OP_BLEZL 026 /* MIPS-II, for r4000 port */ #define OP_BGTZL 027 /* MIPS-II, for r4000 port */ #define OP_DADDI 030 /* MIPS-II, for r4000 port */ #define OP_DADDIU 031 /* MIPS-II, for r4000 port */ #define OP_LDL 032 /* MIPS-II, for r4000 port */ #define OP_LDR 033 /* MIPS-II, for r4000 port */ #define OP_SPECIAL2 034 /* QED opcodes */ #define OP_LB 040 #define OP_LH 041 #define OP_LWL 042 #define OP_LW 043 #define OP_LBU 044 #define OP_LHU 045 #define OP_LWR 046 #define OP_LHU 045 #define OP_LWR 046 #define OP_LWU 047 /* MIPS-II, for r4000 port */ #define OP_SB 050 #define OP_SH 051 #define OP_SWL 052 #define OP_SW 053 #define OP_SDL 054 /* MIPS-II, for r4000 port */ #define OP_SDR 055 /* MIPS-II, for r4000 port */ #define OP_SWR 056 #define OP_CACHE 057 /* MIPS-II, for r4000 port */ #define OP_LL 060 #define OP_LWC0 OP_LL /* backwards source compatibility */ #define OP_LWC1 061 #define OP_LWC2 062 #define OP_LWC3 063 #define OP_LLD 064 /* MIPS-II, for r4000 port */ #define OP_LDC1 065 #define OP_LD 067 /* MIPS-II, for r4000 port */ #define OP_SC 070 #define OP_SWC0 OP_SC /* backwards source compatibility */ #define OP_SWC1 071 #define OP_SWC2 072 #define OP_SWC3 073 #define OP_SCD 074 /* MIPS-II, for r4000 port */ #define OP_SDC1 075 #define OP_SD 077 /* MIPS-II, for r4000 port */ /* * Values for the 'func' field when 'op' == OP_SPECIAL. */ #define OP_SLL 000 #define OP_SRL 002 #define OP_SRA 003 #define OP_SLLV 004 #define OP_SRLV 006 #define OP_SRAV 007 #define OP_JR 010 #define OP_JALR 011 #define OP_SYSCALL 014 #define OP_BREAK 015 #define OP_SYNC 017 /* MIPS-II, for r4000 port */ #define OP_MFHI 020 #define OP_MTHI 021 #define OP_MFLO 022 #define OP_MTLO 023 #define OP_DSLLV 024 /* MIPS-II, for r4000 port */ #define OP_DSRLV 026 /* MIPS-II, for r4000 port */ #define OP_DSRAV 027 /* MIPS-II, for r4000 port */ #define OP_MULT 030 #define OP_MULTU 031 #define OP_DIV 032 #define OP_DIVU 033 #define OP_DMULT 034 /* MIPS-II, for r4000 port */ #define OP_DMULTU 035 /* MIPS-II, for r4000 port */ #define OP_DDIV 036 /* MIPS-II, for r4000 port */ #define OP_DDIVU 037 /* MIPS-II, for r4000 port */ #define OP_ADD 040 #define OP_ADDU 041 #define OP_SUB 042 #define OP_SUBU 043 #define OP_AND 044 #define OP_OR 045 #define OP_XOR 046 #define OP_NOR 047 #define OP_SLT 052 #define OP_SLTU 053 #define OP_DADD 054 /* MIPS-II, for r4000 port */ #define OP_DADDU 055 /* MIPS-II, for r4000 port */ #define OP_DSUB 056 /* MIPS-II, for r4000 port */ #define OP_DSUBU 057 /* MIPS-II, for r4000 port */ #define OP_TGE 060 /* MIPS-II, for r4000 port */ #define OP_TGEU 061 /* MIPS-II, for r4000 port */ #define OP_TLT 062 /* MIPS-II, for r4000 port */ #define OP_TLTU 063 /* MIPS-II, for r4000 port */ #define OP_TEQ 064 /* MIPS-II, for r4000 port */ #define OP_TNE 066 /* MIPS-II, for r4000 port */ #define OP_DSLL 070 /* MIPS-II, for r4000 port */ #define OP_DSRL 072 /* MIPS-II, for r4000 port */ #define OP_DSRA 073 /* MIPS-II, for r4000 port */ #define OP_DSLL32 074 /* MIPS-II, for r4000 port */ #define OP_DSRL32 076 /* MIPS-II, for r4000 port */ #define OP_DSRA32 077 /* MIPS-II, for r4000 port */ /* * Values for the 'func' field when 'op' == OP_SPECIAL2. */ #define OP_MAD 000 /* QED */ #define OP_MADU 001 /* QED */ #define OP_MUL 002 /* QED */ /* * Values for the 'func' field when 'op' == OP_BCOND. */ #define OP_BLTZ 000 #define OP_BGEZ 001 #define OP_BLTZL 002 /* MIPS-II, for r4000 port */ #define OP_BGEZL 003 /* MIPS-II, for r4000 port */ #define OP_TGEI 010 /* MIPS-II, for r4000 port */ #define OP_TGEIU 011 /* MIPS-II, for r4000 port */ #define OP_TLTI 012 /* MIPS-II, for r4000 port */ #define OP_TLTIU 013 /* MIPS-II, for r4000 port */ #define OP_TEQI 014 /* MIPS-II, for r4000 port */ #define OP_TNEI 016 /* MIPS-II, for r4000 port */ #define OP_BLTZAL 020 /* MIPS-II, for r4000 port */ #define OP_BGEZAL 021 #define OP_BLTZALL 022 #define OP_BGEZALL 023 /* * Values for the 'rs' field when 'op' == OP_COPz. */ #define OP_MF 000 #define OP_DMF 001 /* MIPS-II, for r4000 port */ #define OP_CF 002 #define OP_MFH 003 #define OP_MT 004 #define OP_DMT 005 /* MIPS-II, for r4000 port */ #define OP_CT 006 #define OP_MTH 007 #define OP_BCx 010 #define OP_BCy 014 /* * Values for the 'rt' field when 'op' == OP_COPz. */ #define COPz_BC_TF_MASK 0x01 #define COPz_BC_TRUE 0x01 #define COPz_BC_FALSE 0x00 #define COPz_BCL_TF_MASK 0x02 /* MIPS-II, for r4000 port */ #define COPz_BCL_TRUE 0x02 /* MIPS-II, for r4000 port */ #define COPz_BCL_FALSE 0x00 /* MIPS-II, for r4000 port */ #endif /* __DECODER_LOCAL_H__ */ mupen64plus-core-src-2.6.0/src/debugger/dbg_memory.c000066400000000000000000000334711464506436200223210ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dbg_memory.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 DarkJeztr * * Copyright (C) 2002 Blight * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "dbg_breakpoints.h" #include "dbg_memory.h" #include "device/device.h" #include "device/r4300/cached_interp.h" #include "osal/preproc.h" #if defined(__GNUC__) #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) #else #define ATTR_FMT(fmtpos, attrpos) #endif #if !defined(NO_ASM) && (defined(__i386__) || (defined(__x86_64__) && defined(__GNUC__))) /* we must define PACKAGE so that bfd.h (which is included from dis-asm.h) doesn't throw an error */ #define PACKAGE "mupen64plus-core" #include #include static int lines_recompiled; static uint32_t addr_recompiled; static int num_decoded; static char opcode_recompiled[564][MAX_DISASSEMBLY]; static char args_recompiled[564][MAX_DISASSEMBLY*4]; static void *opaddr_recompiled[564]; static disassemble_info dis_info; static disassembler_ftype disassemble; static void process_opcode_out(void *strm, const char *fmt, ...) ATTR_FMT(2,3); void process_opcode_out(void *strm, const char *fmt, ...) { va_list ap; va_start(ap, fmt); char *arg; char buff[256]; if (num_decoded==0) { if (strcmp(fmt,"%s")==0) { arg = va_arg(ap, char*); strcpy(opcode_recompiled[lines_recompiled],arg); } else strcpy(opcode_recompiled[lines_recompiled],"OPCODE-X"); num_decoded++; *(args_recompiled[lines_recompiled])=0; } else { vsprintf(buff, fmt, ap); sprintf(args_recompiled[lines_recompiled],"%s%s", args_recompiled[lines_recompiled],buff); } va_end(ap); } // Callback function that will be called by libopcodes to read the // bytes to disassemble ('read_memory_func' member of 'disassemble_info'). static int read_memory_func(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, disassemble_info *info) { char* from = (char*)(long)(memaddr); char* to = (char*)myaddr; while (length-- != 0) { *to++ = *from++; } return (0); } #ifdef USE_LIBBFD_GE_2_39 static int fprintf_styled_nop(void *out __attribute__((unused)), enum disassembler_style s __attribute__((unused)), const char *fmt __attribute__((unused)), ...) { return 0; } #endif void init_host_disassembler(void) { #ifdef USE_LIBBFD_GE_2_39 INIT_DISASSEMBLE_INFO(dis_info, stderr, process_opcode_out, fprintf_styled_nop); #else INIT_DISASSEMBLE_INFO(dis_info, stderr, process_opcode_out); #endif dis_info.fprintf_func = (fprintf_ftype) process_opcode_out; dis_info.stream = stderr; dis_info.bytes_per_line=1; dis_info.endian = 1; dis_info.arch = bfd_arch_i386; dis_info.mach = bfd_mach_i386_i8086; dis_info.disassembler_options = (char*) "i386,suffix"; dis_info.read_memory_func = read_memory_func; #if defined(USE_LIBOPCODES_GE_2_29) /* libopcode >= 2.29 cannot use print_insn_i386 directly, * but can get it through disassembler function * whose prototype has been also updated to allow such selection. */ disassemble = disassembler(dis_info.arch, (dis_info.endian == BFD_ENDIAN_BIG), dis_info.mach, NULL); #else disassemble = print_insn_i386; #endif } static void decode_recompiled(struct r4300_core* r4300, uint32_t addr) { unsigned char *assemb, *end_addr; lines_recompiled=0; if (r4300->cached_interp.blocks[addr>>12] == NULL) return; if (r4300->cached_interp.blocks[addr>>12]->block[(addr&0xFFF)/4].ops == r4300->cached_interp.not_compiled) { strcpy(opcode_recompiled[0],"INVLD"); strcpy(args_recompiled[0],"NOTCOMPILED"); opaddr_recompiled[0] = (void *) 0; addr_recompiled=0; lines_recompiled++; return; } assemb = (r4300->cached_interp.blocks[addr>>12]->code) + (r4300->cached_interp.blocks[addr>>12]->block[(addr&0xFFF)/4].local_addr); end_addr = r4300->cached_interp.blocks[addr>>12]->code; if ((addr & 0xFFF) >= 0xFFC) end_addr += r4300->cached_interp.blocks[addr>>12]->code_length; else end_addr += r4300->cached_interp.blocks[addr>>12]->block[(addr&0xFFF)/4+1].local_addr; while (assemb < end_addr) { opaddr_recompiled[lines_recompiled] = assemb; num_decoded=0; assemb += disassemble((bfd_vma)(long) assemb, &dis_info); lines_recompiled++; } addr_recompiled = addr; } char* get_recompiled_opcode(struct r4300_core* r4300, uint32_t addr, int index) { if (addr != addr_recompiled) decode_recompiled(r4300, addr); if (index < lines_recompiled) return opcode_recompiled[index]; else return NULL; } char* get_recompiled_args(struct r4300_core* r4300, uint32_t addr, int index) { if (addr != addr_recompiled) decode_recompiled(r4300, addr); if (index < lines_recompiled) return args_recompiled[index]; else return NULL; } void* get_recompiled_addr(struct r4300_core* r4300, uint32_t addr, int index) { if (addr != addr_recompiled) decode_recompiled(r4300, addr); if (index < lines_recompiled) return opaddr_recompiled[index]; else return 0; } int get_num_recompiled(struct r4300_core* r4300, uint32_t addr) { if (addr != addr_recompiled) decode_recompiled(r4300, addr); return lines_recompiled; } int get_has_recompiled(struct r4300_core* r4300, uint32_t addr) { unsigned char *assemb, *end_addr; if (r4300->emumode != EMUMODE_DYNAREC || r4300->cached_interp.blocks[addr>>12] == NULL) return FALSE; assemb = (r4300->cached_interp.blocks[addr>>12]->code) + (r4300->cached_interp.blocks[addr>>12]->block[(addr&0xFFF)/4].local_addr); end_addr = r4300->cached_interp.blocks[addr>>12]->code; if ((addr & 0xFFF) >= 0xFFC) end_addr += r4300->cached_interp.blocks[addr>>12]->code_length; else end_addr += r4300->cached_interp.blocks[addr>>12]->block[(addr&0xFFF)/4+1].local_addr; if(assemb==end_addr) return FALSE; return TRUE; } #else int get_num_recompiled(struct r4300_core* r4300, uint32_t addr) { return 0; } char* get_recompiled_opcode(struct r4300_core* r4300, uint32_t addr, int index) { return NULL; } char* get_recompiled_args(struct r4300_core* r4300, uint32_t addr, int index) { return NULL; } void* get_recompiled_addr(struct r4300_core* r4300, uint32_t addr, int index) { return 0; } int get_has_recompiled(struct r4300_core* r4300, uint32_t addr) { return 0; } void init_host_disassembler(void) { } #endif #ifdef DBG uint64_t read_memory_64(struct device* dev, uint32_t addr) { return ((uint64_t)read_memory_32(dev, addr) << 32) | (uint64_t)read_memory_32(dev, addr + 4); } uint64_t read_memory_64_unaligned(struct device* dev, uint32_t addr) { uint64_t w[2]; w[0] = read_memory_32_unaligned(dev, addr); w[1] = read_memory_32_unaligned(dev, addr + 4); return (w[0] << 32) | w[1]; } void write_memory_64(struct device* dev, uint32_t addr, uint64_t value) { write_memory_32(dev, addr, (uint32_t) (value >> 32)); write_memory_32(dev, addr + 4, (uint32_t) (value & 0xFFFFFFFF)); } void write_memory_64_unaligned(struct device* dev, uint32_t addr, uint64_t value) { write_memory_32_unaligned(dev, addr, (uint32_t) (value >> 32)); write_memory_32_unaligned(dev, addr + 4, (uint32_t) (value & 0xFFFFFFFF)); } uint32_t read_memory_32(struct device* dev, uint32_t addr) { uint32_t value; if (r4300_read_aligned_word(&dev->r4300, addr, &value) == 0) return M64P_MEM_INVALID; return value; } uint32_t read_memory_32_unaligned(struct device* dev, uint32_t addr) { uint8_t i, b[4]; for(i=0; i<4; i++) b[i] = read_memory_8(dev, addr + i); return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; } void write_memory_32(struct device* dev, uint32_t addr, uint32_t value) { r4300_write_aligned_word(&dev->r4300, addr, value, 0xffffffff); } void write_memory_32_unaligned(struct device* dev, uint32_t addr, uint32_t value) { write_memory_8(dev, addr + 0, value >> 24); write_memory_8(dev, addr + 1, (value >> 16) & 0xFF); write_memory_8(dev, addr + 2, (value >> 8) & 0xFF); write_memory_8(dev, addr + 3, value & 0xFF); } //read_memory_16_unaligned and write_memory_16_unaligned don't exist because //read_memory_16 and write_memory_16 work unaligned already. uint16_t read_memory_16(struct device* dev, uint32_t addr) { return ((uint16_t)read_memory_8(dev, addr) << 8) | (uint16_t)read_memory_8(dev, addr+1); //cough cough hack hack } void write_memory_16(struct device* dev, uint32_t addr, uint16_t value) { write_memory_8(dev, addr, value >> 8); //this isn't much better write_memory_8(dev, addr + 1, value & 0xFF); //then again, it works unaligned } uint8_t read_memory_8(struct device* dev, uint32_t addr) { uint32_t word; word = read_memory_32(dev, addr & ~3); return (word >> ((3 - (addr & 3)) * 8)) & 0xFF; } void write_memory_8(struct device* dev, uint32_t addr, uint8_t value) { uint32_t word; uint32_t mask; mask = 0xFF << ((3 - (addr & 3)) * 8); word = value << ((3 - (addr & 3)) * 8); r4300_write_aligned_word(&dev->r4300, addr, word, mask); } uint32_t get_memory_flags(struct device* dev, uint32_t addr) { int type=get_memory_type(&dev->mem, addr); const uint32_t addrlow = (addr & 0xFFFF); uint32_t flags = 0; switch(type) { case M64P_MEM_NOMEM: if(dev->r4300.cp0.tlb.LUT_r[addr>>12]) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_NOTHING: if (((addr >> 16) == 0x8801 || (addr >> 16 == 0xA801)) && addrlow == 0) flags = M64P_MEM_FLAG_WRITABLE_EMUONLY; // for flashram command break; case M64P_MEM_RDRAM: flags = M64P_MEM_FLAG_WRITABLE; case M64P_MEM_ROM: flags |= M64P_MEM_FLAG_READABLE; break; case M64P_MEM_RDRAMREG: if (addrlow < 0x28) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_RSPMEM: if (addrlow < 0x2000) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_RSPREG: if (addrlow < 0x20) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_RSP: if (addrlow < 0x8) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_DP: if (addrlow < 0x20) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_DPS: if (addrlow < 0x10) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_VI: if (addrlow < 0x38) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_AI: if (addrlow < 0x18) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_PI: if (addrlow < 0x34) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_RI: if (addrlow < 0x20) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_SI: if (addrlow < 0x1c) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_FLASHRAMSTAT: if (addrlow == 0) flags = M64P_MEM_FLAG_READABLE_EMUONLY; break; case M64P_MEM_PIF: if (addrlow >= 0x7C0 && addrlow <= 0x7FF) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; case M64P_MEM_MI: if (addrlow < 0x10) flags = M64P_MEM_FLAG_READABLE | M64P_MEM_FLAG_WRITABLE_EMUONLY; break; default: break; } return flags; } #endif mupen64plus-core-src-2.6.0/src/debugger/dbg_memory.h000066400000000000000000000060601464506436200223200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dbg_memory.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 DarkJeztr * * Copyright (C) 2002 davFr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __DEBUGGER_MEMORY_H__ #define __DEBUGGER_MEMORY_H__ #define MAX_DISASSEMBLY 64 #include struct device; struct r4300_core; void init_host_disassembler(void); char* get_recompiled_opcode(struct r4300_core* r4300, uint32_t address, int index); char* get_recompiled_args(struct r4300_core* r4300, uint32_t address, int index); void* get_recompiled_addr(struct r4300_core* r4300, uint32_t address, int index); int get_num_recompiled(struct r4300_core* r4300, uint32_t address ); int get_has_recompiled(struct r4300_core* r4300, uint32_t address ); uint64_t read_memory_64(struct device* dev, uint32_t addr); uint64_t read_memory_64_unaligned(struct device* dev, uint32_t addr); void write_memory_64(struct device* dev, uint32_t addr, uint64_t value); void write_memory_64_unaligned(struct device* dev, uint32_t addr, uint64_t value); uint32_t read_memory_32(struct device* dev, uint32_t addr); uint32_t read_memory_32_unaligned(struct device* dev, uint32_t addr); void write_memory_32(struct device* dev, uint32_t addr, uint32_t value); void write_memory_32_unaligned(struct device* dev, uint32_t addr, uint32_t value); uint16_t read_memory_16(struct device* dev, uint32_t addr); void write_memory_16(struct device* dev, uint32_t addr, uint16_t value); uint8_t read_memory_8(struct device* dev, uint32_t addr); void write_memory_8(struct device* dev, uint32_t addr, uint8_t value); uint32_t get_memory_flags(struct device* dev, uint32_t addr); #endif /* __DEBUGGER_MEMORY_H__ */ mupen64plus-core-src-2.6.0/src/device/000077500000000000000000000000001464506436200174745ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/cart/000077500000000000000000000000001464506436200204255ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/cart/af_rtc.c000066400000000000000000000101141464506436200220240ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - af_rtc.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "af_rtc.h" #include "api/callbacks.h" #include "api/m64p_types.h" #include "backends/api/clock_backend.h" #include static uint8_t byte2bcd(int n) { n %= 100; return (uint8_t)(((n / 10) << 4) | (n % 10)); } static void time2data(uint8_t* data, time_t now) { const struct tm* tm = localtime(&now); data[0] = byte2bcd(tm->tm_sec); data[1] = byte2bcd(tm->tm_min); data[2] = 0x80 + byte2bcd(tm->tm_hour); data[3] = byte2bcd(tm->tm_mday); data[4] = byte2bcd(tm->tm_wday); data[5] = byte2bcd(tm->tm_mon + 1); data[6] = byte2bcd(tm->tm_year); data[7] = byte2bcd(tm->tm_year / 100); } static void update_rtc(struct af_rtc* rtc) { /* update rtc->now */ time_t now = rtc->iclock->get_time(rtc->clock); rtc->now += now - rtc->last_update_rtc; rtc->last_update_rtc = now; } void init_af_rtc(struct af_rtc* rtc, void* clock, const struct clock_backend_interface* iclock) { rtc->clock = clock; rtc->iclock = iclock; } void poweron_af_rtc(struct af_rtc* rtc) { /* blocks 1&2 are read/write, timer is activated */ rtc->control = 0x0200; rtc->now = 0; rtc->last_update_rtc = 0; } void af_rtc_read_block(struct af_rtc* rtc, uint8_t block, uint8_t* data, uint8_t* status) { switch (block) { case 0: data[0] = (uint8_t)(rtc->control >> 0); data[1] = (uint8_t)(rtc->control >> 8); *status = 0x00; break; case 1: DebugMessage(M64MSG_ERROR, "AF-RTC reading block 1 is not implemented !"); break; case 2: update_rtc(rtc); time2data(data, rtc->now); *status = 0x00; break; default: DebugMessage(M64MSG_ERROR, "AF-RTC read invalid block: %u", block); } } void af_rtc_write_block(struct af_rtc* rtc, uint8_t block, const uint8_t* data, uint8_t* status) { switch (block) { case 0: rtc->control = (data[1] << 8) | data[0]; *status = 0x00; break; case 1: /* block 1 read-only when control[0] is set */ if (rtc->control & 0x01) { break; } DebugMessage(M64MSG_ERROR, "AF-RTC writing block 1 is not implemented !"); break; case 2: /* block 2 read-only when control[1] is set */ if (rtc->control & 0x02) { break; } /* TODO: implement block 2 writes */ DebugMessage(M64MSG_ERROR, "AF-RTC writing block 2 is not implemented !"); break; default: DebugMessage(M64MSG_ERROR, "AF-RTC write invalid block: %u", block); } } mupen64plus-core-src-2.6.0/src/device/cart/af_rtc.h000066400000000000000000000043111464506436200220330ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - af_rtc.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_AF_RTC_H #define M64P_DEVICE_SI_AF_RTC_H #include #include struct clock_backend_interface; struct af_rtc { /* block 0 */ uint16_t control; /* block 2 */ time_t now; time_t last_update_rtc; void* clock; const struct clock_backend_interface* iclock; }; void init_af_rtc(struct af_rtc* rtc, void* clock, const struct clock_backend_interface* iclock); void poweron_af_rtc(struct af_rtc* rtc); void af_rtc_read_block(struct af_rtc* rtc, uint8_t block, uint8_t* data, uint8_t* status); void af_rtc_write_block(struct af_rtc* rtc, uint8_t block, const uint8_t* data, uint8_t* status); #endif mupen64plus-core-src-2.6.0/src/device/cart/cart.c000066400000000000000000000165651464506436200215370ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cart.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "cart.h" #include "api/callbacks.h" #include "api/m64p_types.h" #include "main/rom.h" #include #include static void process_cart_command(void* jbd, const uint8_t* tx, const uint8_t* tx_buf, uint8_t* rx, uint8_t* rx_buf) { struct cart* cart = (struct cart*)jbd; uint8_t cmd = tx_buf[0]; switch (cmd) { case JCMD_RESET: /* TODO: perform internal reset */ /* fall through */ case JCMD_STATUS: { JOYBUS_CHECK_COMMAND_FORMAT(1, 3) if (cart->eeprom.type) { /* set type, status, and extra */ rx_buf[0] = (uint8_t)(cart->eeprom.type >> 0); rx_buf[1] = (uint8_t)(cart->eeprom.type >> 8); rx_buf[2] = 0x00; } else { *rx |= 0x80; } } break; case JCMD_EEPROM_READ: { JOYBUS_CHECK_COMMAND_FORMAT(2, 8) eeprom_read_block(&cart->eeprom, tx_buf[1], &rx_buf[0]); } break; case JCMD_EEPROM_WRITE: { JOYBUS_CHECK_COMMAND_FORMAT(10, 1) eeprom_write_block(&cart->eeprom, tx_buf[1], &tx_buf[2], &rx_buf[0]); } break; case JCMD_AF_RTC_STATUS: { JOYBUS_CHECK_COMMAND_FORMAT(1, 3) /* set type and status */ rx_buf[0] = (uint8_t)(JDT_AF_RTC >> 0); rx_buf[1] = (uint8_t)(JDT_AF_RTC >> 8); rx_buf[2] = 0x00; } break; case JCMD_AF_RTC_READ: { JOYBUS_CHECK_COMMAND_FORMAT(2, 9) af_rtc_read_block(&cart->af_rtc, tx_buf[1], &rx_buf[0], &rx_buf[8]); } break; case JCMD_AF_RTC_WRITE: { JOYBUS_CHECK_COMMAND_FORMAT(10, 1) af_rtc_write_block(&cart->af_rtc, tx_buf[1], &tx_buf[2], &rx_buf[0]); } break; default: DebugMessage(M64MSG_WARNING, "cart: Unknown command %02x %02x %02x", *tx, *rx, cmd); } } const struct joybus_device_interface g_ijoybus_device_cart = { NULL, process_cart_command, NULL }; void init_cart(struct cart* cart, /* AF-RTC */ void* af_rtc_clock, const struct clock_backend_interface* iaf_rtc_clock, /* cart ROM */ uint8_t* rom, size_t rom_size, struct r4300_core* r4300, struct pi_controller* pi, /* eeprom */ uint16_t eeprom_type, void* eeprom_storage, const struct storage_backend_interface* ieeprom_storage, /* flashram */ uint32_t flashram_type, void* flashram_storage, const struct storage_backend_interface* iflashram_storage, const uint8_t* dram, /* sram */ void* sram_storage, const struct storage_backend_interface* isram_storage) { init_af_rtc(&cart->af_rtc, af_rtc_clock, iaf_rtc_clock); init_cart_rom(&cart->cart_rom, rom, rom_size, r4300, pi); init_eeprom(&cart->eeprom, eeprom_type, eeprom_storage, ieeprom_storage); init_flashram(&cart->flashram, flashram_type, flashram_storage, iflashram_storage); init_sram(&cart->sram, sram_storage, isram_storage); if (ROM_SETTINGS.savetype == SAVETYPE_SRAM) cart->use_flashram = -1; else if (ROM_SETTINGS.savetype == SAVETYPE_FLASH_RAM) cart->use_flashram = 1; else cart->use_flashram = 0; } void poweron_cart(struct cart* cart) { poweron_af_rtc(&cart->af_rtc); poweron_cart_rom(&cart->cart_rom); poweron_flashram(&cart->flashram); } void read_cart_dom2(void* opaque, uint32_t address, uint32_t* value) { struct cart* cart = (struct cart*)opaque; if (cart->use_flashram == -1) { read_sram(&cart->sram, address, value); } else { if ((address & 0xffff) != 0) { DebugMessage(M64MSG_ERROR, "unknown read in read_cart_dom2()"); return; } cart->use_flashram = 1; read_flashram(&cart->flashram, address, value); } } void write_cart_dom2(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct cart* cart = (struct cart*)opaque; if (cart->use_flashram == -1) { write_sram(&cart->sram, address, value, mask); } else { if ((address & 0xffff) != 0) { DebugMessage(M64MSG_ERROR, "unknown write in write_cart_dom2()"); return; } cart->use_flashram = 1; write_flashram(&cart->flashram, address, value, mask); } } unsigned int cart_dom2_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { struct cart* cart = (struct cart*)opaque; unsigned int cycles; if (cart->use_flashram != 1) { cycles = sram_dma_read(&cart->sram, dram, dram_addr, cart_addr, length); cart->use_flashram = -1; } else { cycles = flashram_dma_read(&cart->flashram, dram, dram_addr, cart_addr, length); } return cycles; } unsigned int cart_dom2_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { struct cart* cart = (struct cart*)opaque; unsigned int cycles; if (cart->use_flashram != 1) { cycles = sram_dma_write(&cart->sram, dram, dram_addr, cart_addr, length); cart->use_flashram = -1; } else { cycles = flashram_dma_write(&cart->flashram, dram, dram_addr, cart_addr, length); } return cycles; } unsigned int cart_dom3_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { struct cart* cart = (struct cart*)opaque; return cart_rom_dma_read(&cart->cart_rom, dram, dram_addr, cart_addr, length); } unsigned int cart_dom3_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { struct cart* cart = (struct cart*)opaque; return cart_rom_dma_write(&cart->cart_rom, dram, dram_addr, cart_addr, length); } mupen64plus-core-src-2.6.0/src/device/cart/cart.h000066400000000000000000000070461464506436200215360ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cart.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_CART_CART_H #define M64P_DEVICE_CART_CART_H #include "backends/api/joybus.h" #include "af_rtc.h" #include "cart_rom.h" #include "eeprom.h" #include "flashram.h" #include "sram.h" #include #include struct r4300_core; struct pi_controller; struct clock_backend_interface; struct storage_backend_interface; struct cart { struct af_rtc af_rtc; struct cart_rom cart_rom; struct eeprom eeprom; struct flashram flashram; struct sram sram; int use_flashram; }; void init_cart(struct cart* cart, /* AF-RTC */ void* af_rtc_clock, const struct clock_backend_interface* iaf_rtc_clock, /* cart ROM */ uint8_t* rom, size_t rom_size, struct r4300_core* r4300, struct pi_controller* pi, /* eeprom */ uint16_t eeprom_type, void* eeprom_storage, const struct storage_backend_interface* ieeprom_storage, /* flashram */ uint32_t flashram_type, void* flashram_storage, const struct storage_backend_interface* iflashram_storage, const uint8_t* dram, /* sram */ void* sram_storage, const struct storage_backend_interface* isram_storage); void poweron_cart(struct cart* cart); void read_cart_dom2(void* opaque, uint32_t address, uint32_t* value); void write_cart_dom2(void* opaque, uint32_t address, uint32_t value, uint32_t mask); unsigned int cart_dom2_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int cart_dom2_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int cart_dom3_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int cart_dom3_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); extern const struct joybus_device_interface g_ijoybus_device_cart; #endif mupen64plus-core-src-2.6.0/src/device/cart/cart_rom.c000066400000000000000000000105411464506436200224000ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cart_rom.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "cart_rom.h" #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rcp/pi/pi_controller.h" #define __STDC_FORMAT_MACROS #include #define CART_ROM_ADDR_MASK UINT32_C(0x03ffffff); void init_cart_rom(struct cart_rom* cart_rom, uint8_t* rom, size_t rom_size, struct r4300_core* r4300, struct pi_controller* pi) { cart_rom->rom = rom; cart_rom->rom_size = rom_size; cart_rom->r4300 = r4300; cart_rom->pi = pi; } void poweron_cart_rom(struct cart_rom* cart_rom) { cart_rom->last_write = 0; } void read_cart_rom(void* opaque, uint32_t address, uint32_t* value) { struct cart_rom* cart_rom = (struct cart_rom*)opaque; uint32_t addr = rom_address(address); if (cart_rom->pi->regs[PI_STATUS_REG] & PI_STATUS_IO_BUSY) { *value = cart_rom->last_write; } else { *value = *(uint32_t*)(cart_rom->rom + addr); } } void write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct cart_rom* cart_rom = (struct cart_rom*)opaque; cart_rom->last_write = value & mask; if (!validate_pi_request(cart_rom->pi)) return; /* Mark IO as busy */ cart_rom->pi->regs[PI_STATUS_REG] |= PI_STATUS_IO_BUSY; cp0_update_count(cart_rom->r4300); add_interrupt_event(&cart_rom->r4300->cp0, PI_INT, 0x1000); } unsigned int cart_rom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { cart_addr &= CART_ROM_ADDR_MASK; DebugMessage(M64MSG_WARNING, "DMA Writing to CART_ROM: 0x%" PRIX32 " -> 0x%" PRIX32 " (0x%" PRIX32 ")", dram_addr, cart_addr, length); return /* length / 8 */0x1000; } unsigned int cart_rom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { size_t i; struct cart_rom* cart_rom = (struct cart_rom*)opaque; const uint8_t* mem = cart_rom->rom; cart_addr &= CART_ROM_ADDR_MASK; if (cart_addr + length < cart_rom->rom_size) { for(i = 0; i < length; ++i) { dram[(dram_addr+i)^S8] = mem[(cart_addr+i)^S8]; } } else { unsigned int diff = (cart_rom->rom_size <= cart_addr) ? 0 : cart_rom->rom_size - cart_addr; for (i = 0; i < diff; ++i) { dram[(dram_addr+i)^S8] = mem[(cart_addr+i)^S8]; } for (; i < length; ++i) { dram[(dram_addr+i)^S8] = 0; } } /* invalidate cached code */ invalidate_r4300_cached_code(cart_rom->r4300, 0x80000000 + dram_addr, length); invalidate_r4300_cached_code(cart_rom->r4300, 0xa0000000 + dram_addr, length); return (length / 8) + add_random_interrupt_time(cart_rom->r4300); } mupen64plus-core-src-2.6.0/src/device/cart/cart_rom.h000066400000000000000000000050631464506436200224100ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cart_rom.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_PI_CART_ROM_H #define M64P_DEVICE_PI_CART_ROM_H #include #include #include "osal/preproc.h" struct r4300_core; struct pi_controller; struct cart_rom { uint8_t* rom; size_t rom_size; uint32_t last_write; struct r4300_core* r4300; struct pi_controller* pi; }; static osal_inline uint32_t rom_address(uint32_t address) { return (address & 0x03fffffc); } void init_cart_rom(struct cart_rom* cart_rom, uint8_t* rom, size_t rom_size, struct r4300_core* r4300, struct pi_controller* pi); void poweron_cart_rom(struct cart_rom* cart_rom); void read_cart_rom(void* opaque, uint32_t address, uint32_t* value); void write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask); unsigned int cart_rom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int cart_rom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); #endif mupen64plus-core-src-2.6.0/src/device/cart/eeprom.c000066400000000000000000000057431464506436200220710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - eeprom.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "eeprom.h" #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "backends/api/storage_backend.h" #define __STDC_FORMAT_MACROS #include enum { EEPROM_BLOCK_SIZE = 8 }; void format_eeprom(uint8_t* mem, size_t size) { memset(mem, 0xff, size); } void init_eeprom(struct eeprom* eeprom, uint16_t type, void* storage, const struct storage_backend_interface* istorage) { eeprom->type = type; eeprom->storage = storage; eeprom->istorage = istorage; } void eeprom_read_block(struct eeprom* eeprom, uint8_t block, uint8_t* data) { unsigned int address = block * EEPROM_BLOCK_SIZE; if (address < eeprom->istorage->size(eeprom->storage)) { memcpy(data, eeprom->istorage->data(eeprom->storage) + address, EEPROM_BLOCK_SIZE); } else { DebugMessage(M64MSG_WARNING, "Invalid access to eeprom address=%04x", address); } } void eeprom_write_block(struct eeprom* eeprom, uint8_t block, const uint8_t* data, uint8_t* status) { unsigned int address = block * EEPROM_BLOCK_SIZE; if (address < eeprom->istorage->size(eeprom->storage)) { memcpy(eeprom->istorage->data(eeprom->storage) + address, data, EEPROM_BLOCK_SIZE); eeprom->istorage->save(eeprom->storage, address, EEPROM_BLOCK_SIZE); *status = 0x00; } else { DebugMessage(M64MSG_WARNING, "Invalid access to eeprom address=%04x", address); } } mupen64plus-core-src-2.6.0/src/device/cart/eeprom.h000066400000000000000000000042001464506436200220610ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - eeprom.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_EEPROM_H #define M64P_DEVICE_SI_EEPROM_H #include #include struct storage_backend_interface; struct eeprom { uint16_t type; void* storage; const struct storage_backend_interface* istorage; }; void format_eeprom(uint8_t* eeprom, size_t size); void init_eeprom(struct eeprom* eeprom, uint16_t type, void* storage, const struct storage_backend_interface* istorage); void eeprom_read_block(struct eeprom* eeprom, uint8_t block, uint8_t* data); void eeprom_write_block(struct eeprom* eeprom, uint8_t block, const uint8_t* data, uint8_t* status); #endif mupen64plus-core-src-2.6.0/src/device/cart/flashram.c000066400000000000000000000212011464506436200223620ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - flashram.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "flashram.h" #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "backends/api/storage_backend.h" #include "device/memory/memory.h" #define __STDC_FORMAT_MACROS #include static void flashram_command(struct flashram* flashram, uint32_t command) { unsigned int i; unsigned int offset; uint8_t* mem = flashram->istorage->data(flashram->storage); switch (command & 0xff000000) { case 0x3c000000: /* set chip erase mode */ flashram->mode = FLASHRAM_MODE_CHIP_ERASE; break; case 0x4b000000: /* set sector erase mode, set erase sector */ flashram->mode = FLASHRAM_MODE_SECTOR_ERASE; flashram->erase_page = (command & 0xffff); break; case 0x78000000: /* set erase busy flag */ flashram->status |= 0x02; /* do chip/sector erase */ if (flashram->mode == FLASHRAM_MODE_SECTOR_ERASE) { offset = (flashram->erase_page & 0xff80) * 128; memset(mem + offset, 0xff, 128*128); flashram->istorage->save(flashram->storage, offset, 128*128); } else if (flashram->mode == FLASHRAM_MODE_CHIP_ERASE){ memset(mem, 0xff, FLASHRAM_SIZE); flashram->istorage->save(flashram->storage, 0, FLASHRAM_SIZE); } else { DebugMessage(M64MSG_WARNING, "Unexpected erase command (mode=%x)", flashram->mode); } /* clear erase busy flag, set erase success flag, transition to status mode */ flashram->status &= ~UINT32_C(0x02); flashram->status |= 0x08; flashram->mode = FLASHRAM_MODE_STATUS; break; case 0xa5000000: /* set program busy flag */ flashram->status |= 0x01; /* program selected page */ offset = (command & 0xffff) * 128; for (i = 0; i < 128; ++i) { mem[(offset+i)^S8] = flashram->page_buf[i]; } flashram->istorage->save(flashram->storage, offset, 128); /* clear program busy flag, set program success flag, transition to status mode */ flashram->status &= ~UINT32_C(0x01); flashram->status |= 0x04; flashram->mode = FLASHRAM_MODE_STATUS; break; case 0xb4000000: /* set page program mode */ flashram->mode = FLASHRAM_MODE_PAGE_PROGRAM; break; case 0xd2000000: /* set status mode */ flashram->mode = FLASHRAM_MODE_STATUS; break; case 0xe1000000: /* set silicon_id mode */ flashram->mode = FLASHRAM_MODE_READ_SILICON_ID; flashram->status |= 0x01; /* Needed for Pokemon Puzzle League */ break; case 0xf0000000: /* set read mode */ flashram->mode = FLASHRAM_MODE_READ_ARRAY; break; default: DebugMessage(M64MSG_WARNING, "unknown flashram command: %" PRIX32, command); } } void init_flashram(struct flashram* flashram, uint32_t flashram_id, void* storage, const struct storage_backend_interface* istorage) { flashram->silicon_id[0] = FLASHRAM_TYPE_ID; flashram->silicon_id[1] = flashram_id; flashram->storage = storage; flashram->istorage = istorage; } void poweron_flashram(struct flashram* flashram) { flashram->mode = FLASHRAM_MODE_READ_ARRAY; flashram->status = 0x00; flashram->erase_page = 0; memset(flashram->page_buf, 0xff, 128); } void format_flashram(uint8_t* flash) { memset(flash, 0xff, FLASHRAM_SIZE); } void read_flashram(void* opaque, uint32_t address, uint32_t* value) { struct flashram* flashram = (struct flashram*)opaque; if ((address & 0x1ffff) == 0x00000 && flashram->mode == FLASHRAM_MODE_STATUS) { /* read Status register */ *value = flashram->status; } else if ((address & 0x1ffff) == 0x0000 && flashram->mode == FLASHRAM_MODE_READ_ARRAY) { /* flashram MMIO read are not supported except for the "dummy" read @0x0000 done before DMA. * returns a "dummy" value. */ *value = 0; } else { /* other accesses are not implemented */ DebugMessage(M64MSG_WARNING, "unknown Flashram read IO (mode=%x) @%08x", flashram->mode, address); } } void write_flashram(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct flashram* flashram = (struct flashram*)opaque; if ((address & 0x1ffff) == 0x00000 && flashram->mode == FLASHRAM_MODE_STATUS) { /* clear/set Status register */ flashram->status = (value & mask) & 0xff; } else if ((address & 0x1ffff) == 0x10000) { /* set command */ flashram_command(flashram, value & mask); } else { /* other accesses are not implemented */ DebugMessage(M64MSG_WARNING, "unknown Flashram write IO (mode=%x) @%08x <- %08x & %08x", flashram->mode, address, value, mask); } } unsigned int flashram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { size_t i; struct flashram* flashram = (struct flashram*)opaque; const uint8_t* mem = flashram->istorage->data(flashram->storage); if ((cart_addr & 0x1ffff) == 0x00000 && length == 8 && flashram->mode == FLASHRAM_MODE_READ_SILICON_ID) { /* read Silicon ID using DMA */ ((uint32_t*)dram)[dram_addr/4+0] = flashram->silicon_id[0]; ((uint32_t*)dram)[dram_addr/4+1] = flashram->silicon_id[1]; } else if ((cart_addr & 0x1ffff) < 0x10000 && flashram->mode == FLASHRAM_MODE_READ_ARRAY) { /* adjust flashram address before starting DMA. */ if (flashram->silicon_id[1] == MX29L1100_ID || flashram->silicon_id[1] == MX29L0000_ID || flashram->silicon_id[1] == MX29L0001_ID) { /* "old" flash needs special address adjusting */ cart_addr = (cart_addr & 0xffff) * 2; } else { /* "new" flash doesn't require special address adjusting at DMA start. */ cart_addr &= 0xffff; } /* do actual DMA */ for(i = 0; i < length; ++i) { dram[(dram_addr+i)^S8] = mem[(cart_addr+i)^S8]; } } else { /* other accesses are not implemented */ DebugMessage(M64MSG_WARNING, "unknown Flashram DMA Write (mode=%x) @%08x <- %08x length=%08x", flashram->mode, dram_addr, cart_addr, length); } return /* length / 8 */0x1000; } unsigned int flashram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { struct flashram* flashram = (struct flashram*)opaque; unsigned int i; if ((cart_addr & 0x1ffff) == 0x00000 && length == 128 && flashram->mode == FLASHRAM_MODE_PAGE_PROGRAM) { /* load page buf using DMA */ for(i = 0; i < length; ++i) { flashram->page_buf[i] = dram[(dram_addr+i)^S8]; } } else { /* other accesses are not implemented */ DebugMessage(M64MSG_WARNING, "unknown Flashram DMA Read (mode=%x) @%08x <- %08x length=%08x", flashram->mode, cart_addr, dram_addr, length); } return /* length / 8 */0x1000; } mupen64plus-core-src-2.6.0/src/device/cart/flashram.h000066400000000000000000000061521464506436200223770ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - flashram.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_PI_FLASHRAM_H #define M64P_DEVICE_PI_FLASHRAM_H #include struct storage_backend_interface; enum { FLASHRAM_SIZE = 0x20000 }; enum { FLASHRAM_TYPE_ID = 0x11118001 }; /* flashram manufacturer and device code */ enum { MX29L0000_ID = 0x00c20000, MX29L0001_ID = 0x00c20001, MX29L1100_ID = 0x00c2001e, MX29L1101_ID = 0x00c2001d, MN63F8MPN_ID = 0x003200f1, }; enum flashram_mode { FLASHRAM_MODE_READ_ARRAY, FLASHRAM_MODE_READ_SILICON_ID, FLASHRAM_MODE_STATUS, FLASHRAM_MODE_SECTOR_ERASE, FLASHRAM_MODE_CHIP_ERASE, FLASHRAM_MODE_PAGE_PROGRAM }; struct flashram { uint8_t page_buf[128]; uint32_t silicon_id[2]; uint32_t status; // supposedly only 8-bit uint16_t erase_page; enum flashram_mode mode; void* storage; const struct storage_backend_interface* istorage; }; void init_flashram(struct flashram* flashram, uint32_t flashram_id, void* storage, const struct storage_backend_interface* istorage); void poweron_flashram(struct flashram* flashram); void format_flashram(uint8_t* flash); void read_flashram(void* opaque, uint32_t address, uint32_t* value); void write_flashram(void* opaque, uint32_t address, uint32_t value, uint32_t mask); unsigned int flashram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int flashram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); #endif mupen64plus-core-src-2.6.0/src/device/cart/is_viewer.c000066400000000000000000000074001464506436200225660ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - is_viewer.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2021 loganmc10 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "is_viewer.h" #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "main/util.h" #define __STDC_FORMAT_MACROS #include #include #define IS_ADDR_MASK UINT32_C(0x00000fff) void poweron_is_viewer(struct is_viewer* is_viewer) { memset(is_viewer->data, 0, IS_BUFFER_SIZE); memset(is_viewer->output_buffer, 0, IS_BUFFER_SIZE); is_viewer->buffer_pos = 0; } void read_is_viewer(void* opaque, uint32_t address, uint32_t* value) { struct is_viewer* is_viewer = (struct is_viewer*)opaque; address &= IS_ADDR_MASK; memcpy(value, &is_viewer->data[address], 4); *value = big32(*value); } void write_is_viewer(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct is_viewer* is_viewer = (struct is_viewer*)opaque; address &= IS_ADDR_MASK; uint32_t word = value & mask; if (address == 0x14) { if (word > 0) { /* make sure we don't overflow the buffer */ if (is_viewer->buffer_pos + word > IS_BUFFER_SIZE) { /* reset buffer */ memset(is_viewer->output_buffer, 0, IS_BUFFER_SIZE); is_viewer->buffer_pos = 0; DebugMessage(M64MSG_WARNING, "IS64: prevented buffer overflow, cleared buffer"); return; } memcpy(&is_viewer->output_buffer[is_viewer->buffer_pos], &is_viewer->data[0x20], word); is_viewer->buffer_pos += word; /* process new lines in buffer to prevent empty debug messages without losing data */ char* newline = memchr(is_viewer->output_buffer, '\n', is_viewer->buffer_pos); while (newline) { size_t index = (newline - is_viewer->output_buffer) + 1; *newline = '\0'; DebugMessage(M64MSG_INFO, "IS64: %s", is_viewer->output_buffer); memcpy(&is_viewer->output_buffer, &is_viewer->output_buffer[index], IS_BUFFER_SIZE - index); is_viewer->buffer_pos -= index; newline = memchr(is_viewer->output_buffer, '\n', is_viewer->buffer_pos); } } } else { word = big32(word); memcpy(&is_viewer->data[address], &word, sizeof(word)); } } mupen64plus-core-src-2.6.0/src/device/cart/is_viewer.h000066400000000000000000000037451464506436200226030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - is_viewer.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2021 loganmc10 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_PI_IS_VIEWER_H #define M64P_DEVICE_PI_IS_VIEWER_H #include #include #define IS_BUFFER_SIZE 0x1000 struct is_viewer { char data[IS_BUFFER_SIZE]; char output_buffer[IS_BUFFER_SIZE]; uint32_t buffer_pos; }; void poweron_is_viewer(struct is_viewer* is_viewer); void read_is_viewer(void* opaque, uint32_t address, uint32_t* value); void write_is_viewer(void* opaque, uint32_t address, uint32_t value, uint32_t mask); #endif mupen64plus-core-src-2.6.0/src/device/cart/sram.c000066400000000000000000000066121464506436200215400ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - sram.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "sram.h" #include #include #include #include "backends/api/storage_backend.h" #include "device/memory/memory.h" #define SRAM_ADDR_MASK UINT32_C(0x0000ffff) void format_sram(uint8_t* mem) { memset(mem, 0xff, SRAM_SIZE); } void init_sram(struct sram* sram, void* storage, const struct storage_backend_interface* istorage) { sram->storage = storage; sram->istorage = istorage; } unsigned int sram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { size_t i; struct sram* sram = (struct sram*)opaque; uint8_t* mem = sram->istorage->data(sram->storage); cart_addr &= SRAM_ADDR_MASK; for (i = 0; i < length; ++i) { mem[(cart_addr+i)^S8] = dram[(dram_addr+i)^S8]; } sram->istorage->save(sram->storage, cart_addr, length); return /* length / 8 */0x1000; } unsigned int sram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { size_t i; struct sram* sram = (struct sram*)opaque; const uint8_t* mem = sram->istorage->data(sram->storage); cart_addr &= SRAM_ADDR_MASK; for (i = 0; i < length; ++i) { dram[(dram_addr+i)^S8] = mem[(cart_addr+i)^S8]; } return /* length / 8 */0x1000; } void read_sram(void* opaque, uint32_t address, uint32_t* value) { struct sram* sram = (struct sram*)opaque; const uint8_t* mem = sram->istorage->data(sram->storage); address &= SRAM_ADDR_MASK; *value = *(uint32_t*)(mem + address); } void write_sram(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct sram* sram = (struct sram*)opaque; uint8_t* mem = sram->istorage->data(sram->storage); address &= SRAM_ADDR_MASK; masked_write((uint32_t*)(mem + address), value, mask); sram->istorage->save(sram->storage, address, sizeof(value)); } mupen64plus-core-src-2.6.0/src/device/cart/sram.h000066400000000000000000000044161464506436200215450ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - sram.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_PI_SRAM_H #define M64P_DEVICE_PI_SRAM_H #include struct storage_backend_interface; enum { SRAM_SIZE = 0x8000 }; struct sram { void* storage; const struct storage_backend_interface* istorage; }; void format_sram(uint8_t* sram); void init_sram(struct sram* sram, void* storage, const struct storage_backend_interface* istorage); unsigned int sram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int sram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); void read_sram(void* opaque, uint32_t address, uint32_t* value); void write_sram(void* opaque, uint32_t address, uint32_t value, uint32_t mask); #endif mupen64plus-core-src-2.6.0/src/device/controllers/000077500000000000000000000000001464506436200220425ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/controllers/game_controller.c000066400000000000000000000154621464506436200253720ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - game_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "game_controller.h" #include "api/callbacks.h" #include "api/m64p_types.h" #include "backends/api/controller_input_backend.h" #include "backends/api/joybus.h" #ifdef COMPARE_CORE #include "api/debugger.h" #endif #include #include enum { PAK_CHUNK_SIZE = 0x20 }; enum controller_status { CONT_STATUS_PAK_PRESENT = 0x01, CONT_STATUS_PAK_CHANGED = 0x02, CONT_STATUS_PAK_ADDR_CRC_ERR = 0x04 }; /* Standard controller */ static void standard_controller_reset(struct game_controller* cont) { /* reset controller status */ cont->status = 0x00; /* if pak is connected */ if (cont->ipak != NULL) { cont->status |= CONT_STATUS_PAK_PRESENT; } else { cont->status |= CONT_STATUS_PAK_CHANGED; } /* XXX: recalibrate joysticks */ } const struct game_controller_flavor g_standard_controller_flavor = { "Standard controller", JDT_JOY_ABS_COUNTERS | JDT_JOY_PORT, standard_controller_reset }; /* Pak handling functions */ void change_pak(struct game_controller* cont, void* pak, const struct pak_interface* ipak) { cont->status &= ~(CONT_STATUS_PAK_PRESENT | CONT_STATUS_PAK_CHANGED); /* unplug previous pak (if any) */ if (cont->ipak != NULL) { cont->ipak->unplug(cont->pak); cont->status |= CONT_STATUS_PAK_CHANGED; } /* plug new one (if any) */ if (ipak != NULL) { ipak->plug(pak); cont->status |= CONT_STATUS_PAK_PRESENT; } /* set new pak */ cont->pak = pak; cont->ipak = ipak; } static uint8_t pak_data_crc(const uint8_t* data, size_t size) { size_t i; uint8_t crc = 0; for(i = 0; i <= size; ++i) { int mask; for (mask = 0x80; mask >= 1; mask >>= 1) { uint8_t xor_tap = (crc & 0x80) ? 0x85 : 0x00; crc <<= 1; if (i != size && (data[i] & mask)) crc |= 1; crc ^= xor_tap; } } return crc; } static void pak_read_block(struct game_controller* cont, const uint8_t* addr_acrc, uint8_t* data, uint8_t* dcrc) { uint16_t address = (addr_acrc[0] << 8) | (addr_acrc[1] & 0xe0); #if 0 uint8_t acrc = addr_acrc[1] & 0x1f; #endif if (cont->ipak != NULL) { cont->ipak->read(cont->pak, address, data, PAK_CHUNK_SIZE); *dcrc = pak_data_crc(data, PAK_CHUNK_SIZE); } else { //NOT the CRC value when pak is not present *dcrc = ~pak_data_crc(data, PAK_CHUNK_SIZE); } } static void pak_write_block(struct game_controller* cont, const uint8_t* addr_acrc, const uint8_t* data, uint8_t* dcrc) { uint16_t address = (addr_acrc[0] << 8) | (addr_acrc[1] & 0xe0); #if 0 uint8_t acrc = addr_acrc[1] & 0x1f; #endif if (cont->ipak != NULL) { cont->ipak->write(cont->pak, address, data, PAK_CHUNK_SIZE); *dcrc = pak_data_crc(data, PAK_CHUNK_SIZE); } else { *dcrc = ~pak_data_crc(data, PAK_CHUNK_SIZE); } } /* Mouse controller */ static void mouse_controller_reset(struct game_controller* cont) { cont->status = 0x00; } const struct game_controller_flavor g_mouse_controller_flavor = { "Mouse controller", JDT_JOY_REL_COUNTERS, mouse_controller_reset }; void init_game_controller(struct game_controller* cont, const struct game_controller_flavor* flavor, void* cin, const struct controller_input_backend_interface* icin, void* pak, const struct pak_interface* ipak) { cont->flavor = flavor; cont->cin = cin; cont->icin = icin; cont->pak = pak; cont->ipak = ipak; } static void poweron_game_controller(void* jbd) { struct game_controller* cont = (struct game_controller*)jbd; cont->flavor->reset(cont); if (cont->flavor == &g_standard_controller_flavor && cont->ipak != NULL) { cont->ipak->plug(cont->pak); } } static void process_controller_command(void* jbd, const uint8_t* tx, const uint8_t* tx_buf, uint8_t* rx, uint8_t* rx_buf) { struct game_controller* cont = (struct game_controller*)jbd; uint32_t input_ = 0; uint8_t cmd = tx_buf[0]; /* if controller can't successfully be polled, consider it to be absent */ if (cont->icin->get_input(cont->cin, &input_) != M64ERR_SUCCESS) { *rx |= 0x80; return; } switch (cmd) { case JCMD_RESET: cont->flavor->reset(cont); /* fall through */ case JCMD_STATUS: { JOYBUS_CHECK_COMMAND_FORMAT(1, 3) rx_buf[0] = (uint8_t)(cont->flavor->type >> 0); rx_buf[1] = (uint8_t)(cont->flavor->type >> 8); rx_buf[2] = cont->status; } break; case JCMD_CONTROLLER_READ: { JOYBUS_CHECK_COMMAND_FORMAT(1, 4) *((uint32_t*)(rx_buf)) = input_; #ifdef COMPARE_CORE CoreCompareDataSync(4, rx_buf); #endif } break; case JCMD_PAK_READ: { JOYBUS_CHECK_COMMAND_FORMAT(3, 33) pak_read_block(cont, &tx_buf[1], &rx_buf[0], &rx_buf[32]); } break; case JCMD_PAK_WRITE: { JOYBUS_CHECK_COMMAND_FORMAT(35, 1) pak_write_block(cont, &tx_buf[1], &tx_buf[3], &rx_buf[0]); } break; default: DebugMessage(M64MSG_WARNING, "cont: Unknown command %02x %02x %02x", *tx, *rx, cmd); } } const struct joybus_device_interface g_ijoybus_device_controller = { poweron_game_controller, process_controller_command, NULL }; mupen64plus-core-src-2.6.0/src/device/controllers/game_controller.h000066400000000000000000000061321464506436200253710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - game_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_GAME_CONTROLLER_H #define M64P_DEVICE_SI_GAME_CONTROLLER_H #include "backends/api/joybus.h" #include #include struct game_controller; struct controller_input_backend_interface; struct game_controller_flavor { const char* name; uint16_t type; /* controller reset procedure */ void (*reset)(struct game_controller* cont); }; struct pak_interface { const char* name; void (*plug)(void* pak); void (*unplug)(void* pak); void (*read)(void* pak, uint16_t address, uint8_t* data, size_t size); void (*write)(void* pak, uint16_t address, const uint8_t* data, size_t size); }; struct game_controller { uint8_t status; const struct game_controller_flavor* flavor; void* cin; const struct controller_input_backend_interface* icin; void* pak; const struct pak_interface* ipak; /* VRU */ uint8_t voice_state; uint8_t load_offset; uint8_t voice_init; uint16_t word[40]; }; void init_game_controller(struct game_controller* cont, const struct game_controller_flavor* flavor, void* cin, const struct controller_input_backend_interface* icin, void* pak, const struct pak_interface* ipak); void change_pak(struct game_controller* cont, void* pak, const struct pak_interface* ipak); /* Controller Joybus interface */ extern const struct joybus_device_interface g_ijoybus_device_controller; /* Controller flavors */ extern const struct game_controller_flavor g_standard_controller_flavor; extern const struct game_controller_flavor g_mouse_controller_flavor; #endif mupen64plus-core-src-2.6.0/src/device/controllers/paks/000077500000000000000000000000001464506436200230005ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/controllers/paks/biopak.c000066400000000000000000000052661464506436200244220ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - biopak.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Implementation based on notes from raphnet * See http://www.raphnet.net/divers/n64_bio_sensor/index_en.php */ #include "biopak.h" #include "api/m64p_types.h" #include "api/callbacks.h" #include #include void init_biopak(struct biopak* bpk, unsigned int bpm) { bpk->bpm = bpm; } static void plug_biopak(void* pak) { } static void unplug_biopak(void* pak) { } static void read_biopak(void* pak, uint16_t address, uint8_t* data, size_t size) { struct biopak* bpk = (struct biopak*)pak; if (address == 0xc000) { uint32_t now = SDL_GetTicks(); uint32_t period = UINT32_C(60*1000) / bpk->bpm; uint32_t k = now % period; memset(data, (2*k < period) ? 0x00 : 0x03, size); } else { DebugMessage(M64MSG_WARNING, "Unexpected bio sensor read address %04x", address); } } static void write_biopak(void* pak, uint16_t address, const uint8_t* data, size_t size) { DebugMessage(M64MSG_WARNING, "Unexpected bio sensor write address %04x", address); } /* bio pak definition */ const struct pak_interface g_ibiopak = { "Bio pak", plug_biopak, unplug_biopak, read_biopak, write_biopak }; mupen64plus-core-src-2.6.0/src/device/controllers/paks/biopak.h000066400000000000000000000034601464506436200244210ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - biopak.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_CONTROLLERS_PAKS_BIOPAK_H #define M64P_DEVICE_CONTROLLERS_PAKS_BIOPAK_H #include "device/controllers/game_controller.h" struct biopak { unsigned int bpm; }; void init_biopak(struct biopak* bpk, unsigned int bpm); extern const struct pak_interface g_ibiopak; #endif mupen64plus-core-src-2.6.0/src/device/controllers/paks/mempak.c000066400000000000000000000141361464506436200244230ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - mempak.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "mempak.h" #include "backends/api/storage_backend.h" #include "device/controllers/game_controller.h" #include "main/util.h" #include #include #include #include /* Serialized representation of ID Block * Only used to ease offsets/pointers computation * DO NOT DEREFERENCE */ #pragma pack(push, 1) struct id_block_serialized { uint32_t serial[6]; uint16_t device_id; uint8_t banks; uint8_t version; uint16_t sum; uint16_t isum; }; #pragma pack(pop) #if defined(static_assert) static_assert(sizeof(struct id_block_serialized) == 32, "id_block_serialized must have a size of 32 bytes"); #endif static void checksum_id_block(unsigned char* ptr, uint16_t* sum, uint16_t* isum) { size_t i; uint16_t accu = 0; for (i = 0; i < offsetof(struct id_block_serialized, sum); i += 2) { accu += load_beu16((void*)&ptr[i]); } *sum = accu; *isum = UINT16_C(0xfff2) - accu; } static uint8_t checksum_index_table(size_t count, unsigned char* ptr) { unsigned sum = 0; while (count != 0) { sum += load_beu8((void*)ptr); ++ptr; --count; } return (uint8_t)sum; } static void serialize_id_block(unsigned char *ptr, const uint32_t serial[6], uint16_t device_id, uint8_t banks, uint8_t version) { size_t i; /* _ should never be dereferenced - it is only used to ease pointer/offsets computation */ struct id_block_serialized* const _ = (struct id_block_serialized*)ptr; for (i = 0; i < 6; ++i) { store_beu32(serial[i], (void*)&_->serial[i]); } store_beu16(device_id, (void*)&_->device_id); store_beu8(banks, (void*)&_->banks); store_beu8(version, (void*)&_->version); uint16_t sum, isum; checksum_id_block(ptr, &sum, &isum); store_beu16(sum, (void*)&_->sum); store_beu16(isum, (void*)&_->isum); } void format_mempak(uint8_t* mem, const uint32_t serial[6], uint16_t device_id, uint8_t banks, uint8_t version) { enum { MPK_PAGE_SIZE = 256 }; uint8_t* const page_0 = mem + 0*MPK_PAGE_SIZE; uint8_t* const page_1 = mem + 1*MPK_PAGE_SIZE; uint8_t* const page_2 = mem + 2*MPK_PAGE_SIZE; uint8_t* const page_3 = mem + 3*MPK_PAGE_SIZE; /* Page 0 is divided in 8 x 32-byte blocks: * 0. reserved * 1. ID * 2. reserved * 3. ID backup #1 * 4. ID backup #2 * 5. reserved * 6. ID backup #3 * 7. reserved */ serialize_id_block(page_0 + 1*32, serial, device_id, banks, version); memset(page_0 + 0*32, 0, 32); memset(page_0 + 2*32, 0, 32); memset(page_0 + 5*32, 0, 32); memset(page_0 + 7*32, 0, 32); memcpy(page_0 + 3*32, page_0 + 1*32, 32); memcpy(page_0 + 4*32, page_0 + 1*32, 32); memcpy(page_0 + 6*32, page_0 + 1*32, 32); /* Page 1 holds the index table. * The first 5 inodes are reserved because the first 5 pages are reserved. * The first inode page index holds the checksum of the 123 normal nodes. * The remaining 123 pages are marked empty. */ size_t start_page = 5; size_t last_page = 128; size_t i; memset(page_1, 0, 2*start_page); for(i = start_page; i < last_page; ++i) { store_beu16(UINT16_C(0x0003), page_1 + 2*i); } page_1[1] = checksum_index_table(2*(last_page-start_page), page_1 + 2*start_page); /* Page 2 is a backup of Page 1 */ memcpy(page_2, page_1, MPK_PAGE_SIZE); /* Remaining pages DIR+DATA (3...) are initialized with 0x00 */ memset(page_3, 0, MEMPAK_SIZE - 3*MPK_PAGE_SIZE); } void init_mempak(struct mempak* mpk, void* storage, const struct storage_backend_interface* istorage) { mpk->storage = storage; mpk->istorage = istorage; } static void plug_mempak(void* pak) { } static void unplug_mempak(void* pak) { } static void read_mempak(void* pak, uint16_t address, uint8_t* data, size_t size) { struct mempak* mpk = (struct mempak*)pak; if (address < 0x8000) { memcpy(data, mpk->istorage->data(mpk->storage) + address, size); } else { memset(data, 0x00, size); } } static void write_mempak(void* pak, uint16_t address, const uint8_t* data, size_t size) { struct mempak* mpk = (struct mempak*)pak; if (address < 0x8000) { memcpy(mpk->istorage->data(mpk->storage) + address, data, size); mpk->istorage->save(mpk->storage, address, size); } else { /* do nothing */ } } /* Memory pak definition */ const struct pak_interface g_imempak = { "Memory pak", plug_mempak, unplug_mempak, read_mempak, write_mempak }; mupen64plus-core-src-2.6.0/src/device/controllers/paks/mempak.h000066400000000000000000000043361464506436200244310ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - mempak.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_MEMPAK_H #define M64P_DEVICE_SI_MEMPAK_H #include #include struct storage_backend_interface; #define DEFAULT_MEMPAK_DEVICEID UINT16_C(0x0001) #define DEFAULT_MEMPAK_BANKS UINT8_C(0x01) #define DEFAULT_MEMPAK_VERSION UINT8_C(0x00) struct mempak { void* storage; const struct storage_backend_interface* istorage; }; enum { MEMPAK_SIZE = 0x8000 }; void format_mempak(uint8_t* mem, const uint32_t serial[6], uint16_t device_id, uint8_t banks, uint8_t version); void init_mempak(struct mempak* mpk, void* storage, const struct storage_backend_interface* istorage); extern const struct pak_interface g_imempak; #endif mupen64plus-core-src-2.6.0/src/device/controllers/paks/rumblepak.c000066400000000000000000000060061464506436200251300ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rumblepak.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "rumblepak.h" #include "backends/api/rumble_backend.h" #include "device/controllers/game_controller.h" #include void set_rumble_reg(struct rumblepak* rpk, uint8_t value) { rpk->state = value; rpk->irumble->exec(rpk->rumble, (rpk->state == 0) ? RUMBLE_STOP : RUMBLE_START); } void init_rumblepak(struct rumblepak* rpk, void* rumble, const struct rumble_backend_interface* irumble) { rpk->rumble = rumble; rpk->irumble = irumble; } void poweron_rumblepak(struct rumblepak* rpk) { set_rumble_reg(rpk, 0x00); } static void plug_rumblepak(void* pak) { struct rumblepak* rpk = (struct rumblepak*)pak; poweron_rumblepak(rpk); } static void unplug_rumblepak(void* pak) { struct rumblepak* rpk = (struct rumblepak*)pak; /* Stop rumbling if pak gets disconnected */ set_rumble_reg(rpk, 0x00); } static void read_rumblepak(void* pak, uint16_t address, uint8_t* data, size_t size) { uint8_t value; if ((address >= 0x8000) && (address < 0x9000)) { value = 0x80; } else { value = 0x00; } memset(data, value, size); } static void write_rumblepak(void* pak, uint16_t address, const uint8_t* data, size_t size) { struct rumblepak* rpk = (struct rumblepak*)pak; if (address == 0xc000) { set_rumble_reg(rpk, data[size - 1]); } } /* Rumble pak definition */ const struct pak_interface g_irumblepak = { "Rumble pak", plug_rumblepak, unplug_rumblepak, read_rumblepak, write_rumblepak }; mupen64plus-core-src-2.6.0/src/device/controllers/paks/rumblepak.h000066400000000000000000000040331464506436200251330ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rumblepak.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_RUMBLEPAK_H #define M64P_DEVICE_SI_RUMBLEPAK_H #include #include struct rumble_backend_interface; struct rumblepak { uint8_t state; void* rumble; const struct rumble_backend_interface* irumble; }; void init_rumblepak(struct rumblepak* rpk, void* rumble, const struct rumble_backend_interface* irumble); void poweron_rumblepak(struct rumblepak* rpk); void set_rumble_reg(struct rumblepak* rpk, uint8_t value); extern const struct pak_interface g_irumblepak; #endif mupen64plus-core-src-2.6.0/src/device/controllers/paks/transferpak.c000066400000000000000000000147031464506436200254710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - transferpak.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This work is based on the NRage plugin source. * Transfer pak emulation is certainly NOT accurate * but without proper reverse-engineering this as good as we can get. */ #include "transferpak.h" #include "api/m64p_types.h" #include "api/callbacks.h" #include "device/gb/gb_cart.h" #include "device/controllers/game_controller.h" #include static uint16_t gb_cart_address(unsigned int bank, uint16_t address) { return (address & 0x3fff) | ((bank & 0x3) * 0x4000) ; } void init_transferpak(struct transferpak* tpk, struct gb_cart* gb_cart) { tpk->gb_cart = gb_cart; } void poweron_transferpak(struct transferpak* tpk) { tpk->enabled = 0; tpk->bank = 0; tpk->access_mode = (tpk->gb_cart == NULL) ? CART_NOT_INSERTED : CART_ACCESS_MODE_0; tpk->access_mode_changed = 0x44; if (tpk->gb_cart != NULL) { poweron_gb_cart(tpk->gb_cart); } } void change_gb_cart(struct transferpak* tpk, struct gb_cart* gb_cart) { tpk->enabled = 0; if (gb_cart == NULL) { tpk->access_mode = CART_NOT_INSERTED; } else { tpk->access_mode = CART_ACCESS_MODE_0; poweron_gb_cart(gb_cart); } tpk->gb_cart = gb_cart; } static void plug_transferpak(void* pak) { struct transferpak* tpk = (struct transferpak*)pak; poweron_transferpak(tpk); } static void unplug_transferpak(void* pak) { } static void read_transferpak(void* pak, uint16_t address, uint8_t* data, size_t size) { struct transferpak* tpk = (struct transferpak*)pak; uint8_t value; DebugMessage(M64MSG_VERBOSE, "tpak read: %04x", address); switch(address >> 12) { case 0x8: /* get gb cart state (enabled/disabled) */ value = (tpk->enabled) ? 0x84 : 0x00; DebugMessage(M64MSG_VERBOSE, "tpak get cart state: %02x", value); memset(data, value, size); break; case 0xb: /* get gb cart access mode */ if (tpk->enabled) { DebugMessage(M64MSG_VERBOSE, "tpak get access mode: %02x", tpk->access_mode); memset(data, tpk->access_mode, size); if (tpk->access_mode != CART_NOT_INSERTED) { data[0] |= tpk->access_mode_changed; } tpk->access_mode_changed = 0; } break; case 0xc: case 0xd: case 0xe: case 0xf: /* read gb cart */ if (tpk->enabled) { DebugMessage(M64MSG_VERBOSE, "tpak read cart: %04x", address); if (tpk->gb_cart != NULL) { read_gb_cart(tpk->gb_cart, gb_cart_address(tpk->bank, address), data, size); } } break; default: DebugMessage(M64MSG_WARNING, "Unknown tpak read: %04x", address); } } static void write_transferpak(void* pak, uint16_t address, const uint8_t* data, size_t size) { struct transferpak* tpk = (struct transferpak*)pak; uint8_t value = data[size-1]; DebugMessage(M64MSG_VERBOSE, "tpak write: %04x <- %02x", address, value); switch(address >> 12) { case 0x8: /* enable / disable gb cart */ switch(value) { case 0xfe: tpk->enabled = 0; DebugMessage(M64MSG_VERBOSE, "tpak disabled"); break; case 0x84: tpk->enabled = 1; DebugMessage(M64MSG_VERBOSE, "tpak enabled"); break; default: DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value); } break; case 0xa: /* set gb cart bank */ if (tpk->enabled) { tpk->bank = value; DebugMessage(M64MSG_VERBOSE, "tpak set bank %02x", tpk->bank); } break; case 0xb: /* set gb cart access mode */ if (tpk->enabled) { tpk->access_mode_changed = 0x04; tpk->access_mode = ((value & 1) == 0) ? CART_ACCESS_MODE_0 : CART_ACCESS_MODE_1; if ((value & 0xfe) != 0) { DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value); } DebugMessage(M64MSG_VERBOSE, "tpak set access mode %02x", tpk->access_mode); } break; case 0xc: case 0xd: case 0xe: case 0xf: /* write gb cart */ // if (tpk->enabled) { DebugMessage(M64MSG_VERBOSE, "tpak write gb: %04x <- %02x", address, value); if (tpk->gb_cart != NULL) { write_gb_cart(tpk->gb_cart, gb_cart_address(tpk->bank, address), data, size); } } break; default: DebugMessage(M64MSG_WARNING, "Unknown tpak write: %04x <- %02x", address, value); } } /* Transfer pak definition */ const struct pak_interface g_itransferpak = { "Transfer pak", plug_transferpak, unplug_transferpak, read_transferpak, write_transferpak }; mupen64plus-core-src-2.6.0/src/device/controllers/paks/transferpak.h000066400000000000000000000042541464506436200254760ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - transferpak.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_TRANSFERPAK_H #define M64P_DEVICE_SI_TRANSFERPAK_H #include #include struct gb_cart; enum cart_access_mode { CART_NOT_INSERTED = 0x40, CART_ACCESS_MODE_0 = 0x80, CART_ACCESS_MODE_1 = 0x89 }; struct transferpak { unsigned int enabled; unsigned int bank; unsigned int access_mode; unsigned int access_mode_changed; struct gb_cart* gb_cart; }; void init_transferpak(struct transferpak* tpk, struct gb_cart* gb_cart); void poweron_transferpak(struct transferpak* tpk); void change_gb_cart(struct transferpak* tpk, struct gb_cart* gb_cart); extern const struct pak_interface g_itransferpak; #endif mupen64plus-core-src-2.6.0/src/device/controllers/vru_controller.c000066400000000000000000000216051464506436200252710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - vru_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "game_controller.h" #include "vru_controller.h" #include "api/callbacks.h" #include "api/m64p_types.h" #include "backends/api/controller_input_backend.h" #include "backends/api/joybus.h" #include "plugin/plugin.h" #include "main/rom.h" #ifdef COMPARE_CORE #include "api/debugger.h" #endif #include #include enum voice_status { VOICE_STATUS_READY = 0x00, VOICE_STATUS_START = 0x01, VOICE_STATUS_CANCEL = 0x03, VOICE_STATUS_BUSY = 0x05, VOICE_STATUS_END = 0x07 }; static uint8_t vru_data_crc(const uint8_t* data, size_t size) { size_t i; uint8_t crc = 0; for(i = 0; i <= size; ++i) { int mask; for (mask = 0x80; mask >= 1; mask >>= 1) { uint8_t xor_tap = (crc & 0x80) ? 0x85 : 0x00; crc <<= 1; if (i != size && (data[i] & mask)) crc |= 1; crc ^= xor_tap; } } return crc; } /* VRU controller */ static void vru_controller_reset(struct game_controller* cont) { cont->status = 0x00; if (ROM_HEADER.Country_code == 0x4A /* Japan */ || ROM_HEADER.Country_code == 0x00 /* Demo */) cont->voice_state = VOICE_STATUS_READY; else cont->voice_state = VOICE_STATUS_START; cont->load_offset = 0; cont->voice_init = 1; memset(cont->word, 0, 80); } const struct game_controller_flavor g_vru_controller_flavor = { "VRU controller", JDT_VRU, vru_controller_reset }; static void poweron_vru_controller(void* jbd) { struct game_controller* cont = (struct game_controller*)jbd; cont->flavor->reset(cont); } static void process_vru_command(void* jbd, const uint8_t* tx, const uint8_t* tx_buf, uint8_t* rx, uint8_t* rx_buf) { struct game_controller* cont = (struct game_controller*)jbd; uint32_t input_ = 0; uint8_t cmd = tx_buf[0]; /* if controller can't successfully be polled, consider it to be absent */ if (cont->icin->get_input(cont->cin, &input_) != M64ERR_SUCCESS) { *rx |= 0x80; return; } switch (cmd) { case JCMD_RESET: cont->flavor->reset(cont); /* fall through */ case JCMD_STATUS: { JOYBUS_CHECK_COMMAND_FORMAT(1, 3) if (cont->voice_init == 2) { /* words have been loaded, we can change the state from READY to START */ cont->voice_state = VOICE_STATUS_START; cont->voice_init = 1; } else if ((input_ & 0x0020) && (cont->voice_state == VOICE_STATUS_START)) { /* HACK: The Z input on the VRU controller is used to indicate that someone is talking */ /* On Densha de Go, if the player is talking for more than ~2.5 seconds, the input is ignored */ cont->voice_state = VOICE_STATUS_BUSY; cont->status = 0; /* setting the status to 0 tells the game to check the voice_status */ } else if (!(input_ & 0x0020) && (cont->voice_state == VOICE_STATUS_BUSY)) { cont->voice_state = VOICE_STATUS_READY; cont->status = 0; /* setting the status to 0 tells the game to check the voice_status */ } rx_buf[0] = (uint8_t)(cont->flavor->type >> 0); rx_buf[1] = (uint8_t)(cont->flavor->type >> 8); rx_buf[2] = cont->status; } break; case JCMD_CONTROLLER_READ: { JOYBUS_CHECK_COMMAND_FORMAT(1, 4) #ifdef COMPARE_CORE CoreCompareDataSync(4, rx_buf); #endif } break; case JCMD_VRU_READ_STATUS: { JOYBUS_CHECK_COMMAND_FORMAT(3, 3) rx_buf[0] = cont->voice_init ? cont->voice_state : 0; rx_buf[1] = 0; rx_buf[2] = vru_data_crc(&rx_buf[0], 2); if (cont->load_offset > 0) { uint8_t offset = 0; while (cont->word[offset] == 0 && offset < 40) ++offset; if (offset == 40) { DebugMessage(M64MSG_WARNING, "Empty JCMD_VRU_WRITE."); } else if (cont->word[offset] == 3) { offset += 3; uint16_t length = cont->word[offset]; if (ROM_HEADER.Country_code == 0x4A /* Japan */ || ROM_HEADER.Country_code == 0x00 /* Demo */) { offset -= 1; length = 0; while (cont->word[offset + length] != 0) { ++length; } input.sendVRUWord(length, &cont->word[offset], 1); } else { ++offset; input.sendVRUWord(length, &cont->word[offset], 0); } } else { /* Unhandled command, could be a string/word mask. For a mask: "Data is right-aligned and padded with zeroes to an even length, followed with command 0004. Set bits allow strings, unset ignores." I haven't seen Hey You Pikachu or Densha de GO use the mask command, so I wasn't able to test. TODO: Call input.SetVRUWordMask() to tell the input plugin about the mask settings */ DebugMessage(M64MSG_WARNING, "Unknown command in JCMD_VRU_WRITE."); } cont->load_offset = 0; } cont->status = 1; } break; case JCMD_VRU_WRITE_CONFIG: { JOYBUS_CHECK_COMMAND_FORMAT(7, 1) rx_buf[0] = vru_data_crc(&tx_buf[3], 4); if (rx_buf[0] == 0x4E) { input.setMicState(1); cont->voice_init = 2; } else if (rx_buf[0] == 0xEF) { input.setMicState(0); } else if (tx_buf[3] == 0x2) { cont->voice_init = 0; input.clearVRUWords(tx_buf[5]); } cont->status = 0; /* status is always set to 0 after a write */ } break; case JCMD_VRU_WRITE_INIT: { JOYBUS_CHECK_COMMAND_FORMAT(3, 1) if (*((uint16_t*)(&tx_buf[1])) == 0) input.setMicState(0); rx_buf[0] = 0; } break; case JCMD_VRU_READ: { JOYBUS_CHECK_COMMAND_FORMAT(3, 37) *((uint16_t*)(&rx_buf[0])) = 0x8000; /* as per zoinkity https://pastebin.com/6UiErk5h */ *((uint16_t*)(&rx_buf[2])) = 0x0F00; /* as per zoinkity https://pastebin.com/6UiErk5h */ *((uint16_t*)(&rx_buf[34])) = 0x0040; /* as per zoinkity https://pastebin.com/6UiErk5h */ input.readVRUResults((uint16_t*)&rx_buf[4] /*error flags*/, (uint16_t*)&rx_buf[6] /*number of results*/, (uint16_t*)&rx_buf[8] /*mic level*/, \ (uint16_t*)&rx_buf[10] /*voice level*/, (uint16_t*)&rx_buf[12] /*voice length*/, (uint16_t*)&rx_buf[14] /*matches*/); rx_buf[36] = vru_data_crc(&rx_buf[0], 36); cont->voice_state = VOICE_STATUS_START; } break; case JCMD_VRU_WRITE: { JOYBUS_CHECK_COMMAND_FORMAT(23, 1) rx_buf[0] = vru_data_crc(&tx_buf[3], 20); if (cont->load_offset == 0) memset(cont->word, 0, 80); memcpy(&cont->word[cont->load_offset], &tx_buf[3], 20); cont->load_offset += 10; cont->status = 0; /* status is always set to 0 after a write */ } break; default: DebugMessage(M64MSG_WARNING, "cont: Unknown command %02x %02x %02x", *tx, *rx, cmd); } } const struct joybus_device_interface g_ijoybus_vru_controller = { poweron_vru_controller, process_vru_command, NULL }; mupen64plus-core-src-2.6.0/src/device/controllers/vru_controller.h000066400000000000000000000035641464506436200253020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - vru_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_VRU_CONTROLLER_H #define M64P_DEVICE_SI_VRU_CONTROLLER_H #include "backends/api/joybus.h" #include #include /* Controller Joybus interface */ extern const struct joybus_device_interface g_ijoybus_vru_controller; /* Controller flavors */ extern const struct game_controller_flavor g_vru_controller_flavor; #endif mupen64plus-core-src-2.6.0/src/device/dd/000077500000000000000000000000001464506436200200635ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/dd/dd_controller.c000066400000000000000000000774211464506436200230740ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dd_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2015 LuigiBlood * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "dd_controller.h" #include #include #include #include #define M64P_CORE_PROTOTYPES 1 #include "api/m64p_types.h" #include "api/callbacks.h" #include "backends/api/clock_backend.h" #include "backends/api/storage_backend.h" #include "device/dd/disk.h" #include "device/device.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" /* dd commands definition */ #define DD_CMD_NOOP UINT32_C(0x00000000) #define DD_CMD_SEEK_READ UINT32_C(0x00010001) #define DD_CMD_SEEK_WRITE UINT32_C(0x00020001) #define DD_CMD_RECALIBRATE UINT32_C(0x00030001) // ??? #define DD_CMD_SLEEP UINT32_C(0x00040000) #define DD_CMD_START UINT32_C(0x00050001) #define DD_CMD_SET_STANDBY UINT32_C(0x00060000) #define DD_CMD_SET_SLEEP UINT32_C(0x00070000) #define DD_CMD_CLR_DSK_CHNG UINT32_C(0x00080000) #define DD_CMD_CLR_RESET UINT32_C(0x00090000) #define DD_CMD_READ_VERSION UINT32_C(0x000A0000) #define DD_CMD_SET_DISK_TYPE UINT32_C(0x000B0001) #define DD_CMD_REQUEST_STATUS UINT32_C(0x000C0000) #define DD_CMD_STANDBY UINT32_C(0x000D0000) #define DD_CMD_IDX_LOCK_RETRY UINT32_C(0x000E0000) // ??? #define DD_CMD_SET_YEAR_MONTH UINT32_C(0x000F0000) #define DD_CMD_SET_DAY_HOUR UINT32_C(0x00100000) #define DD_CMD_SET_MIN_SEC UINT32_C(0x00110000) #define DD_CMD_GET_YEAR_MONTH UINT32_C(0x00120000) #define DD_CMD_GET_DAY_HOUR UINT32_C(0x00130000) #define DD_CMD_GET_MIN_SEC UINT32_C(0x00140000) #define DD_CMD_FEATURE_INQ UINT32_C(0x001B0000) /* dd status register bitfields definition */ #define DD_STATUS_DATA_RQ UINT32_C(0x40000000) #define DD_STATUS_C2_XFER UINT32_C(0x10000000) #define DD_STATUS_BM_ERR UINT32_C(0x08000000) #define DD_STATUS_BM_INT UINT32_C(0x04000000) #define DD_STATUS_MECHA_INT UINT32_C(0x02000000) #define DD_STATUS_DISK_PRES UINT32_C(0x01000000) #define DD_STATUS_BUSY_STATE UINT32_C(0x00800000) #define DD_STATUS_RST_STATE UINT32_C(0x00400000) #define DD_STATUS_MTR_N_SPIN UINT32_C(0x00100000) #define DD_STATUS_HEAD_RTRCT UINT32_C(0x00080000) #define DD_STATUS_WR_PR_ERR UINT32_C(0x00040000) #define DD_STATUS_MECHA_ERR UINT32_C(0x00020000) #define DD_STATUS_DISK_CHNG UINT32_C(0x00010000) /* dd bm status register bitfields definition */ /* read flags */ #define DD_BM_STATUS_RUNNING UINT32_C(0x80000000) #define DD_BM_STATUS_ERROR UINT32_C(0x04000000) #define DD_BM_STATUS_MICRO UINT32_C(0x02000000) /* ??? */ #define DD_BM_STATUS_BLOCK UINT32_C(0x01000000) #define DD_BM_STATUS_C1CRR UINT32_C(0x00800000) #define DD_BM_STATUS_C1DBL UINT32_C(0x00400000) #define DD_BM_STATUS_C1SNG UINT32_C(0x00200000) #define DD_BM_STATUS_C1ERR UINT32_C(0x00010000) /* Typo ??? */ /* write flags */ #define DD_BM_CTL_START UINT32_C(0x80000000) #define DD_BM_CTL_MNGRMODE UINT32_C(0x40000000) #define DD_BM_CTL_INTMASK UINT32_C(0x20000000) #define DD_BM_CTL_RESET UINT32_C(0x10000000) #define DD_BM_CTL_DIS_OR_CHK UINT32_C(0x08000000) /* ??? */ #define DD_BM_CTL_DIS_C1_CRR UINT32_C(0x04000000) #define DD_BM_CTL_BLK_TRANS UINT32_C(0x02000000) #define DD_BM_CTL_MECHA_RST UINT32_C(0x01000000) #define DD_TRACK_LOCK UINT32_C(0x60000000) static uint8_t byte2bcd(int n) { n %= 100; return (uint8_t)(((n / 10) << 4) | (n % 10)); } static uint32_t time2data(int hi, int lo) { return ((uint32_t)byte2bcd(hi) << 24) | ((uint32_t)byte2bcd(lo) << 16); } static void update_rtc(struct dd_rtc* rtc) { /* update rtc->now */ time_t now = rtc->iclock->get_time(rtc->clock); rtc->now += now - rtc->last_update_rtc; rtc->last_update_rtc = now; } static void signal_dd_interrupt(struct dd_controller* dd, uint32_t bm_int) { dd->regs[DD_ASIC_CMD_STATUS] |= bm_int; r4300_check_interrupt(dd->r4300, CP0_CAUSE_IP3, 1); } static void clear_dd_interrupt(struct dd_controller* dd, uint32_t bm_int) { dd->regs[DD_ASIC_CMD_STATUS] &= ~bm_int; r4300_check_interrupt(dd->r4300, CP0_CAUSE_IP3, 0); } void dd_mecha_int_handler(void* opaque) { struct dd_controller* dd = (struct dd_controller*)opaque; /* clear busy state flag */ dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_BUSY_STATE; signal_dd_interrupt(dd, DD_STATUS_MECHA_INT); } void dd_bm_int_handler(void* opaque) { struct dd_controller* dd = (struct dd_controller*)opaque; dd_update_bm(dd); } void dd_dv_active(void* opaque) { struct dd_controller* dd = (struct dd_controller*)opaque; /* make motor active and prep standby */ dd->regs[DD_ASIC_CMD_STATUS] &= ~(DD_STATUS_MTR_N_SPIN | DD_STATUS_HEAD_RTRCT); remove_event(&dd->r4300->cp0.q, DD_DV_INT); if (dd->timer_standby >= 0) { add_interrupt_event(&dd->r4300->cp0, DD_DV_INT, 46875000 * dd->timer_standby); } } void dd_dv_standby(void* opaque) { struct dd_controller* dd = (struct dd_controller*)opaque; /* make motor standby and prep sleep */ dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_MTR_N_SPIN; dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_HEAD_RTRCT; remove_event(&dd->r4300->cp0.q, DD_DV_INT); if (dd->timer_sleep >= 0) { add_interrupt_event(&dd->r4300->cp0, DD_DV_INT, 46875000 * dd->timer_sleep); } } void dd_dv_sleep(void* opaque) { struct dd_controller* dd = (struct dd_controller*)opaque; /* make motor sleep */ dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_MTR_N_SPIN | DD_STATUS_HEAD_RTRCT; remove_event(&dd->r4300->cp0.q, DD_DV_INT); } void dd_dv_int_handler(void* opaque) { struct dd_controller* dd = (struct dd_controller*)opaque; /* manage drive motor modes (active, standby, sleep) */ int motorNotSpinning = (dd->regs[DD_ASIC_CMD_STATUS] & DD_STATUS_MTR_N_SPIN) != 0; int headRetracted = (dd->regs[DD_ASIC_CMD_STATUS] & DD_STATUS_HEAD_RTRCT) != 0; if (!motorNotSpinning && headRetracted) { /* standby to sleep */ dd_dv_sleep(dd); DebugMessage(M64MSG_VERBOSE, "Disk drive motor put to sleep mode (auto)"); } if (!motorNotSpinning && !headRetracted) { /* active to standby, prep time to sleep */ dd_dv_standby(dd); DebugMessage(M64MSG_VERBOSE, "Disk drive motor put to standby mode (auto)"); } } static void read_C2(struct dd_controller* dd) { size_t i; size_t length = zone_sec_size[dd->bm_zone]; unsigned int sector = (dd->regs[DD_ASIC_CUR_SECTOR] >> 16) & 0xff; sector %= 90; size_t offset = 0x40 * (sector - SECTORS_PER_BLOCK); DebugMessage(M64MSG_VERBOSE, "read C2: length=%08x, offset=%08x", (uint32_t)length, (uint32_t)offset); for (i = 0; i < length; ++i) { dd->c2s_buf[(offset + i) ^ 3] = 0; } } static uint8_t* seek_sector(struct dd_controller* dd) { unsigned int head = (dd->regs[DD_ASIC_CUR_TK] & 0x10000000) >> 28; unsigned int track = (dd->regs[DD_ASIC_CUR_TK] & 0x0fff0000) >> 16; // XXX: takes into account that for writes dd_update_bm use the previous sector. unsigned int sector = ((dd->regs[DD_ASIC_CUR_SECTOR] >> 16) & 0xff) - dd->bm_write; unsigned int block = sector / 90; sector %= 90; uint8_t* sector_base = get_sector_base(dd->disk, head, track, block, sector); if (sector_base == NULL) { dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_MICRO; } return sector_base; } static void read_sector(struct dd_controller* dd) { size_t i; const uint8_t* disk_sec = seek_sector(dd); if (disk_sec == NULL) { return; } size_t length = dd->regs[DD_ASIC_HOST_SECBYTE] + 1; for (i = 0; i < length; ++i) { dd->ds_buf[i ^ 3] = disk_sec[i]; } } static void write_sector(struct dd_controller* dd) { size_t i; uint8_t* disk_sec = seek_sector(dd); if (disk_sec == NULL) { return; } size_t length = dd->regs[DD_ASIC_HOST_SECBYTE] + 1; for (i = 0; i < length; ++i) { disk_sec[i] = dd->ds_buf[i ^ 3]; } dd->idisk->save(dd->disk, disk_sec - dd->idisk->data(dd->disk), length); } void dd_update_bm(void* opaque) { struct dd_controller* dd = (struct dd_controller*)opaque; /* not running */ if ((dd->regs[DD_ASIC_BM_STATUS_CTL] & DD_BM_STATUS_RUNNING) == 0) { return; } /* clear flags */ dd->regs[DD_ASIC_CMD_STATUS] &= ~(DD_STATUS_DATA_RQ | DD_STATUS_C2_XFER); /* calculate sector and block info for use later */ unsigned int sector = (dd->regs[DD_ASIC_CUR_SECTOR] >> 16) & 0xff; unsigned int block = sector / 90; sector %= 90; /* handle writes (BM mode 0) */ if (dd->bm_write) { /* do not write anything and stop BM if the track being written is write protected */ if (dd->regs[DD_ASIC_CMD_STATUS] & DD_STATUS_WR_PR_ERR) { dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_BM_ERR; dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_MICRO; dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_RUNNING; } /* first sector : just issue a BM interrupt to get things going */ else if (sector == 0) { dd->regs[DD_ASIC_CUR_SECTOR] += 0x10000; dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ; } /* subsequent sectors: write previous sector */ else if (sector < SECTORS_PER_BLOCK) { write_sector(dd); dd->regs[DD_ASIC_CUR_SECTOR] += 0x10000; dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ; } /* otherwise write last sector */ else if (sector < SECTORS_PER_BLOCK + 1) { write_sector(dd); /* continue to next block */ if (dd->regs[DD_ASIC_BM_STATUS_CTL] & DD_BM_STATUS_BLOCK) { // Start at next block sector 1. dd->regs[DD_ASIC_CUR_SECTOR] = ((1 - block) * 90 + 1) << 16; dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_BLOCK; dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ; /* quit writing after second block */ } else { dd->regs[DD_ASIC_CUR_SECTOR] += 0x10000; dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_RUNNING; } } else { DebugMessage(M64MSG_ERROR, "DD Write, sector overrun"); } } /* handle reads (BM mode 1) */ else { uint8_t dev = dd->disk->development; /* track 6 fails to read on retail units (XXX: retail test) */ if ((((dd->regs[DD_ASIC_CUR_TK] >> 16) & 0x1fff) == 6) && block == 0 && !dev) { dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_DATA_RQ; dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_MICRO; } /* data sectors : read sector and signal BM interrupt */ else if (sector < SECTORS_PER_BLOCK) { read_sector(dd); dd->regs[DD_ASIC_CUR_SECTOR] += 0x10000; dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DATA_RQ; } /* C2 sectors: do nothing since they're loaded with zeros */ else if (sector < SECTORS_PER_BLOCK + 3) { read_C2(dd); dd->regs[DD_ASIC_CUR_SECTOR] += 0x10000; } /* Last C2 sector: continue to next block, quit after second block */ else if (sector == SECTORS_PER_BLOCK + 3) { read_C2(dd); dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_C2_XFER; if (dd->regs[DD_ASIC_BM_STATUS_CTL] & DD_BM_STATUS_BLOCK) { // Start at next block sector 0. dd->regs[DD_ASIC_CUR_SECTOR] = ((1 - block) * 90 + 0) << 16; dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_BLOCK; } else { dd->regs[DD_ASIC_BM_STATUS_CTL] &= ~DD_BM_STATUS_RUNNING; } } else { DebugMessage(M64MSG_ERROR, "DD Read, sector overrun"); } } /* Make sure motor is still considered active */ dd_dv_active(dd); /* Signal a BM interrupt */ signal_dd_interrupt(dd, DD_STATUS_BM_INT); } void init_dd(struct dd_controller* dd, void* clock, const struct clock_backend_interface* iclock, const uint32_t* rom, size_t rom_size, struct dd_disk* disk, const struct storage_backend_interface* idisk, struct r4300_core* r4300) { dd->rtc.clock = clock; dd->rtc.iclock = iclock; dd->rom = rom; dd->rom_size = rom_size; dd->disk = disk; dd->idisk = idisk; dd->r4300 = r4300; } void poweron_dd(struct dd_controller* dd) { memset(dd->regs, 0, DD_ASIC_REGS_COUNT*sizeof(dd->regs[0])); memset(dd->c2s_buf, 0, 0x400); memset(dd->ds_buf, 0, 0x100); memset(dd->ms_ram, 0, 0x40); dd->bm_write = 0; dd->bm_reset_held = 0; dd->bm_zone = 0; dd->rtc.now = 0; dd->rtc.last_update_rtc = 0; dd->timer_sleep = 1; dd->timer_standby = 3; dd_dv_sleep(dd); dd->regs[DD_ASIC_ID_REG] = 0x00030000; dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_RST_STATE; if (dd->idisk != NULL) { dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_DISK_PRES; if (dd->disk->development) dd->regs[DD_ASIC_ID_REG] = 0x00040000; } } void read_dd_regs(void* opaque, uint32_t address, uint32_t* value) { struct dd_controller* dd = (struct dd_controller*)opaque; if (address < MM_DD_REGS || address >= MM_DD_MS_RAM) { DebugMessage(M64MSG_ERROR, "Unknown access in DD registers MMIO space %08x", address); *value = 0; return; } uint32_t reg = dd_reg(address); /* disk presence test */ if (reg == DD_ASIC_CMD_STATUS) { if (dd->idisk != NULL) { dd->regs[reg] |= DD_STATUS_DISK_PRES; } else { dd->regs[reg] &= ~DD_STATUS_DISK_PRES; } } *value = dd->regs[reg]; DebugMessage(M64MSG_VERBOSE, "DD REG: %08X -> %08x", address, *value); /* post read update. Not part of the returned value */ switch(reg) { case DD_ASIC_CMD_STATUS: { /* acknowledge BM interrupt */ if (dd->regs[DD_ASIC_CMD_STATUS] & DD_STATUS_BM_INT) { clear_dd_interrupt(dd, DD_STATUS_BM_INT); add_interrupt_event(&dd->r4300->cp0, DD_BM_INT, 8020 + (((dd->regs[DD_ASIC_CUR_TK] & 0x0fff0000) >> 16) / 56)); } } break; } } void write_dd_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { unsigned int head, track, old_track, cycles; const uint16_t startTrackZones[9] = { 0x000, 0x09E, 0x13C, 0x1D1, 0x266, 0x2FB, 0x390, 0x425, 0x497 }; struct dd_controller* dd = (struct dd_controller*)opaque; if (address < MM_DD_REGS || address >= MM_DD_MS_RAM) { DebugMessage(M64MSG_ERROR, "Unknown access in DD registers MMIO space %08x", address); return; } uint32_t reg = dd_reg(address); assert(mask == ~UINT32_C(0)); DebugMessage(M64MSG_VERBOSE, "DD REG: %08X <- %08x", address, value); switch (reg) { case DD_ASIC_DATA: dd->regs[DD_ASIC_DATA] = value; break; case DD_ASIC_CMD_STATUS: update_rtc(&dd->rtc); const struct tm* tm = localtime(&dd->rtc.now); /* base cycle count */ cycles = 2000; /* say the drive is busy while processing the command */ dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_BUSY_STATE; switch ((value >> 16) & 0xff) { /* No-op */ case 0x00: break; /* Seek track */ case 0x01: case 0x02: /* base timing cycle count for Seek track CMD */ cycles = 248250; /* check if motor is active or not, if not, add more cycles */ if ((dd->regs[DD_ASIC_CMD_STATUS] & (DD_STATUS_MTR_N_SPIN | DD_STATUS_HEAD_RTRCT)) != 0) { //divided by 100 because F-Zero X Expansion Kit really dislikes anything higher cycles += 501750; } /* make motor active */ dd_dv_active(dd); /* get old track for calculating extra cycles */ old_track = (dd->regs[DD_ASIC_CUR_TK] & 0x0fff0000) >> 16; /* update track */ dd->regs[DD_ASIC_CUR_TK] = dd->regs[DD_ASIC_DATA]; /* lock track */ dd->regs[DD_ASIC_CUR_TK] |= DD_TRACK_LOCK; dd->bm_write = (value >> 17) & 0x1; /* update bm_zone */ head = (dd->regs[DD_ASIC_CUR_TK] & 0x10000000) >> 28; track = (dd->regs[DD_ASIC_CUR_TK] & 0x0fff0000) >> 16; dd->bm_zone = (get_zone_from_head_track(head, track) - head) + 8*head; /* calculate track to track head movement timing */ cycles += 4825 * abs(track - old_track); /* if write seek command, check if the track is writable */ dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_WR_PR_ERR; if (dd->bm_write) { if (track < startTrackZones[(dd->disk_type & 0xf) - head + 3]) { dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_WR_PR_ERR; } } break; /* Rezero / Start (Seek to track 0) */ case 0x03: case 0x05: /* both commands do the exact same thing */ /* base timing cycle count for Seek track CMD */ cycles = 248250; /* check if motor is active or not, if not, add more cycles */ if ((dd->regs[DD_ASIC_CMD_STATUS] & (DD_STATUS_MTR_N_SPIN | DD_STATUS_HEAD_RTRCT)) != 0) { //divided by 100 because F-Zero X Expansion Kit really dislikes anything higher cycles += 501750; } /* make motor active */ dd_dv_active(dd); /* get old track for calculating extra cycles */ old_track = (dd->regs[DD_ASIC_CUR_TK] & 0x0fff0000) >> 16; /* update track to 0 */ dd->regs[DD_ASIC_CUR_TK] = 0; /* lock track */ dd->regs[DD_ASIC_CUR_TK] |= DD_TRACK_LOCK; dd->bm_write = 1; /* update bm_zone */ head = (dd->regs[DD_ASIC_CUR_TK] & 0x10000000) >> 28; track = (dd->regs[DD_ASIC_CUR_TK] & 0x0fff0000) >> 16; dd->bm_zone = (get_zone_from_head_track(head, track) - head) + 8 * head; /* calculate track to track head movement timing */ cycles += 4825 * abs(track - old_track); break; /* Sleep / Brake */ case 0x04: if ((dd->regs[DD_ASIC_CMD_STATUS] & (DD_STATUS_MTR_N_SPIN | DD_STATUS_HEAD_RTRCT)) != 0) { //divided by 100 because F-Zero X Expansion Kit really dislikes anything higher cycles = 207500; } dd_dv_sleep(dd); if (dd->regs[DD_ASIC_DATA] == 0) { DebugMessage(M64MSG_VERBOSE, "Disk drive motor put to sleep mode"); } else { DebugMessage(M64MSG_VERBOSE, "Disk drive motor put to brake mode"); } break; /* Set standby delay */ case 0x06: if ((dd->regs[DD_ASIC_DATA] & 0x01000000) == 0) { dd->timer_standby = (dd->regs[DD_ASIC_DATA] >> 16) & 0xff; DebugMessage(M64MSG_VERBOSE, "Set disk drive standby delay to %u seconds", dd->timer_standby); } else { dd->timer_standby = -1; DebugMessage(M64MSG_VERBOSE, "Disable disk drive standby delay"); } break; /* Set sleep delay */ case 0x07: if ((dd->regs[DD_ASIC_DATA] & 0x01000000) == 0) { dd->timer_sleep = (dd->regs[DD_ASIC_DATA] >> 16) & 0xff; DebugMessage(M64MSG_VERBOSE, "Set disk drive sleep delay to %u seconds", dd->timer_sleep); } else { dd->timer_sleep = -1; DebugMessage(M64MSG_VERBOSE, "Disable disk drive sleep delay"); } break; /* Clear Disk change flag */ case 0x08: dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_DISK_CHNG; break; /* Clear reset flag */ case 0x09: dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_RST_STATE; dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_DISK_CHNG; break; /* Read ASIC version */ case 0x0a: if (dd->regs[DD_ASIC_DATA] == 0) { dd->regs[DD_ASIC_DATA] = 0x01140000; if (dd->disk->development) dd->regs[DD_ASIC_DATA] |= 0x10000000; } else { dd->regs[DD_ASIC_DATA] = 0x53000000; } break; /* Set Disk type */ case 0x0b: dd->disk_type = (dd->regs[DD_ASIC_DATA] >> 16) & 0xf; if (dd->disk_type > 6) { DebugMessage(M64MSG_VERBOSE, "Setting invalid disk type %u, set to fallback disk type 6", dd->disk_type); dd->disk_type = 6; } else { DebugMessage(M64MSG_VERBOSE, "Setting disk type %u", dd->disk_type); } break; /* Request controller status */ case 0x0c: dd->regs[DD_ASIC_DATA] = 0; break; /* Standby */ case 0x0d: if ((dd->regs[DD_ASIC_CMD_STATUS] & (DD_STATUS_MTR_N_SPIN | DD_STATUS_HEAD_RTRCT)) != 0) { //divided by 100 because F-Zero X Expansion Kit really dislikes anything higher cycles = 160000; } dd_dv_standby(dd); DebugMessage(M64MSG_VERBOSE, "Disk drive motor put to standby mode"); break; /* Retry index lock */ case 0x0e: DebugMessage(M64MSG_VERBOSE, "Retry disk track lock"); break; /* Write RTC from ASIC_DATA (BCD format) */ case 0x0f: DebugMessage(M64MSG_VERBOSE, "Write 64DD RTC Year %02x, Month %02x", (dd->regs[DD_ASIC_DATA] & 0xff000000) >> 24, (dd->regs[DD_ASIC_DATA] & 0x00ff0000) >> 16); break; case 0x10: DebugMessage(M64MSG_VERBOSE, "Write 64DD RTC Day %02x, Hour %02x", (dd->regs[DD_ASIC_DATA] & 0xff000000) >> 24, (dd->regs[DD_ASIC_DATA] & 0x00ff0000) >> 16); break; case 0x11: DebugMessage(M64MSG_VERBOSE, "Write 64DD RTC Minute %02x, Second %02x", (dd->regs[DD_ASIC_DATA] & 0xff000000) >> 24, (dd->regs[DD_ASIC_DATA] & 0x00ff0000) >> 16); break; /* Read RTC in ASIC_DATA (BCD format) */ case 0x12: dd->regs[DD_ASIC_DATA] = time2data(tm->tm_year, tm->tm_mon + 1); break; case 0x13: dd->regs[DD_ASIC_DATA] = time2data(tm->tm_mday, tm->tm_hour); break; case 0x14: dd->regs[DD_ASIC_DATA] = time2data(tm->tm_min, tm->tm_sec); break; /* LED On/Off Timing */ case 0x15: DebugMessage(M64MSG_VERBOSE, "LED ON Time %02x, LED OFF Time %02x", (dd->regs[DD_ASIC_DATA] & 0xff000000) >> 24, (dd->regs[DD_ASIC_DATA] & 0x00ff0000) >> 16); break; /* Feature inquiry */ case 0x1b: dd->regs[DD_ASIC_DATA] = 0x00030000; break; default: DebugMessage(M64MSG_WARNING, "DD ASIC CMD not yet implemented (%08x)", value); } /* Signal a MECHA interrupt */ cp0_update_count(dd->r4300); add_interrupt_event(&dd->r4300->cp0, DD_MC_INT, cycles); break; case DD_ASIC_BM_STATUS_CTL: /* set sector */ dd->regs[DD_ASIC_CUR_SECTOR] = (value & 0x00ff0000); if (dd->regs[DD_ASIC_CUR_SECTOR] != 0 && dd->regs[DD_ASIC_CUR_SECTOR] != 0x005a0000) { DebugMessage(M64MSG_ERROR, "Start sector not aligned %08x", dd->regs[DD_ASIC_CUR_SECTOR]); } /* clear MECHA interrupt */ if (value & DD_BM_CTL_MECHA_RST) { dd->regs[DD_ASIC_CMD_STATUS] &= ~DD_STATUS_MECHA_INT; remove_event(&dd->r4300->cp0.q, DD_MC_INT); } /* start block transfer */ if (value & DD_BM_CTL_BLK_TRANS) { dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_BLOCK; } /* handle reset */ if (value & DD_BM_CTL_RESET) { dd->bm_reset_held = 1; } if (!(value & DD_BM_CTL_RESET) && dd->bm_reset_held) { dd->bm_reset_held = 0; dd->regs[DD_ASIC_CMD_STATUS] &= ~(DD_STATUS_DATA_RQ | DD_STATUS_C2_XFER | DD_STATUS_BM_ERR | DD_STATUS_BM_INT); dd->regs[DD_ASIC_BM_STATUS_CTL] = 0; dd->regs[DD_ASIC_CUR_SECTOR] = 0; remove_event(&dd->r4300->cp0.q, DD_BM_INT); } /* clear DD interrupt if both MECHA and BM are cleared */ if ((dd->regs[DD_ASIC_CMD_STATUS] & (DD_STATUS_BM_INT | DD_STATUS_MECHA_INT)) == 0) { clear_dd_interrupt(dd, DD_STATUS_BM_INT); } /* start transfer */ if (value & DD_BM_CTL_START) { if (dd->bm_write && (value & DD_BM_CTL_MNGRMODE)) { DebugMessage(M64MSG_WARNING, "Attempt to write disk with BM mode 1"); } if (!dd->bm_write && !(value & DD_BM_CTL_MNGRMODE)) { DebugMessage(M64MSG_WARNING, "Attempt to read disk with BM mode 0"); } dd->regs[DD_ASIC_BM_STATUS_CTL] |= DD_BM_STATUS_RUNNING; add_interrupt_event(&dd->r4300->cp0, DD_BM_INT, 12500); } break; case DD_ASIC_HARD_RESET: if (value != 0xaaaa0000) { DebugMessage(M64MSG_WARNING, "Unexpected hard reset value %08x", value); } remove_event(&dd->r4300->cp0.q, DD_MC_INT); remove_event(&dd->r4300->cp0.q, DD_BM_INT); dd->regs[DD_ASIC_CMD_STATUS] &= ~(DD_STATUS_DATA_RQ | DD_STATUS_C2_XFER | DD_STATUS_BM_ERR | DD_STATUS_BM_INT | DD_STATUS_BUSY_STATE); dd->regs[DD_ASIC_BM_STATUS_CTL] = 0; dd->regs[DD_ASIC_CUR_SECTOR] = 0; dd->timer_sleep = 1; dd->timer_standby = 3; dd_dv_sleep(dd); clear_dd_interrupt(dd, DD_STATUS_MECHA_INT); dd->regs[DD_ASIC_CMD_STATUS] |= DD_STATUS_RST_STATE; break; case DD_ASIC_HOST_SECBYTE: dd->regs[DD_ASIC_HOST_SECBYTE] = (value >> 16) & 0xff; if ((dd->regs[DD_ASIC_HOST_SECBYTE] + 1) != zone_sec_size[dd->bm_zone]) { DebugMessage(M64MSG_WARNING, "Sector size %u set different than expected %u", dd->regs[DD_ASIC_HOST_SECBYTE] + 1, zone_sec_size[dd->bm_zone]); } break; case DD_ASIC_SEC_BYTE: dd->regs[DD_ASIC_SEC_BYTE] = (value >> 24) & 0xff; if (dd->regs[DD_ASIC_SEC_BYTE] != SECTORS_PER_BLOCK + 4) { DebugMessage(M64MSG_WARNING, "Sectors per block %u set different than expected %u", dd->regs[DD_ASIC_SEC_BYTE] + 1, SECTORS_PER_BLOCK + 4); } break; case DD_ASIC_CUR_TK: /* fallthrough */ case DD_ASIC_CUR_SECTOR: DebugMessage(M64MSG_WARNING, "Trying to write to read-only registers: %08x <- %08x", address, value); break; default: dd->regs[reg] = value; } } void read_dd_rom(void* opaque, uint32_t address, uint32_t* value) { struct dd_controller* dd = (struct dd_controller*)opaque; uint32_t addr = dd_rom_address(address); *value = dd->rom[addr]; DebugMessage(M64MSG_VERBOSE, "DD ROM: %08X -> %08x", address, *value); } void write_dd_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { DebugMessage(M64MSG_VERBOSE, "DD ROM: %08X <- %08x & %08x", address, value, mask); } unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { struct dd_controller* dd = (struct dd_controller*)opaque; uint8_t* mem; size_t i; DebugMessage(M64MSG_VERBOSE, "DD DMA read dram=%08x cart=%08x length=%08x", dram_addr, cart_addr, length); if (cart_addr == MM_DD_DS_BUFFER) { cart_addr = (cart_addr - MM_DD_DS_BUFFER) & 0x3fffff; mem = dd->ds_buf; } else if (cart_addr == MM_DD_MS_RAM) { /* MS is not emulated, we silence warnings for now */ /* Recommended Count Per Op = 1, this seems to break very easily */ return (length * 63) / 25; } else { DebugMessage(M64MSG_ERROR, "Unknown DD dma read dram=%08x cart=%08x length=%08x", dram_addr, cart_addr, length); /* Recommended Count Per Op = 1, this seems to break very easily */ return (length * 63) / 25; } for (i = 0; i < length; ++i) { mem[(cart_addr + i) ^ S8] = dram[(dram_addr + i) ^ S8]; } /* Recommended Count Per Op = 1, this seems to break very easily */ return (length * 63) / 25; } unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length) { struct dd_controller* dd = (struct dd_controller*)opaque; unsigned int cycles; const uint8_t* mem; size_t i; DebugMessage(M64MSG_VERBOSE, "DD DMA write dram=%08x cart=%08x length=%08x", dram_addr, cart_addr, length); if (cart_addr < MM_DD_ROM) { if (cart_addr == MM_DD_C2S_BUFFER) { /* C2 sector buffer */ cart_addr = (cart_addr - MM_DD_C2S_BUFFER); mem = (const uint8_t*)&dd->c2s_buf; } else if (cart_addr == MM_DD_DS_BUFFER) { /* Data sector buffer */ cart_addr = (cart_addr - MM_DD_DS_BUFFER); mem = (const uint8_t*)&dd->ds_buf; } else { DebugMessage(M64MSG_ERROR, "Unknown DD dma write dram=%08x cart=%08x length=%08x", dram_addr, cart_addr, length); /* Recommended Count Per Op = 1, this seems to break very easily */ return (length * 63) / 25; } /* Recommended Count Per Op = 1, this seems to break very easily */ cycles = (length * 63) / 25; } else { /* DD ROM */ cart_addr = (cart_addr - MM_DD_ROM); mem = (const uint8_t*)dd->rom; /* Recommended Count Per Op = 1, this seems to break very easily */ cycles = (length * 63) / 25; } for (i = 0; i < length; ++i) { dram[(dram_addr + i) ^ S8] = mem[(cart_addr + i) ^ S8]; } invalidate_r4300_cached_code(dd->r4300, R4300_KSEG0 + dram_addr, length); invalidate_r4300_cached_code(dd->r4300, R4300_KSEG1 + dram_addr, length); return cycles; } mupen64plus-core-src-2.6.0/src/device/dd/dd_controller.h000066400000000000000000000106541464506436200230740ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dd_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2015 LuigiBlood * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_DD_CONTROLLER_H #define M64P_DEVICE_DD_CONTROLLER_H struct r4300_core; #include #include #include "osal/preproc.h" struct dd_disk; struct clock_backend_interface; struct storage_backend_interface; enum dd_registers { DD_ASIC_DATA, DD_ASIC_MISC_REG, DD_ASIC_CMD_STATUS, DD_ASIC_CUR_TK, DD_ASIC_BM_STATUS_CTL, DD_ASIC_ERR_SECTOR, DD_ASIC_SEQ_STATUS_CTL, DD_ASIC_CUR_SECTOR, DD_ASIC_HARD_RESET, DD_ASIC_C1_S0, DD_ASIC_HOST_SECBYTE, DD_ASIC_C1_S2, DD_ASIC_SEC_BYTE, DD_ASIC_C1_S4, DD_ASIC_C1_S6, DD_ASIC_CUR_ADDR, DD_ASIC_ID_REG, DD_ASIC_TEST_REG, DD_ASIC_TEST_PIN_SEL, DD_ASIC_REGS_COUNT }; struct dd_rtc { time_t now; time_t last_update_rtc; void* clock; const struct clock_backend_interface* iclock; }; struct dd_controller { uint32_t regs[DD_ASIC_REGS_COUNT]; /* 0x500-0x54f: registers */ uint8_t c2s_buf[0x400]; /* 0x000-0x3ff: c2s buffer */ uint8_t ds_buf[0x100]; /* 0x400-0x4ff: data buffer */ uint8_t ms_ram[0x40]; /* 0x580-0x5bf: micro sequencer */ /* drive controller */ unsigned char disk_type; /* [0-6] */ short timer_standby; /* -1 = Disabled, in seconds */ short timer_sleep; /* -1 = Disabled, in seconds */ /* buffer manager */ unsigned char bm_write; /* [0-1] */ unsigned char bm_reset_held; /* [0-1] */ unsigned int bm_zone; /* [0-15] */ /* DD RTC */ struct dd_rtc rtc; /* DD ROM */ const uint32_t* rom; size_t rom_size; /* DD Disk */ struct dd_disk* disk; const struct storage_backend_interface* idisk; struct r4300_core* r4300; }; static osal_inline uint32_t dd_reg(uint32_t address) { return (address & 0xff) >> 2; } static osal_inline uint32_t dd_rom_address(uint32_t address) { return (address & 0x3fffff) >> 2; } void init_dd(struct dd_controller* dd, void* clock, const struct clock_backend_interface* iclock, const uint32_t* rom, size_t rom_size, struct dd_disk* disk, const struct storage_backend_interface* idisk, struct r4300_core* r4300); void poweron_dd(struct dd_controller* dd); void read_dd_regs(void* opaque, uint32_t address, uint32_t* value); void write_dd_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void read_dd_rom(void* opaque, uint32_t address, uint32_t* value); void write_dd_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask); unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); void dd_update_bm(void* opaque); void dd_mecha_int_handler(void* opaque); void dd_bm_int_handler(void* opaque); void dd_dv_int_handler(void* opaque); #endif mupen64plus-core-src-2.6.0/src/device/dd/disk.c000066400000000000000000000502541464506436200211670ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - disk.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2020 LuigiBlood * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "disk.h" #define M64P_CORE_PROTOTYPES 1 #include "api/m64p_types.h" #include "api/callbacks.h" #include "backends/api/storage_backend.h" #include "main/util.h" static uint8_t* storage_disk_data(const void* storage) { const struct dd_disk* disk = (struct dd_disk*)storage; return disk->istorage->data(disk->storage); } static size_t storage_disk_size(const void* storage) { const struct dd_disk* disk = (struct dd_disk*)storage; return disk->istorage->size(disk->storage); } static void storage_disk_save_dummy(void* storage, size_t start, size_t size) { /* do nothing */ } static void storage_disk_save_full(void* storage, size_t start, size_t size) { struct dd_disk* disk = (struct dd_disk*)storage; disk->isave_storage->save(disk->save_storage, start, size); } static void storage_disk_save_ram_only(void* storage, size_t start, size_t size) { struct dd_disk* disk = (struct dd_disk*)storage; /* check range and translate start address before calling save */ if (start >= disk->offset_ram) { start -= disk->offset_ram; if ((start + size) <= disk->isave_storage->size(disk->save_storage)) { disk->isave_storage->save(disk->save_storage, start, size); } } } const struct storage_backend_interface g_istorage_disk_read_only = { storage_disk_data, storage_disk_size, storage_disk_save_dummy }; const struct storage_backend_interface g_istorage_disk_full = { storage_disk_data, storage_disk_size, storage_disk_save_full }; const struct storage_backend_interface g_istorage_disk_ram_only = { storage_disk_data, storage_disk_size, storage_disk_save_ram_only }; /* Disk Helper routines */ void GenerateLBAToPhysTable(struct dd_disk* disk) { //For SDK and D64 formats if (disk->format == DISK_FORMAT_MAME) return; const struct dd_sys_data* sys_data = (void*)(disk->istorage->data(disk->storage) + disk->offset_sys); for (uint32_t lba = 0; lba < SIZE_LBA; lba++) { disk->lba_phys_table[lba] = LBAToPhys(sys_data, lba); } } uint32_t LBAToVZone(const struct dd_sys_data* sys_data, uint32_t lba) { return LBAToVZoneA(sys_data->type, lba); } uint32_t LBAToVZoneA(uint8_t type, uint32_t lba) { for (uint32_t vzone = 0; vzone < 16; vzone++) { if (lba < VZoneLBATable[type & 0x0F][vzone]) { return vzone; } } return -1; } uint32_t LBAToByte(const struct dd_sys_data* sys_data, uint32_t lba, uint32_t nlbas) { return LBAToByteA(sys_data->type, lba, nlbas); } uint32_t LBAToByteA(uint8_t type, uint32_t lba, uint32_t nlbas) { uint8_t init_flag = 1; uint32_t totalbytes = 0; uint32_t blocksize = 0; uint32_t vzone = 0; uint32_t pzone = 0; uint8_t disktype = type & 0x0F; if (nlbas != 0) { for (; nlbas != 0; nlbas--) { if ((init_flag == 1) || (VZoneLBATable[disktype][vzone] == lba)) { vzone = LBAToVZoneA(type, lba); pzone = VZoneToPZone(vzone, disktype); if (7 < pzone) { pzone -= 7; } blocksize = zone_sec_size_phys[pzone] * SECTORS_PER_BLOCK; } totalbytes += blocksize; lba++; init_flag = 0; if (((nlbas - 1) != 0) && (lba > MAX_LBA)) { return 0xFFFFFFFF; } } } return totalbytes; } uint16_t LBAToPhys(const struct dd_sys_data* sys_data, uint32_t lba) { uint8_t disktype = sys_data->type & 0x0F; const uint16_t OUTERCYL_TBL[8] = { 0x000, 0x09E, 0x13C, 0x1D1, 0x266, 0x2FB, 0x390, 0x425 }; //Get Block 0/1 on Disk Track uint8_t block = 1; if (((lba & 3) == 0) || ((lba & 3) == 3)) block = 0; //Get Virtual & Physical Disk Zones uint16_t vzone = LBAToVZone(sys_data, lba); uint16_t pzone = VZoneToPZone(vzone, disktype); //Get Disk Head uint16_t head = (7 < pzone); //Get Disk Zone uint16_t disk_zone = pzone; if (disk_zone != 0) disk_zone = pzone - 7; //Get Virtual Zone LBA start, if Zone 0, it's LBA 0 uint16_t vzone_lba = 0; if (vzone != 0) vzone_lba = VZoneLBATable[disktype][vzone - 1]; //Calculate Physical Track uint16_t track = (lba - vzone_lba) >> 1; //Get the start track from current zone uint16_t track_zone_start = TrackZoneTable[0][pzone]; if (head != 0) { //If Head 1, count from the other way around track = -track; track_zone_start = OUTERCYL_TBL[disk_zone - 1]; } track += TrackZoneTable[0][pzone]; //Get the relative offset to defect tracks for the current zone (if Zone 0, then it's 0) uint16_t defect_offset = 0; if (pzone != 0) defect_offset = sys_data->defect_offset[pzone - 1]; //Get amount of defect tracks for the current zone uint16_t defect_amount = sys_data->defect_offset[pzone] - defect_offset; //Skip defect tracks while ((defect_amount != 0) && ((sys_data->defect_info[defect_offset] + track_zone_start) <= track)) { track++; defect_offset++; defect_amount--; } return track | (head * 0x1000) | (block * 0x2000); } uint32_t PhysToLBA(const struct dd_disk* disk, uint16_t head, uint16_t track, uint16_t block) { uint16_t expectedvalue = track | (head * 0x1000) | (block * 0x2000); for (uint16_t lba = 0; lba < SIZE_LBA; lba++) { if (disk->lba_phys_table[lba] == expectedvalue) { return lba; } } return 0xFFFF; } unsigned int get_zone_from_head_track(unsigned int head, unsigned int track) { unsigned int zone; for (zone = 7; zone > 0; --zone) { if (track >= TrackZoneTable[0][zone]) { break; } } return zone + head; } static uint8_t* get_sector_base_mame(const struct dd_disk* disk, unsigned int head, unsigned int track, unsigned int block, unsigned int sector) { static const unsigned int start_offset[] = { 0x0000000, 0x05f15e0, 0x0b79d00, 0x10801a0, 0x1523720, 0x1963d80, 0x1d414c0, 0x20bbce0, 0x23196e0, 0x28a1e00, 0x2df5dc0, 0x3299340, 0x36d99a0, 0x3ab70e0, 0x3e31900, 0x4149200 }; unsigned int zone = get_zone_from_head_track(head, track); /* Development disk have 0xC0 sector size for head == 0 && track < 6, * in all other cases use default sector size based on zone */ unsigned int sector_size = (disk->development && head == 0 && track < 6) ? 0xC0 : zone_sec_size_phys[zone]; /* For the sake of tr_off computation we need zone - head */ zone = zone - head; unsigned int tr_off = track - TrackZoneTable[0][zone]; /* For start_offsets and all other macros we want (zone + head * 8) */ zone += head * 8; /* compute sector offset */ unsigned int offset = start_offset[zone] + tr_off * TRACKSIZE(zone) + block * BLOCKSIZE(zone) + sector * sector_size; /* Access to protected LBA should return an error */ if (sector == 0 && track < (SYSTEM_LBAS / 2)) { uint16_t lblock = offset / BLOCKSIZE(0); uint16_t lblock_sys = disk->offset_sys / BLOCKSIZE(0); uint16_t lblock_id = disk->offset_id / BLOCKSIZE(0); if ((lblock < PROTECT_LBA && lblock != lblock_sys) || (lblock > PROTECT_LBA && lblock < (DISKID_LBA + 2) && lblock != lblock_id)) { return NULL; } } return disk->istorage->data(disk->storage) + offset; } static uint8_t* get_sector_base_sdk(const struct dd_disk* disk, unsigned int head, unsigned int track, unsigned int block, unsigned int sector) { uint16_t lba = PhysToLBA(disk, head, track, block); if (lba > MAX_LBA) { DebugMessage(M64MSG_ERROR, "Invalid LBA (Head:%d - Track:%04x - Block:%d)", head, track, block); return NULL; } /* Development disk have 0xC0 sector size for head == 0 && track < 6, * in all other cases use default sector size based on zone */ unsigned int sector_size = (disk->development && head == 0 && track < 6) ? 0xC0 : zone_sec_size_phys[get_zone_from_head_track(head, track)]; const struct dd_sys_data* sys_data = (void*)(disk->istorage->data(disk->storage) + disk->offset_sys); unsigned int offset = LBAToByte(sys_data, 0, lba) + sector * sector_size; /* Handle Errors for wrong System Data */ if (sector == 0 && lba < SYSTEM_LBAS) { uint16_t lblock = offset / BLOCKSIZE(0); uint16_t lblock_sys = disk->offset_sys / BLOCKSIZE(0); uint16_t lblock_id = disk->offset_id / BLOCKSIZE(0); if ((lblock < PROTECT_LBA && lblock != lblock_sys) || (lblock > PROTECT_LBA && lblock < (DISKID_LBA + 2) && lblock != lblock_id)) { return NULL; } } if (lba <= MAX_LBA && sector == 0) DebugMessage(M64MSG_VERBOSE, "LBA %d - Offset %08X - Size %04X", lba, offset, sector_size * SECTORS_PER_BLOCK); return disk->istorage->data(disk->storage) + offset; } static uint8_t* get_sector_base_d64(const struct dd_disk* disk, unsigned int head, unsigned int track, unsigned int block, unsigned int sector) { const struct dd_sys_data* sys_data = (void*)(disk->istorage->data(disk->storage) + disk->offset_sys); uint16_t rom_lba_end = big16(sys_data->rom_lba_end); uint16_t ram_lba_start = big16(sys_data->ram_lba_start); uint16_t ram_lba_end = big16(sys_data->ram_lba_end); uint8_t disk_type = sys_data->type & 0x0F; unsigned int sector_size = zone_sec_size_phys[get_zone_from_head_track(head, track)]; uint16_t lba = PhysToLBA(disk, head, track, block); unsigned int offset = 0; if (lba < DISKID_LBA) { //System Data offset = disk->offset_sys; } else if ((lba >= DISKID_LBA) && (lba < SYSTEM_LBAS)) { //Disk ID offset = disk->offset_id; } else if (lba <= (rom_lba_end + SYSTEM_LBAS)) { //ROM Area offset = D64_OFFSET_DATA + LBAToByteA(disk_type, SYSTEM_LBAS, lba - SYSTEM_LBAS) + (sector * sector_size); } else if (((lba - SYSTEM_LBAS) >= ram_lba_start) && ((lba - SYSTEM_LBAS) <= ram_lba_end)) { //RAM Area offset = disk->offset_ram + LBAToByteA(disk_type, ram_lba_start + SYSTEM_LBAS, lba - SYSTEM_LBAS - ram_lba_start) + (sector * sector_size); } else { //Invalid DebugMessage(M64MSG_ERROR, "Invalid LBA (Head:%d - Track:%04x - Block:%d)", head, track, block); return NULL; } if (lba <= MAX_LBA && sector == 0) DebugMessage(M64MSG_VERBOSE, "LBA %d - Offset %08X - Size %04X", lba, offset, sector_size * SECTORS_PER_BLOCK); return disk->istorage->data(disk->storage) + offset; } uint8_t* get_sector_base(const struct dd_disk* disk, unsigned int head, unsigned int track, unsigned int block, unsigned int sector) { switch(disk->format) { case DISK_FORMAT_MAME: return get_sector_base_mame(disk, head, track, block, sector); case DISK_FORMAT_SDK: return get_sector_base_sdk(disk, head, track, block, sector); case DISK_FORMAT_D64: return get_sector_base_d64(disk, head, track, block, sector); default: return NULL; } } uint8_t* scan_and_expand_disk_format(uint8_t* data, size_t size, unsigned int* format, unsigned int* development, size_t* offset_sys, size_t* offset_id, size_t* offset_ram, size_t* size_ram) { /* Search for good System Data */ const unsigned int blocks[8] = { 0, 1, 2, 3, 8, 9, 10, 11 }; int isValidDisk = -1; int isValidDiskID = -1; unsigned int isDevelopment = 0; for (int i = 0; i < 8; i++) { uint32_t offset = BLOCKSIZE(0) * blocks[i]; const struct dd_sys_data* sys_data = (void*)(&data[offset]); if ((offset + 0x20) >= size || (size < MAME_FORMAT_DUMP_SIZE && size < SDK_FORMAT_DUMP_SIZE && i > 0)) { isValidDisk = -1; break; } //Disk Type if ((sys_data->type & 0xEF) > 6) continue; //IPL Load Block uint16_t ipl_load_blk = big16(sys_data->ipl_load_blk); if (ipl_load_blk > (MAX_LBA - SYSTEM_LBAS) || ipl_load_blk == 0x0000) continue; //IPL Load Address uint32_t ipl_load_addr = big32(sys_data->ipl_load_addr); if (ipl_load_addr < 0x80000000 && ipl_load_addr >= 0x80800000) continue; //Country Code uint32_t disk_region = big32(sys_data->region); switch (disk_region) { case DD_REGION_JP: case DD_REGION_US: case DD_REGION_DV: isValidDisk = i; break; default: continue; } //Verify if sector repeats if (size == MAME_FORMAT_DUMP_SIZE || size == SDK_FORMAT_DUMP_SIZE) { uint8_t sectorsize = SECTORSIZE_SYS; //Development System Data if (blocks[i] == 2 || blocks[i] == 3 || blocks[i] == 10 || blocks[i] == 11) sectorsize = SECTORSIZE_SYS_DEV; for (int j = 1; j < SECTORS_PER_BLOCK; j++) { if (memcmp(&data[offset + ((j - 1) * sectorsize)], &data[offset + (j * sectorsize)], sectorsize) != 0) { isValidDisk = -1; break; } else { isValidDisk = i; } } } if (isValidDisk != -1) break; } if (isValidDisk == 2 || isValidDisk == 3 || isValidDisk == 10 || isValidDisk == 11) isDevelopment = 1; if (isValidDisk == -1) { DebugMessage(M64MSG_ERROR, "Invalid DD Disk System Data."); return NULL; } const uint16_t RAM_START_LBA[7] = { 0x5A2, 0x7C6, 0x9EA, 0xC0E, 0xE32, 0x1010, 0x10DC }; const uint32_t RAM_SIZES[7] = { 0x24A9DC0, 0x1C226C0, 0x1450F00, 0xD35680, 0x6CFD40, 0x1DA240, 0x0 }; if (size == MAME_FORMAT_DUMP_SIZE || size == SDK_FORMAT_DUMP_SIZE) { //Check Disk ID //Verify if sector repeats for (int i = 14; i < 16; i++) { for (int j = 1; j < SECTORS_PER_BLOCK; j++) { if (memcmp(&data[(i * BLOCKSIZE(0)) + (j - 1) * SECTORSIZE_SYS], &data[(i * BLOCKSIZE(0)) + j * SECTORSIZE_SYS], SECTORSIZE_SYS) != 0) { isValidDiskID = -1; break; } else { isValidDiskID = i; } } if (isValidDiskID != -1) break; } if (isValidDiskID == -1) { DebugMessage(M64MSG_ERROR, "Invalid DD Disk ID Data."); return NULL; } } else { //Check D64 File Size const struct dd_sys_data* sys_data = (void*)(&data[D64_OFFSET_SYS]); uint16_t rom_lba_end = big16(sys_data->rom_lba_end); uint16_t ram_lba_start = big16(sys_data->ram_lba_start); uint16_t ram_lba_end = big16(sys_data->ram_lba_end); uint8_t disk_type = sys_data->type & 0x0F; size_t rom_size = LBAToByteA(disk_type, 24, rom_lba_end + 1); size_t ram_size = 0; if (ram_lba_start != 0xFFFF && ram_lba_end != 0xFFFF) ram_size = LBAToByteA(disk_type, SYSTEM_LBAS + ram_lba_start, ram_lba_end + 1 - ram_lba_start); size_t d64_size = D64_OFFSET_DATA + rom_size + ram_size; size_t full_d64_size = D64_OFFSET_DATA + rom_size + RAM_SIZES[disk_type]; DebugMessage(M64MSG_INFO, "D64 Disk Areas - ROM: 0000 - %04X / RAM: %04X - %04X", rom_lba_end, ram_lba_start, ram_lba_end); if (ram_lba_start != (RAM_START_LBA[disk_type] - 24) && ram_lba_start != 0xFFFF) { isValidDisk = -1; DebugMessage(M64MSG_ERROR, "Invalid D64 Disk RAM Start Info (expected %04X)", (RAM_START_LBA[disk_type] - SYSTEM_LBAS)); } else if (size != d64_size) { isValidDisk = -1; DebugMessage(M64MSG_ERROR, "Invalid D64 Disk size %zu (calculated 0x200 + 0x%zx + 0x%zx = %zu).", size, rom_size, ram_size, d64_size); } else { //Change Size to fit all of RAM Area possible uint8_t* buffer = malloc(full_d64_size); if (buffer == NULL) { DebugMessage(M64MSG_ERROR, "Failed to allocate memory for D64 disk dump"); return NULL; } memset(buffer, 0, full_d64_size); memcpy(buffer, data, d64_size); struct dd_sys_data* sys_data_ = (void*)(&buffer[D64_OFFSET_SYS]); //Modify System Data so there are no errors in emulation sys_data_->format = 0x10; sys_data_->type |= 0x10; if (disk_type < 6) { sys_data_->ram_lba_start = big16((RAM_START_LBA[disk_type] - SYSTEM_LBAS)); sys_data_->ram_lba_end = big16(MAX_LBA - SYSTEM_LBAS); } else { sys_data_->ram_lba_start = 0xFFFF; sys_data_->ram_lba_end = 0xFFFF; } /* FIXME: you're not supposed to know that data was malloc'ed */ free(data); data = buffer; size = full_d64_size; } } switch (size) { case MAME_FORMAT_DUMP_SIZE: *format = DISK_FORMAT_MAME; *development = isDevelopment; *offset_sys = 0x4D08 * isValidDisk; *offset_id = 0x4D08 * isValidDiskID; break; case SDK_FORMAT_DUMP_SIZE: { *format = DISK_FORMAT_SDK; *development = isDevelopment; *offset_sys = 0x4D08 * isValidDisk; *offset_id = 0x4D08 * isValidDiskID; const struct dd_sys_data* sys_data = (void*)(&data[*offset_sys]); *offset_ram = LBAToByteA(sys_data->type & 0xF, 0, RAM_START_LBA[sys_data->type & 0xF]); *size_ram = RAM_SIZES[sys_data->type & 0xF]; } break; default: if (isValidDisk == -1) { DebugMessage(M64MSG_ERROR, "Invalid DD Disk size %zu.", size); return NULL; } else { //D64 *format = DISK_FORMAT_D64; *development = 1; *offset_sys = 0x000; *offset_id = 0x100; const struct dd_sys_data* sys_data = (void*)(&data[*offset_sys]); *offset_ram = D64_OFFSET_DATA + LBAToByteA(sys_data->type & 0xF, 24, big16(sys_data->rom_lba_end) + 1); *size_ram = RAM_SIZES[sys_data->type & 0xF]; } } return data; } const char* get_disk_format_name(unsigned int format) { switch(format) { case DISK_FORMAT_MAME: return "MAME"; case DISK_FORMAT_SDK: return "SDK"; case DISK_FORMAT_D64: return "D64"; default: return ""; } } mupen64plus-core-src-2.6.0/src/device/dd/disk.h000066400000000000000000000172771464506436200212040ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - disk.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2020 LuigiBlood * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_DISK_H #define M64P_DEVICE_DISK_H #include #include struct storage_backend_interface; /* Disk format sizes */ #define MAME_FORMAT_DUMP_SIZE 0x0435b0c0 #define SDK_FORMAT_DUMP_SIZE 0x03dec800 #define DD_REGION_JP UINT32_C(0xe848d316) #define DD_REGION_US UINT32_C(0x2263ee56) #define DD_REGION_DV UINT32_C(0x00000000) #define DISK_FORMAT_MAME 0 #define DISK_FORMAT_SDK 1 #define DISK_FORMAT_D64 2 /* System Data struct */ struct dd_sys_data { uint32_t region; uint8_t format; uint8_t type; uint16_t ipl_load_blk; uint8_t defect_offset[16]; uint32_t dummy; uint32_t ipl_load_addr; uint8_t defect_info[192]; uint16_t rom_lba_end; uint16_t ram_lba_start; uint16_t ram_lba_end; uint16_t dummy2; }; /* D64 */ #define D64_OFFSET_SYS 0x000 #define D64_OFFSET_ID 0x100 #define D64_OFFSET_DATA 0x200 /* disk geometry definitions */ enum { SECTORS_PER_BLOCK = 85 }; enum { BLOCKS_PER_TRACK = 2 }; enum { DD_DISK_SYSTEM_DATA_SIZE = 0xe8 }; static const unsigned int zone_sec_size[16] = { 232, 216, 208, 192, 176, 160, 144, 128, 216, 208, 192, 176, 160, 144, 128, 112 }; static const unsigned int zone_sec_size_phys[9] = { 232, 216, 208, 192, 176, 160, 144, 128, 112 }; static const uint32_t ZoneTracks[16] = { 158, 158, 149, 149, 149, 149, 149, 114, 158, 158, 149, 149, 149, 149, 149, 114 }; static const uint32_t DiskTypeZones[7][16] = { { 0, 1, 2, 9, 8, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10 }, { 0, 1, 2, 3, 10, 9, 8, 4, 5, 6, 7, 15, 14, 13, 12, 11 }, { 0, 1, 2, 3, 4, 11, 10, 9, 8, 5, 6, 7, 15, 14, 13, 12 }, { 0, 1, 2, 3, 4, 5, 12, 11, 10, 9, 8, 6, 7, 15, 14, 13 }, { 0, 1, 2, 3, 4, 5, 6, 13, 12, 11, 10, 9, 8, 7, 15, 14 }, { 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8, 15 }, { 0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8 } }; static const uint32_t RevDiskTypeZones[7][16] = { { 0, 1, 2, 5, 6, 7, 8, 9, 4, 3, 15, 14, 13, 12, 11, 10 }, { 0, 1, 2, 3, 7, 8, 9, 10, 6, 5, 4, 15, 14, 13, 12, 11 }, { 0, 1, 2, 3, 4, 9, 10, 11, 8, 7, 6, 5, 15, 14, 13, 12 }, { 0, 1, 2, 3, 4, 5, 11, 12, 10, 9, 8, 7, 6, 15, 14, 13 }, { 0, 1, 2, 3, 4, 5, 6, 13, 12, 11, 10, 9, 8, 7, 15, 14 }, { 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8, 15 }, { 0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8 } }; static const uint32_t StartBlock[7][16] = { { 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1 }, { 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 }, { 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1 }, { 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1 } }; static const uint16_t VZoneLBATable[7][16] = { {0x0124, 0x0248, 0x035A, 0x047E, 0x05A2, 0x06B4, 0x07C6, 0x08D8, 0x09EA, 0x0AB6, 0x0B82, 0x0C94, 0x0DA6, 0x0EB8, 0x0FCA, 0x10DC}, {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x06A2, 0x07C6, 0x08D8, 0x09EA, 0x0AFC, 0x0BC8, 0x0C94, 0x0DA6, 0x0EB8, 0x0FCA, 0x10DC}, {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x08C6, 0x09EA, 0x0AFC, 0x0C0E, 0x0CDA, 0x0DA6, 0x0EB8, 0x0FCA, 0x10DC}, {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x08B4, 0x09C6, 0x0AEA, 0x0C0E, 0x0D20, 0x0DEC, 0x0EB8, 0x0FCA, 0x10DC}, {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x08B4, 0x09C6, 0x0AD8, 0x0BEA, 0x0D0E, 0x0E32, 0x0EFE, 0x0FCA, 0x10DC}, {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x086E, 0x0980, 0x0A92, 0x0BA4, 0x0CB6, 0x0DC8, 0x0EEC, 0x1010, 0x10DC}, {0x0124, 0x0248, 0x035A, 0x046C, 0x057E, 0x0690, 0x07A2, 0x086E, 0x093A, 0x0A4C, 0x0B5E, 0x0C70, 0x0D82, 0x0E94, 0x0FB8, 0x10DC} }; static const uint16_t TrackZoneTable[2][8] = { {0x000, 0x09E, 0x13C, 0x1D1, 0x266, 0x2FB, 0x390, 0x425}, {0x091, 0x12F, 0x1C4, 0x259, 0x2EE, 0x383, 0x418, 0x48A} }; #define SECTORSIZE(_zone) zone_sec_size[_zone] #define BLOCKSIZE(_zone) SECTORSIZE(_zone) * SECTORS_PER_BLOCK #define TRACKSIZE(_zone) BLOCKSIZE(_zone) * BLOCKS_PER_TRACK #define ZONESIZE(_zone) TRACKSIZE(_zone) * ZoneTracks[_zone] #define VZONESIZE(_zone) TRACKSIZE(_zone) * (ZoneTracks[_zone] - 0xC) #define VZoneToPZone(x, y) DiskTypeZones[y][x] #define MAX_LBA 0x10DB #define SIZE_LBA MAX_LBA+1 #define SYSTEM_LBAS 24 #define DISKID_LBA 14 #define PROTECT_LBA 12 #define SECTORSIZE_SYS SECTORSIZE(0) #define SECTORSIZE_SYS_DEV SECTORSIZE(3) struct dd_disk { /* Full storage - read only */ void* storage; const struct storage_backend_interface* istorage; /* Storage that will be saved - may be a subset of full storage */ void* save_storage; const struct storage_backend_interface* isave_storage; uint16_t lba_phys_table[0x10DC]; uint8_t format; uint8_t development; uint8_t region; size_t offset_sys; size_t offset_id; size_t offset_ram; }; /* Storage interface which handles the various 64DD disks format specificities */ extern const struct storage_backend_interface g_istorage_disk_read_only; extern const struct storage_backend_interface g_istorage_disk_full; extern const struct storage_backend_interface g_istorage_disk_ram_only; /* Disk Helper routines */ void GenerateLBAToPhysTable(struct dd_disk* disk); uint32_t LBAToVZone(const struct dd_sys_data* sys_data, uint32_t lba); uint32_t LBAToVZoneA(uint8_t type, uint32_t lba); uint32_t LBAToByte(const struct dd_sys_data* sys_data, uint32_t lba, uint32_t nlbas); uint32_t LBAToByteA(uint8_t type, uint32_t lba, uint32_t nlbas); uint16_t LBAToPhys(const struct dd_sys_data* sys_data, uint32_t lba); uint32_t PhysToLBA(const struct dd_disk* disk, uint16_t head, uint16_t track, uint16_t block); unsigned int get_zone_from_head_track(unsigned int head, unsigned int track); uint8_t* get_sector_base(const struct dd_disk* disk, unsigned int head, unsigned int track, unsigned int block, unsigned int sector); uint8_t* scan_and_expand_disk_format(uint8_t* data, size_t size, unsigned int* format, unsigned int* development, size_t* offset_sys, size_t* offset_id, size_t* offset_ram, size_t* size_ram); const char* get_disk_format_name(unsigned int format); #endif mupen64plus-core-src-2.6.0/src/device/device.c000066400000000000000000000262131464506436200211030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - device.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "device.h" #include "memory/memory.h" #include "pif/pif.h" #include "r4300/r4300_core.h" #include "rcp/ai/ai_controller.h" #include "rcp/mi/mi_controller.h" #include "rcp/pi/pi_controller.h" #include "rcp/rdp/rdp_core.h" #include "rcp/ri/ri_controller.h" #include "rcp/rsp/rsp_core.h" #include "rcp/si/si_controller.h" #include "rcp/vi/vi_controller.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) static void read_open_bus(void* opaque, uint32_t address, uint32_t* value) { *value = (address & 0xffff); *value |= (*value << 16); } static void write_open_bus(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { } static void get_pi_dma_handler(struct cart* cart, struct dd_controller* dd, uint32_t address, void** opaque, const struct pi_dma_handler** handler) { #define RW(o, x) \ do { \ static const struct pi_dma_handler h = { x ## _dma_read, x ## _dma_write }; \ *opaque = (o); \ *handler = &h; \ } while(0) if (address >= MM_CART_ROM) { if (address >= MM_CART_DOM3) { /* 0x1fd00000 - 0x7fffffff : dom3 addr2, cart rom (Paper Mario (U)) ??? */ RW(cart, cart_dom3); } else { /* 0x10000000 - 0x1fbfffff : dom1 addr2, cart rom */ RW(&cart->cart_rom, cart_rom); } } else if (address >= MM_DOM2_ADDR2) { /* 0x08000000 - 0x0fffffff : dom2 addr2, cart save */ RW(cart, cart_dom2); } else if (address >= MM_DOM2_ADDR1) { /* 0x05000000 - 0x05ffffff : dom2 addr1, dd buffers */ /* 0x06000000 - 0x07ffffff : dom1 addr1, dd rom */ RW(dd, dd_dom); } #undef RW } void init_device(struct device* dev, /* memory */ void* base, /* r4300 */ unsigned int emumode, unsigned int count_per_op, unsigned int count_per_op_denom_pot, int no_compiled_jump, int randomize_interrupt, uint32_t start_address, /* ai */ void* aout, const struct audio_out_backend_interface* iaout, float dma_modifier, /* si */ unsigned int si_dma_duration, /* rdram */ size_t dram_size, /* pif */ void* jbds[PIF_CHANNELS_COUNT], const struct joybus_device_interface* ijbds[PIF_CHANNELS_COUNT], /* vi */ unsigned int vi_clock, unsigned int expected_refresh_rate, /* cart */ void* af_rtc_clock, const struct clock_backend_interface* iaf_rtc_clock, size_t rom_size, uint16_t eeprom_type, void* eeprom_storage, const struct storage_backend_interface* ieeprom_storage, uint32_t flashram_type, void* flashram_storage, const struct storage_backend_interface* iflashram_storage, void* sram_storage, const struct storage_backend_interface* isram_storage, /* dd */ void* dd_rtc_clock, const struct clock_backend_interface* dd_rtc_iclock, size_t dd_rom_size, void* dd_disk, const struct storage_backend_interface* dd_idisk) { struct interrupt_handler interrupt_handlers[] = { { &dev->vi, vi_vertical_interrupt_event }, /* VI */ { &dev->r4300, compare_int_handler }, /* COMPARE */ { &dev->r4300, check_int_handler }, /* CHECK */ { &dev->si, si_end_of_dma_event }, /* SI */ { &dev->pi, pi_end_of_dma_event }, /* PI */ { &dev->r4300.cp0, special_int_handler }, /* SPECIAL */ { &dev->ai, ai_end_of_dma_event }, /* AI */ { &dev->sp, rsp_interrupt_event }, /* SP */ { &dev->dp, rdp_interrupt_event }, /* DP */ { &dev->pif, hw2_int_handler }, /* HW2 */ { dev, nmi_int_handler }, /* NMI */ { dev, reset_hard_handler }, /* reset_hard */ { &dev->sp, rsp_end_of_dma_event }, { &dev->dd, dd_mecha_int_handler }, /* DD MECHA */ { &dev->dd, dd_bm_int_handler }, /* DD BM */ { &dev->dd, dd_dv_int_handler }, /* DD DRIVE */ }; #define R(x) read_ ## x #define W(x) write_ ## x #define RW(x) R(x), W(x) #define A(x,m) (x), (x) | (m) struct mem_mapping mappings[] = { /* clear mappings */ { 0x00000000, 0xffffffff, M64P_MEM_NOTHING, { NULL, RW(open_bus) } }, /* memory map */ { A(MM_RDRAM_DRAM, 0x3efffff), M64P_MEM_RDRAM, { &dev->rdram, RW(rdram_dram) } }, { A(MM_RDRAM_REGS, 0xfffff), M64P_MEM_RDRAMREG, { &dev->rdram, RW(rdram_regs) } }, { A(MM_RSP_MEM, 0xffff), M64P_MEM_RSPMEM, { &dev->sp, RW(rsp_mem) } }, { A(MM_RSP_REGS, 0xffff), M64P_MEM_RSPREG, { &dev->sp, RW(rsp_regs) } }, { A(MM_RSP_REGS2, 0xffff), M64P_MEM_RSP, { &dev->sp, RW(rsp_regs2) } }, { A(MM_DPC_REGS, 0xffff), M64P_MEM_DP, { &dev->dp, RW(dpc_regs) } }, { A(MM_DPS_REGS, 0xffff), M64P_MEM_DPS, { &dev->dp, RW(dps_regs) } }, { A(MM_MI_REGS, 0xffff), M64P_MEM_MI, { &dev->mi, RW(mi_regs) } }, { A(MM_VI_REGS, 0xffff), M64P_MEM_VI, { &dev->vi, RW(vi_regs) } }, { A(MM_AI_REGS, 0xffff), M64P_MEM_AI, { &dev->ai, RW(ai_regs) } }, { A(MM_PI_REGS, 0xffff), M64P_MEM_PI, { &dev->pi, RW(pi_regs) } }, { A(MM_RI_REGS, 0xffff), M64P_MEM_RI, { &dev->ri, RW(ri_regs) } }, { A(MM_SI_REGS, 0xffff), M64P_MEM_SI, { &dev->si, RW(si_regs) } }, { A(MM_DOM2_ADDR1, 0xffffff), M64P_MEM_NOTHING, { NULL, RW(open_bus) } }, { A(MM_DD_ROM, 0x1ffffff), M64P_MEM_NOTHING, { NULL, RW(open_bus) } }, { A(MM_DOM2_ADDR2, 0x1ffff), M64P_MEM_FLASHRAMSTAT, { &dev->cart, RW(cart_dom2) } }, { A(MM_IS_VIEWER, 0xfff), M64P_MEM_NOTHING, { &dev->is, RW(is_viewer) } }, { A(MM_CART_ROM, rom_size-1), M64P_MEM_ROM, { &dev->cart.cart_rom, RW(cart_rom) } }, { A(MM_PIF_MEM, 0xffff), M64P_MEM_PIF, { &dev->pif, RW(pif_mem) } } }; /* init and map DD if present */ if (dd_rom_size > 0) { mappings[14] = (struct mem_mapping){ A(MM_DOM2_ADDR1, 0xffffff), M64P_MEM_NOTHING, { &dev->dd, RW(dd_regs) } }; mappings[15] = (struct mem_mapping){ A(MM_DD_ROM, dd_rom_size-1), M64P_MEM_NOTHING, { &dev->dd, RW(dd_rom) } }; init_dd(&dev->dd, dd_rtc_clock, dd_rtc_iclock, mem_base_u32(base, MM_DD_ROM), dd_rom_size, dd_disk, dd_idisk, &dev->r4300); } struct mem_handler dbg_handler = { &dev->r4300, RW(with_bp_checks) }; #undef A #undef R #undef W #undef RW init_memory(&dev->mem, mappings, ARRAY_SIZE(mappings), base, &dbg_handler); init_rdram(&dev->rdram, mem_base_u32(base, MM_RDRAM_DRAM), dram_size, &dev->r4300); init_r4300(&dev->r4300, &dev->mem, &dev->mi, &dev->rdram, interrupt_handlers, emumode, count_per_op, count_per_op_denom_pot, no_compiled_jump, randomize_interrupt, start_address); init_rdp(&dev->dp, &dev->sp, &dev->mi, &dev->mem, &dev->rdram, &dev->r4300); init_rsp(&dev->sp, mem_base_u32(base, MM_RSP_MEM), &dev->mi, &dev->dp, &dev->ri); init_ai(&dev->ai, &dev->mi, &dev->ri, &dev->vi, aout, iaout, dma_modifier); init_mi(&dev->mi, &dev->r4300); init_pi(&dev->pi, get_pi_dma_handler, &dev->cart, &dev->dd, &dev->mi, &dev->ri, &dev->dp); init_ri(&dev->ri, &dev->rdram); init_si(&dev->si, si_dma_duration, &dev->mi, &dev->pif, &dev->ri); init_vi(&dev->vi, vi_clock, expected_refresh_rate, &dev->mi, &dev->dp); /* * use CART unless DD is plugged and the plugged CART is not a combo media (cart+disk), * or rom_size is 0 meaning there's no CART loaded */ uint8_t media = *((uint8_t*)mem_base_u32(base, MM_CART_ROM) + (0x3b ^ S8)); uint32_t rom_base = (rom_size == 0 || (dd_rom_size > 0 && media != 'C')) ? MM_DD_ROM : MM_CART_ROM; init_pif(&dev->pif, (uint8_t*)mem_base_u32(base, MM_PIF_MEM), jbds, ijbds, (uint8_t*)mem_base_u32(base, rom_base) + 0x40, &dev->r4300, &dev->si); init_cart(&dev->cart, af_rtc_clock, iaf_rtc_clock, (uint8_t*)mem_base_u32(base, MM_CART_ROM), rom_size, &dev->r4300, &dev->pi, eeprom_type, eeprom_storage, ieeprom_storage, flashram_type, flashram_storage, iflashram_storage, (const uint8_t*)dev->rdram.dram, sram_storage, isram_storage); } void poweron_device(struct device* dev) { size_t i; poweron_rdram(&dev->rdram); poweron_r4300(&dev->r4300); poweron_rdp(&dev->dp); poweron_rsp(&dev->sp); poweron_ai(&dev->ai); poweron_mi(&dev->mi); poweron_pi(&dev->pi); poweron_ri(&dev->ri); poweron_si(&dev->si); poweron_vi(&dev->vi); poweron_pif(&dev->pif); poweron_cart(&dev->cart); poweron_is_viewer(&dev->is); /* poweron for controllers */ for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { struct pif_channel* channel = &dev->pif.channels[i]; if ((channel->ijbd != NULL) && (channel->ijbd->poweron != NULL)) { channel->ijbd->poweron(channel->jbd); } } if (dev->dd.rom != NULL) { poweron_dd(&dev->dd); } } void run_device(struct device* dev) { /* device execution is driven by the r4300 */ run_r4300(&dev->r4300); } void stop_device(struct device* dev) { /* set stop flag so that r4300 execution will be stopped at next interrupt */ *r4300_stop(&dev->r4300) = 1; } void hard_reset_device(struct device* dev) { /* set reset hard flag so reset_hard will be called at next interrupt */ dev->r4300.reset_hard_job = 1; } void soft_reset_device(struct device* dev) { /* schedule HW2 interrupt now and an NMI after 1/2 seconds */ add_interrupt_event(&dev->r4300.cp0, HW2_INT, 0); add_interrupt_event(&dev->r4300.cp0, NMI_INT, 50000000); } mupen64plus-core-src-2.6.0/src/device/device.h000066400000000000000000000146351464506436200211150ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - device.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_DEVICE_H #define M64P_DEVICE_DEVICE_H #include #include #include "cart/cart.h" #include "cart/is_viewer.h" #include "controllers/game_controller.h" #include "controllers/paks/biopak.h" #include "controllers/paks/mempak.h" #include "controllers/paks/rumblepak.h" #include "controllers/paks/transferpak.h" #include "dd/dd_controller.h" #include "gb/gb_cart.h" #include "memory/memory.h" #include "pif/pif.h" #include "r4300/r4300_core.h" #include "rcp/ai/ai_controller.h" #include "rcp/mi/mi_controller.h" #include "rcp/pi/pi_controller.h" #include "rcp/rdp/rdp_core.h" #include "rcp/ri/ri_controller.h" #include "rcp/rsp/rsp_core.h" #include "rcp/si/si_controller.h" #include "rcp/vi/vi_controller.h" #include "rdram/rdram.h" struct audio_out_backend_interface; struct clock_backend_interface; struct storage_backend_interface; struct joybus_device_interface; enum { GAME_CONTROLLERS_COUNT = 4 }; /* memory map constants */ #define MM_RDRAM_DRAM UINT32_C(0x00000000) #define MM_RDRAM_REGS UINT32_C(0x03f00000) #define MM_RSP_MEM UINT32_C(0x04000000) #define MM_RSP_REGS UINT32_C(0x04040000) #define MM_RSP_REGS2 UINT32_C(0x04080000) #define MM_DPC_REGS UINT32_C(0x04100000) #define MM_DPS_REGS UINT32_C(0x04200000) #define MM_MI_REGS UINT32_C(0x04300000) #define MM_VI_REGS UINT32_C(0x04400000) #define MM_AI_REGS UINT32_C(0x04500000) #define MM_PI_REGS UINT32_C(0x04600000) #define MM_RI_REGS UINT32_C(0x04700000) #define MM_SI_REGS UINT32_C(0x04800000) #define MM_DOM2_ADDR1 UINT32_C(0x05000000) #define MM_DD_C2S_BUFFER UINT32_C(0x05000000) #define MM_DD_DS_BUFFER UINT32_C(0x05000400) #define MM_DD_REGS UINT32_C(0x05000500) #define MM_DD_MS_RAM UINT32_C(0x05000580) #define MM_DD_ROM UINT32_C(0x06000000) #define MM_DOM2_ADDR2 UINT32_C(0x08000000) #define MM_CART_ROM UINT32_C(0x10000000) /* dom1 addr2 */ #define MM_IS_VIEWER UINT32_C(0x13ff0000) /* IS-Viewer */ #define MM_PIF_MEM UINT32_C(0x1fc00000) #define MM_CART_DOM3 UINT32_C(0x1fd00000) /* dom2 addr2 */ /* Device structure is a container for the n64 submodules * It contains all state related to the emulated system. */ struct device { struct r4300_core r4300; struct rdp_core dp; struct rsp_core sp; struct ai_controller ai; struct mi_controller mi; struct pi_controller pi; struct ri_controller ri; struct si_controller si; struct vi_controller vi; struct pif pif; struct rdram rdram; struct memory mem; struct is_viewer is; struct game_controller controllers[GAME_CONTROLLERS_COUNT]; struct biopak biopaks[GAME_CONTROLLERS_COUNT]; struct mempak mempaks[GAME_CONTROLLERS_COUNT]; struct rumblepak rumblepaks[GAME_CONTROLLERS_COUNT]; struct transferpak transferpaks[GAME_CONTROLLERS_COUNT]; struct gb_cart gb_carts[GAME_CONTROLLERS_COUNT]; struct cart cart; struct dd_controller dd; }; /* Setup device "static" properties. */ void init_device(struct device* dev, /* memory */ void* base, /* r4300 */ unsigned int emumode, unsigned int count_per_op, unsigned int count_per_op_denom_pot, int no_compiled_jump, int randomize_interrupt, uint32_t start_address, /* ai */ void* aout, const struct audio_out_backend_interface* iaout, float dma_modifier, /* si */ unsigned int si_dma_duration, /* rdram */ size_t dram_size, /* pif */ void* jbds[PIF_CHANNELS_COUNT], const struct joybus_device_interface* ijbds[PIF_CHANNELS_COUNT], /* vi */ unsigned int vi_clock, unsigned int expected_refresh_rate, /* cart */ void* af_rtc_clock, const struct clock_backend_interface* iaf_rtc_clock, size_t rom_size, uint16_t eeprom_type, void* eeprom_storage, const struct storage_backend_interface* ieeprom_storage, uint32_t flashram_type, void* flashram_storage, const struct storage_backend_interface* iflashram_storage, void* sram_storage, const struct storage_backend_interface* isram_storage, /* dd */ void* dd_rtc_clock, const struct clock_backend_interface* dd_rtc_iclock, size_t dd_rom_size, void* dd_disk, const struct storage_backend_interface* dd_idisk); /* Setup device such that it's state is * what it should be after power on. */ void poweron_device(struct device* dev); /* Let device run. * To return from this function, a call to stop_device has to be made. */ void run_device(struct device* dev); /* Terminate execution of running device. */ void stop_device(struct device* dev); /* Schedule a hard reset on running device. * This is what model a poweroff/poweron action on the device. */ void hard_reset_device(struct device* dev); /* Schedule a soft reset on runnning device. * This is what model a press on the device reset button. */ void soft_reset_device(struct device* dev); #endif mupen64plus-core-src-2.6.0/src/device/gb/000077500000000000000000000000001464506436200200645ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/gb/gb_cart.c000066400000000000000000001110671464506436200216370ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - gb_cart.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2015 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Most of the mappers information comes from * "The Cycle-Accurate Game Boy Docs" by AntonioND */ #include "gb_cart.h" #include "api/m64p_types.h" #include "api/callbacks.h" #include "backends/api/rumble_backend.h" #include "backends/api/storage_backend.h" #include "backends/api/video_capture_backend.h" #if 0 void cv_imshow(const char* name, unsigned int width, unsigned int height, int channels, void* data); #else #define cv_imshow(...) #endif #include #include enum gbcart_extra_devices { GED_NONE = 0x00, GED_RAM = 0x01, GED_BATTERY = 0x02, GED_RTC = 0x04, GED_RUMBLE = 0x08, GED_ACCELEROMETER = 0x10, GED_CAMERA = 0x20, }; /* various helper functions for ram, rom, or MBC uses */ static void read_rom(const void* rom_storage, const struct storage_backend_interface* irom_storage, uint16_t address, uint8_t* data, size_t size) { assert(size > 0); if (address + size > irom_storage->size(rom_storage)) { DebugMessage(M64MSG_WARNING, "Out of bound read from GB ROM %04x", address); return; } memcpy(data, irom_storage->data(rom_storage) + address, size); } static void read_ram(const void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint16_t address, uint8_t* data, size_t size, uint8_t mask) { size_t i; assert(size > 0); /* RAM has to be enabled before use */ if (!enabled) { DebugMessage(M64MSG_WARNING, "Trying to read from non enabled GB RAM %04x", address); memset(data, 0xff, size); return; } /* RAM must be present */ if (iram_storage->data(ram_storage) == NULL) { DebugMessage(M64MSG_WARNING, "Trying to read from absent GB RAM %04x", address); memset(data, 0xff, size); return; } if (address + size > iram_storage->size(ram_storage)) { DebugMessage(M64MSG_WARNING, "Out of bound read from GB RAM %04x", address); return; } memcpy(data, iram_storage->data(ram_storage) + address, size); if (mask != UINT8_C(0xff)) { for (i = 0; i < size; ++i) { data[i] &= mask; } } } static void write_ram(void* ram_storage, const struct storage_backend_interface* iram_storage, unsigned int enabled, uint16_t address, const uint8_t* data, size_t size, uint8_t mask) { size_t i; uint8_t* dst; assert(size > 0); /* RAM has to be enabled before use */ if (!enabled) { DebugMessage(M64MSG_WARNING, "Trying to write to non enabled GB RAM %04x", address); return; } /* RAM must be present */ if (iram_storage->data(ram_storage) == NULL) { DebugMessage(M64MSG_WARNING, "Trying to write to absent GB RAM %04x", address); return; } if (address + size > iram_storage->size(ram_storage)) { DebugMessage(M64MSG_WARNING, "Out of bound write to GB RAM %04x", address); return; } dst = iram_storage->data(ram_storage) + address; memcpy(dst, data, size); if (mask != UINT8_C(0xff)) { for (i = 0; i < size; ++i) { dst[i] &= mask; } } iram_storage->save(ram_storage, address, size); } static void set_ram_enable(struct gb_cart* gb_cart, uint8_t value) { gb_cart->ram_enable = ((value & 0x0f) == 0x0a) ? 1 : 0; DebugMessage(M64MSG_VERBOSE, "RAM enable = %02x", gb_cart->ram_enable); } static int read_gb_cart_nombc(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { switch(address >> 13) { /* 0x0000-0x7fff: ROM */ case (0x0000 >> 13): case (0x2000 >> 13): case (0x4000 >> 13): case (0x6000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size); break; /* 0xa000-0xbfff: RAM */ case (0xa000 >> 13): read_ram(gb_cart->ram_storage, gb_cart->iram_storage, 1, address - 0xa000, data, size, UINT8_C(0xff)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart read (nombc): %04x", address); } return 0; } static int write_gb_cart_nombc(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { switch(address >> 13) { /* 0x0000-0x7fff: ROM */ case (0x0000 >> 13): case (0x2000 >> 13): case (0x4000 >> 13): case (0x6000 >> 13): DebugMessage(M64MSG_VERBOSE, "Trying to write to GB ROM %04x", address); break; /* 0xa000-0xbfff: RAM */ case (0xa000 >> 13): write_ram(gb_cart->ram_storage, gb_cart->iram_storage, 1, address - 0xa000, data, size, UINT8_C(0xff)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart write (nombc): %04x", address); } return 0; } static int read_gb_cart_mbc1(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { switch(address >> 13) { /* 0x0000-0x3fff: ROM bank 00 */ case (0x0000 >> 13): case (0x2000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size); break; /* 0x4000-0x7fff: ROM bank 01-7f */ case (0x4000 >> 13): case (0x6000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, (address - 0x4000) + (gb_cart->rom_bank * 0x4000), data, size); break; /* 0xa000-0xbfff: RAM bank 00-03 */ case (0xa000 >> 13): read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart read (MBC1): %04x", address); } return 0; } static int write_gb_cart_mbc1(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { uint8_t bank; uint8_t value = data[size-1]; switch(address >> 13) { /* 0x0000-0x1fff: RAM enable */ case (0x0000 >> 13): set_ram_enable(gb_cart, value); break; /* 0x2000-0x3fff: ROM bank select (low 5 bits) */ case (0x2000 >> 13): bank = value & 0x1f; gb_cart->rom_bank = (gb_cart->rom_bank & ~UINT8_C(0x1f)) | (bank == 0) ? 1 : bank; DebugMessage(M64MSG_VERBOSE, "MBC1 set rom bank %02x", gb_cart->rom_bank); break; /* 0x4000-0x5fff: RAM bank / upper ROM bank select (2 bits) */ case (0x4000 >> 13): bank = value & 0x3; if (gb_cart->mbc1_mode == 0) { /* ROM mode */ gb_cart->rom_bank = (gb_cart->rom_bank & 0x1f) | (bank << 5); } else { /* RAM mode */ gb_cart->ram_bank = bank; } DebugMessage(M64MSG_VERBOSE, "MBC1 set ram bank %02x", gb_cart->ram_bank); break; /* 0x6000-0x7fff: ROM/RAM mode (1 bit) */ case (0x6000 >> 13): gb_cart->mbc1_mode = (value & 0x1); if (gb_cart->mbc1_mode == 0) { /* only RAM bank 0 is accessible in ROM mode */ gb_cart->ram_bank = 0; } else { /* only ROM banks 0x01 - 0x1f are accessible in RAM mode */ gb_cart->rom_bank &= 0x1f; } break; /* 0xa000-0xbfff: RAM bank 00-03 */ case (0xa000 >> 13): write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart write (MBC1): %04x", address); } return 0; } static int read_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { switch (address >> 13) { /* 0x0000-0x3fff: ROM bank 00 */ case (0x0000 >> 13): case (0x2000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size); break; /* 0x4000-0x7fff: ROM bank 01-0f */ case (0x4000 >> 13): case (0x6000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, (address - 0x4000) + (gb_cart->rom_bank * 0x4000), data, size); break; /* 0xa000-0xa1ff: internal 512x4bit RAM */ case (0xa000 >> 13): read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000), data, size, UINT8_C(0x0f)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart read (MBC2): %04x", address); } return 0; } static int write_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { uint8_t bank; uint8_t value = data[size-1]; switch(address >> 13) { /* 0x0000-0x1fff: RAM enable */ case (0x0000 >> 13): if ((address & 0x0100) == 0) { set_ram_enable(gb_cart, value); } break; /* 0x2000-0x3fff: ROM bank select (low 4 bits) */ case (0x2000 >> 13): if ((address & 0x0100) != 0) { bank = value & 0x0f; gb_cart->rom_bank = (bank == 0) ? 1 : bank; DebugMessage(M64MSG_VERBOSE, "MBC2 set rom bank %02x", gb_cart->rom_bank); } break; /* 0xa000-0xa1ff: internal 512x4bit RAM */ case (0xa000 >> 13): write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000), data, size, UINT8_C(0x0f)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart write (MBC2): %04x", address); } return 0; } static int read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { switch(address >> 13) { /* 0x0000-0x3fff: ROM bank 00 */ case (0x0000 >> 13): case (0x2000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size); break; /* 0x4000-0x7fff: ROM bank 01-7f */ case (0x4000 >> 13): case (0x6000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, (address - 0x4000) + (gb_cart->rom_bank * 0x4000), data, size); break; /* 0xa000-0xbfff: RAM bank 00-07 or RTC register 08-0c */ case (0xa000 >> 13): switch(gb_cart->ram_bank) { /* RAM banks */ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); break; /* RTC registers */ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: /* RAM has to be enabled before use */ if (!gb_cart->ram_enable) { DebugMessage(M64MSG_WARNING, "Trying to read from non enabled GB RAM %04x", address); memset(data, 0xff, size); break; } if (!(gb_cart->extra_devices & GED_RTC)) { DebugMessage(M64MSG_WARNING, "Trying to read from absent RTC %04x", address); memset(data, 0xff, size); break; } memset(data, read_mbc3_rtc_regs(&gb_cart->rtc, gb_cart->ram_bank - 0x08), size); break; default: DebugMessage(M64MSG_WARNING, "Unknown device mapped in RAM/RTC space: %04x", address); } break; default: DebugMessage(M64MSG_WARNING, "Invalid cart read (MBC3): %04x", address); } return 0; } static int write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { uint8_t bank; uint8_t value = data[size-1]; switch(address >> 13) { /* 0x0000-0x1fff: RAM/RTC enable */ case (0x0000 >> 13): set_ram_enable(gb_cart, value); break; /* 0x2000-0x3fff: ROM bank select */ case (0x2000 >> 13): bank = value & 0x7f; gb_cart->rom_bank = (bank == 0) ? 1 : bank; DebugMessage(M64MSG_VERBOSE, "MBC3 set rom bank %02x", gb_cart->rom_bank); break; /* 0x4000-0x5fff: RAM bank / RTC register select */ case (0x4000 >> 13): gb_cart->ram_bank = value; DebugMessage(M64MSG_VERBOSE, "MBC3 set ram bank %02x", gb_cart->ram_bank); break; /* 0x6000-0x7fff: latch clock registers */ case (0x6000 >> 13): if (!(gb_cart->extra_devices & GED_RTC)) { DebugMessage(M64MSG_WARNING, "Trying to latch to absent RTC %04x", address); break; } latch_mbc3_rtc_regs(&gb_cart->rtc, value); break; /* 0xa000-0xbfff: RAM bank 00-07 or RTC register 08-0c */ case (0xa000 >> 13): switch(gb_cart->ram_bank) { /* RAM banks */ case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); break; /* RTC registers */ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: /* RAM has to be enabled before use */ if (!gb_cart->ram_enable) { DebugMessage(M64MSG_WARNING, "Trying to write to non enabled GB RAM %04x", address); break; } if (!(gb_cart->extra_devices & GED_RTC)) { DebugMessage(M64MSG_WARNING, "Trying to write to absent RTC %04x", address); break; } write_mbc3_rtc_regs(&gb_cart->rtc, gb_cart->ram_bank - 0x08, value); break; default: DebugMessage(M64MSG_WARNING, "Unknwown device mapped in RAM/RTC space: %04x", address); } break; default: DebugMessage(M64MSG_WARNING, "Invalid cart write (MBC3): %04x", address); } return 0; } static int read_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { switch(address >> 13) { /* 0x0000-0x3fff: ROM bank 00 */ case (0x0000 >> 13): case (0x2000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size); break; /* 0x4000-0x7fff: ROM bank 00-ff (???) */ case (0x4000 >> 13): case (0x6000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, (address - 0x4000) + (gb_cart->rom_bank * 0x4000), data, size); break; /* 0xa000-0xbfff: RAM bank 00-07 */ case (0xa000 >> 13): read_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + ((gb_cart->ram_bank & 0x7) * 0x2000), data, size, UINT8_C(0xff)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart read (MBC5): %04x", address); } return 0; } static int write_gb_cart_mbc5(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { uint8_t value = data[size-1]; switch(address >> 13) { /* 0x0000-0x1fff: RAM enable */ case (0x0000 >> 13): set_ram_enable(gb_cart, value); break; /* 0x2000-0x3fff: ROM bank select */ case (0x2000 >> 13): if (address < 0x3000) { gb_cart->rom_bank &= 0xff00; gb_cart->rom_bank |= value; } else { gb_cart->rom_bank &= 0x00ff; gb_cart->rom_bank |= (value & 0x01) << 8; } DebugMessage(M64MSG_VERBOSE, "MBC5 set rom bank %04x", gb_cart->rom_bank); break; /* 0x4000-0x5fff: RAM bank select */ case (0x4000 >> 13): gb_cart->ram_bank = value & 0x0f; if (gb_cart->extra_devices & GED_RUMBLE) { gb_cart->irumble->exec(gb_cart->rumble, ((gb_cart->ram_bank & 0x8) == 0) ? RUMBLE_STOP : RUMBLE_START); } DebugMessage(M64MSG_VERBOSE, "MBC5 set ram bank %02x", gb_cart->ram_bank); break; /* 0xa000-0xbfff: RAM bank 00-0f */ case (0xa000 >> 13): write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + ((gb_cart->ram_bank & 0x07)* 0x2000), data, size, UINT8_C(0xff)); break; default: DebugMessage(M64MSG_WARNING, "Invalid cart write (MBC5): %04x", address); } return 0; } static int read_gb_cart_mbc6(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { return 0; } static int write_gb_cart_mbc6(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { return 0; } static int read_gb_cart_mbc7(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { return 0; } static int write_gb_cart_mbc7(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { return 0; } static int read_gb_cart_mmm01(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { return 0; } static int write_gb_cart_mmm01(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { return 0; } /* TODO: extract each mbc into its own module, store in gb_cart a union of them */ static uint8_t apply_dithering_matrix(const uint8_t* d, uint8_t value, unsigned int x, unsigned int y) { d += ((y & 3) * 4 + (x & 3)) * 3; if (value < d[0]) return 0x00; /* black */ else if (value < d[1]) return 0x40; /* dark gray */ else if (value < d[2]) return 0x80; /* light gray */ return 0xc0; /* white */ } static void grab_pocket_cam_image(struct pocket_cam* cam) { static const uint8_t pm[4][2] = { { 0x00, 0x01 }, /* negative */ { 0x01, 0x00 }, /* positive */ { 0x01, 0x02 }, /* edge detect */ { 0x01, 0x02 } /* edge detect */ }; uint8_t regs[M64282FP_REGS_COUNT]; uint8_t tiles[16][16][16]; uint8_t bgr[M64282FP_SENSOR_H][M64282FP_SENSOR_W][3]; uint8_t img[M64282FP_SENSOR_H][M64282FP_SENSOR_W]; unsigned int x, y; /* setup sensor regs */ unsigned int pm_mode = (cam->regs[0] >> 1) & 0x3; regs[M64282FP_Z_O] = cam->regs[5]; regs[M64282FP_N_VH_G] = cam->regs[1]; regs[M64282FP_C_LO] = cam->regs[3]; regs[M64282FP_C_HI] = cam->regs[2]; regs[M64282FP_P] = pm[pm_mode][0]; regs[M64282FP_M] = pm[pm_mode][1]; regs[M64282FP_X] = 0x01; regs[M64282FP_E_I_V] = cam->regs[4]; #if 0 DebugMessage(M64MSG_INFO, "GB cam regs:\n" "P=%02x M=%02x X=%02x N_VH_G=%02x C=%04x E_I_V=%02x Z_O=%02x\n" "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", regs[M64282FP_P], regs[M64282FP_M], regs[M64282FP_X], regs[M64282FP_N_VH_G], regs[M64282FP_C_HI] << 8 | regs[M64282FP_C_LO], regs[M64282FP_E_I_V], regs[M64282FP_Z_O], cam->regs[6], cam->regs[7], cam->regs[8], cam->regs[9], cam->regs[10], cam->regs[11], cam->regs[12], cam->regs[13], cam->regs[14], cam->regs[15], cam->regs[16], cam->regs[17], cam->regs[18], cam->regs[19], cam->regs[20], cam->regs[21], cam->regs[22], cam->regs[23], cam->regs[24], cam->regs[25], cam->regs[26], cam->regs[27], cam->regs[28], cam->regs[29], cam->regs[30], cam->regs[31], cam->regs[32], cam->regs[33], cam->regs[34], cam->regs[35], cam->regs[36], cam->regs[37], cam->regs[38], cam->regs[39], cam->regs[40], cam->regs[41], cam->regs[42], cam->regs[43], cam->regs[44], cam->regs[45], cam->regs[46], cam->regs[47], cam->regs[48], cam->regs[49], cam->regs[50], cam->regs[51], cam->regs[52], cam->regs[53]); #endif /* grab BGR image */ if (cam->ivcap->grab_image(cam->vcap, bgr) != M64ERR_SUCCESS) { memset(cam->ram, UINT8_C(0xff), sizeof(tiles)); return; } cv_imshow("bgr image", M64282FP_SENSOR_W, M64282FP_SENSOR_H, 3, bgr); /* convert to gray using (2R+5G+1B)/8 formula */ const uint8_t* bgr_ptr = &bgr[0][0][0]; uint8_t* gray_ptr = &img[0][0]; for (y = 0; y < M64282FP_SENSOR_H; ++y) { for (x = 0; x < M64282FP_SENSOR_W; ++x) { gray_ptr[0] = (1*bgr_ptr[0] + 5*bgr_ptr[1] + 2*bgr_ptr[2]) / 8; bgr_ptr += 3; gray_ptr += 1; } } /* apply m64282fp processings */ cv_imshow("gray image", M64282FP_SENSOR_W, M64282FP_SENSOR_H, 1, img); process_m64282fp_image(img, regs); cv_imshow("m64282fp", M64282FP_SENSOR_W, M64282FP_SENSOR_H, 1, img); /* convert to dithered GB tile format */ memset(tiles, 0, sizeof(tiles)); for (y = 0; y < M64282FP_SENSOR_H; ++y) { for (x = 0; x < M64282FP_SENSOR_W; ++x) { /* apply dithering matrix */ uint8_t c = UINT8_C(0xc0) - apply_dithering_matrix(&cam->regs[6], img[y][x], x, y); img[y][x] = c; /* encode as tiles */ uint8_t* tile_base = &tiles[y >> 3][x >> 3][(y & 7) << 1]; if (c & 0x40) { tile_base[0] |= (1U << (7 - (7 & x))); } if (c & 0x80) { tile_base[1] |= (1U << (7 - (7 & x))); } } } cv_imshow("dithered", M64282FP_SENSOR_W, M64282FP_SENSOR_H, 1, img); /* copy to ram */ memcpy(cam->ram, tiles, sizeof(tiles)); } static void init_pocket_cam(struct pocket_cam* cam, uint8_t* ram, void* vcap, const struct video_capture_backend_interface* ivcap) { cam->ram = ram; cam->vcap = vcap; cam->ivcap = ivcap; } static void poweron_pocket_cam(struct pocket_cam* cam) { memset(cam->regs, 0, POCKET_CAM_REGS_COUNT*sizeof(cam->regs[0])); } static uint8_t read_pocket_cam_regs(struct pocket_cam* cam, unsigned int reg) { /* All registers except reg 0 are write-only and therefore return 0x00 */ return (reg == 0) ? cam->regs[0] : 0x00; } static void write_pocket_cam_regs(struct pocket_cam* cam, unsigned int reg, uint8_t value) { if (reg >= POCKET_CAM_REGS_COUNT) { #if 0 /* silence it because it happens always (2x32 bytes writes go past 0x36 registers) */ DebugMessage(M64MSG_WARNING, "Out of range camera register write %02x = %02x", reg, value); #endif return; } cam->regs[reg] = value; if (reg == 0) { cam->regs[reg] &= 0x7; if (cam->regs[reg] & 0x1) { grab_pocket_cam_image(cam); cam->regs[reg] &= ~0x01; } } } static int read_gb_cart_pocket_cam(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { switch(address >> 13) { /* 0x0000-0x3fff: ROM bank 00 */ case (0x0000 >> 13): case (0x2000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, address, data, size); break; /* 0x4000-0x7fff: ROM bank 00-3f */ case (0x4000 >> 13): case (0x6000 >> 13): read_rom(gb_cart->rom_storage, gb_cart->irom_storage, (address - 0x4000) + (gb_cart->rom_bank * 0x4000), data, size); break; /* 0xa000-0xbfff: RAM bank 00-0f, Camera registers & 0x10 */ case (0xa000 >> 13): if (gb_cart->ram_bank & 0x10) { size_t i; for(i = 0; i < size; ++i) { data[i] = read_pocket_cam_regs(&gb_cart->cam, ((address+i) & 0x7f)); } } else { read_ram(gb_cart->ram_storage, gb_cart->iram_storage, 1, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); } break; default: DebugMessage(M64MSG_WARNING, "Invalid cart read (cam): %04x", address); } return 0; } static int write_gb_cart_pocket_cam(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { uint8_t value = data[size-1]; switch(address >> 13) { /* 0x0000-0x1fff: RAM write enable */ case (0x0000 >> 13): set_ram_enable(gb_cart, value); break; /* 0x2000-0x3fff: ROM bank select */ case (0x2000 >> 13): gb_cart->rom_bank = (value & 0x3f); DebugMessage(M64MSG_VERBOSE, "CAM set rom bank %04x", gb_cart->rom_bank); break; /* 0x4000-0x5fff: RAM bank select */ case (0x4000 >> 13): if (value & 0x10) { gb_cart->ram_bank = value; DebugMessage(M64MSG_VERBOSE, "CAM set register bank %02x", gb_cart->ram_bank); } else { gb_cart->ram_bank = (value & 0x0f); DebugMessage(M64MSG_VERBOSE, "CAM set ram bank %02x", gb_cart->ram_bank); } break; /* 0xa000-0xbfff: RAM bank 00-0f, Camera registers & 0x10 */ case (0xa000 >> 13): if (gb_cart->ram_bank & 0x10) { size_t i; for(i = 0; i < size; ++i) { write_pocket_cam_regs(&gb_cart->cam, ((address+i) & 0x7f), data[i]); } } else { write_ram(gb_cart->ram_storage, gb_cart->iram_storage, gb_cart->ram_enable, (address - 0xa000) + (gb_cart->ram_bank * 0x2000), data, size, UINT8_C(0xff)); } break; default: DebugMessage(M64MSG_WARNING, "Invalid cart write (cam): %04x", address); } return 0; } static int read_gb_cart_bandai_tama5(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { return 0; } static int write_gb_cart_bandai_tama5(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { return 0; } static int read_gb_cart_huc1(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { return 0; } static int write_gb_cart_huc1(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { return 0; } static int read_gb_cart_huc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { return 0; } static int write_gb_cart_huc3(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { return 0; } struct parsed_cart_type { const char* mbc; int (*read_gb_cart)(struct gb_cart*,uint16_t,uint8_t*,size_t); int (*write_gb_cart)(struct gb_cart*,uint16_t,const uint8_t*,size_t); unsigned int extra_devices; }; static const struct parsed_cart_type* parse_cart_type(uint8_t cart_type) { #define MBC(x) #x, read_gb_cart_ ## x, write_gb_cart_ ## x static const struct parsed_cart_type nombc_none = { MBC(nombc), GED_NONE }; static const struct parsed_cart_type nombc_ram = { MBC(nombc), GED_RAM }; static const struct parsed_cart_type nombc_ram_batt = { MBC(nombc), GED_RAM | GED_BATTERY }; static const struct parsed_cart_type mbc1_none = { MBC(mbc1), GED_NONE }; static const struct parsed_cart_type mbc1_ram = { MBC(mbc1), GED_RAM }; static const struct parsed_cart_type mbc1_ram_batt = { MBC(mbc1), GED_RAM | GED_BATTERY }; static const struct parsed_cart_type mbc2_none = { MBC(mbc2), GED_NONE }; static const struct parsed_cart_type mbc2_ram_batt = { MBC(mbc2), GED_RAM | GED_BATTERY }; static const struct parsed_cart_type mmm01_none = { MBC(mmm01), GED_NONE }; static const struct parsed_cart_type mmm01_ram = { MBC(mmm01), GED_RAM }; static const struct parsed_cart_type mmm01_ram_batt = { MBC(mmm01), GED_RAM | GED_BATTERY }; static const struct parsed_cart_type mbc3_none = { MBC(mbc3), GED_NONE }; static const struct parsed_cart_type mbc3_ram = { MBC(mbc3), GED_RAM }; static const struct parsed_cart_type mbc3_ram_batt = { MBC(mbc3), GED_RAM | GED_BATTERY }; static const struct parsed_cart_type mbc3_batt_rtc = { MBC(mbc3), GED_BATTERY | GED_RTC }; static const struct parsed_cart_type mbc3_ram_batt_rtc = { MBC(mbc3), GED_RAM | GED_BATTERY | GED_RTC }; static const struct parsed_cart_type mbc5_none = { MBC(mbc5), GED_NONE }; static const struct parsed_cart_type mbc5_ram = { MBC(mbc5), GED_RAM }; static const struct parsed_cart_type mbc5_ram_batt = { MBC(mbc5), GED_RAM | GED_BATTERY }; static const struct parsed_cart_type mbc5_rumble = { MBC(mbc5), GED_RUMBLE }; static const struct parsed_cart_type mbc5_ram_rumble = { MBC(mbc5), GED_RAM | GED_RUMBLE }; static const struct parsed_cart_type mbc5_ram_batt_rumble = { MBC(mbc5), GED_RAM | GED_BATTERY | GED_RUMBLE }; static const struct parsed_cart_type mbc6 = { MBC(mbc6), GED_RAM | GED_BATTERY }; static const struct parsed_cart_type mbc7 = { MBC(mbc7), GED_RAM | GED_BATTERY | GED_ACCELEROMETER }; static const struct parsed_cart_type pocket_cam = { MBC(pocket_cam), GED_RAM | GED_CAMERA }; static const struct parsed_cart_type bandai_tama5 = { MBC(bandai_tama5), GED_NONE }; static const struct parsed_cart_type huc3 = { MBC(huc3), GED_NONE }; static const struct parsed_cart_type huc1 = { MBC(huc1), GED_RAM | GED_BATTERY }; #undef MBC switch(cart_type) { case 0x00: return &nombc_none; case 0x01: return &mbc1_none; case 0x02: return &mbc1_ram; case 0x03: return &mbc1_ram_batt; /* 0x04 is unused */ case 0x05: return &mbc2_none; case 0x06: return &mbc2_ram_batt; /* 0x07 is unused */ case 0x08: return &nombc_ram; case 0x09: return &nombc_ram_batt; /* 0x0a is unused */ case 0x0b: return &mmm01_none; case 0x0c: return &mmm01_ram; case 0x0d: return &mmm01_ram_batt; /* 0x0e is unused */ case 0x0f: return &mbc3_batt_rtc; case 0x10: return &mbc3_ram_batt_rtc; case 0x11: return &mbc3_none; case 0x12: return &mbc3_ram; case 0x13: return &mbc3_ram_batt; /* 0x14-0x18 are unused */ case 0x19: return &mbc5_none; case 0x1a: return &mbc5_ram; case 0x1b: return &mbc5_ram_batt; case 0x1c: return &mbc5_rumble; case 0x1d: return &mbc5_ram_rumble; case 0x1e: return &mbc5_ram_batt_rumble; /* 0x1f is unused */ case 0x20: return &mbc6; /* 0x21 is unused */ case 0x22: return &mbc7; /* 0x23-0xfb are unused */ case 0xfc: return &pocket_cam; case 0xfd: return &bandai_tama5; case 0xfe: return &huc3; case 0xff: return &huc1; default: return NULL; } } void init_gb_cart(struct gb_cart* gb_cart, void* rom_opaque, void (*init_rom)(void* user_data, void** rom_storage, const struct storage_backend_interface** irom_storage), void (*release_rom)(void* user_data), void* ram_opaque, void (*init_ram)(void* user_data, size_t ram_size, void** ram_storage, const struct storage_backend_interface** iram_storage), void (*release_ram)(void* user_data), void* clock, const struct clock_backend_interface* iclock, void* rumble, const struct rumble_backend_interface* irumble, void* vcap, const struct video_capture_backend_interface* ivcap) { const struct parsed_cart_type* type; void* rom_storage = NULL; const struct storage_backend_interface* irom_storage = NULL; void* ram_storage = NULL; const struct storage_backend_interface* iram_storage = NULL; struct mbc3_rtc rtc; struct pocket_cam cam; memset(&rtc, 0, sizeof(rtc)); memset(&cam, 0, sizeof(cam)); /* ask to load rom and initialize rom storage backend */ init_rom(rom_opaque, &rom_storage, &irom_storage); /* handle no cart case */ if (irom_storage == NULL) { goto no_cart; } /* check rom size */ const uint8_t* rom_data = irom_storage->data(rom_storage); if (rom_data == NULL || irom_storage->size(rom_storage) < 0x8000) { DebugMessage(M64MSG_ERROR, "Invalid GB ROM file size (< 32k)"); goto error_release_rom; } /* get and parse cart type */ uint8_t cart_type = rom_data[0x147]; type = parse_cart_type(cart_type); if (type == NULL) { DebugMessage(M64MSG_ERROR, "Invalid GB cart type (%02x)", cart_type); goto error_release_rom; } DebugMessage(M64MSG_INFO, "GB cart type (%02x) %s%s%s%s%s%s%s", cart_type, type->mbc, (type->extra_devices & GED_RAM) ? " RAM" : "", (type->extra_devices & GED_BATTERY) ? " BATT" : "", (type->extra_devices & GED_RTC) ? " RTC" : "", (type->extra_devices & GED_RUMBLE) ? " RUMBLE" : "", (type->extra_devices & GED_ACCELEROMETER) ? " ACCEL" : "", (type->extra_devices & GED_CAMERA) ? " CAM" : ""); /* load ram (if present) */ if (type->extra_devices & GED_RAM) { size_t ram_size = 0; switch(rom_data[0x149]) { case 0x00: ram_size = (strcmp(type->mbc, "mbc2") == 0) ? 0x200 /* MBC2 have an integrated 512x4bit RAM */ : 0; break; case 0x01: ram_size = 1*0x800; break; case 0x02: ram_size = 4*0x800; break; case 0x03: ram_size = 16*0x800; break; case 0x04: ram_size = 64*0x800; break; case 0x05: ram_size = 32*0x800; break; } if (ram_size != 0) { init_ram(ram_opaque, ram_size, &ram_storage, &iram_storage); /* check that init_ram succeeded */ if (iram_storage == NULL) { DebugMessage(M64MSG_ERROR, "Failed to initialize GB RAM"); goto error_release_ram; } if (iram_storage->data(ram_storage) == NULL || iram_storage->size(ram_storage) != ram_size) { DebugMessage(M64MSG_ERROR, "Cannot get GB RAM (%d bytes)", (uint32_t) ram_size); goto error_release_ram; } DebugMessage(M64MSG_INFO, "Using a %d bytes GB RAM", (uint32_t) ram_size); } } /* set RTC clock (if present) */ if (type->extra_devices & GED_RTC) { init_mbc3_rtc(&rtc, clock, iclock); } if (type->extra_devices & GED_CAMERA) { init_pocket_cam(&cam, iram_storage->data(ram_storage), vcap, ivcap); } /* update gb_cart */ gb_cart->rom_storage = rom_storage; gb_cart->irom_storage = irom_storage; gb_cart->ram_storage = ram_storage; gb_cart->iram_storage = iram_storage; gb_cart->extra_devices = type->extra_devices; gb_cart->rtc = rtc; gb_cart->cam = cam; gb_cart->rumble = rumble; gb_cart->irumble = irumble; gb_cart->read_gb_cart = type->read_gb_cart; gb_cart->write_gb_cart = type->write_gb_cart; return; error_release_ram: release_ram(ram_opaque); error_release_rom: release_rom(rom_opaque); no_cart: memset(gb_cart, 0, sizeof(*gb_cart)); } void poweron_gb_cart(struct gb_cart* gb_cart) { gb_cart->rom_bank = 1; gb_cart->ram_bank = 0; gb_cart->ram_enable = 0; gb_cart->mbc1_mode = 0; if (gb_cart->extra_devices & GED_RTC) { poweron_mbc3_rtc(&gb_cart->rtc); } if (gb_cart->extra_devices & GED_CAMERA) { poweron_pocket_cam(&gb_cart->cam); } if (gb_cart->extra_devices & GED_RUMBLE) { gb_cart->irumble->exec(gb_cart->rumble, RUMBLE_STOP); } } int read_gb_cart(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size) { return gb_cart->read_gb_cart(gb_cart, address, data, size); } int write_gb_cart(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size) { return gb_cart->write_gb_cart(gb_cart, address, data, size); } mupen64plus-core-src-2.6.0/src/device/gb/gb_cart.h000066400000000000000000000070041464506436200216370ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - gb_cart.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2015 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_GB_GB_CART_H #define M64P_DEVICE_GB_GB_CART_H #include #include #include "m64282fp.h" #include "mbc3_rtc.h" struct storage_backend_interface; struct rumble_backend_interface; struct video_capture_backend_interface; enum pocket_cam_registers { /* TODO: use pretty names for registers */ POCKET_CAM_REGS_COUNT = 0x36 }; struct pocket_cam { uint8_t regs[POCKET_CAM_REGS_COUNT]; void* vcap; const struct video_capture_backend_interface* ivcap; uint8_t* ram; }; struct gb_cart { void* rom_storage; const struct storage_backend_interface* irom_storage; void* ram_storage; const struct storage_backend_interface* iram_storage; unsigned int rom_bank; unsigned int ram_bank; unsigned int ram_enable; unsigned int mbc1_mode; unsigned int extra_devices; struct mbc3_rtc rtc; struct pocket_cam cam; void* rumble; const struct rumble_backend_interface* irumble; int (*read_gb_cart)(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size); int (*write_gb_cart)(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size); }; void init_gb_cart(struct gb_cart* gb_cart, void* rom_opaque, void (*init_rom)(void* user_data, void** rom_storage, const struct storage_backend_interface** irom_storage), void (*release_rom)(void* user_data), void* ram_opaque, void (*init_ram)(void* user_data, size_t ram_size, void** ram_storage, const struct storage_backend_interface** iram_storage), void (*release_ram)(void* user_data), void* clock, const struct clock_backend_interface* iclock, void* rumble, const struct rumble_backend_interface* irumble, void* vcap, const struct video_capture_backend_interface* ivcap); void poweron_gb_cart(struct gb_cart* gb_cart); int read_gb_cart(struct gb_cart* gb_cart, uint16_t address, uint8_t* data, size_t size); int write_gb_cart(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data, size_t size); #endif mupen64plus-core-src-2.6.0/src/device/gb/m64282fp.c000066400000000000000000000155311464506436200214250ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - m64282fp.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Most of the mappers information comes from * "Game Boy Camera Technical Information v1.1.1" by AntonioND */ #include "m64282fp.h" #include int min(int a, int b) { return (a < b) ? a : b; } int max(int a, int b) { return (a < b) ? b : a; } int clamp(int v, int low, int high) { return min(high, max(low, v)); } static void do_kernel_filtering(int img[M64282FP_SENSOR_H][M64282FP_SENSOR_W], int a, const int k[6]) { unsigned int x, y; /* north line and last west pixel previous values */ int tmp[1+M64282FP_SENSOR_W]; memcpy(tmp, &img[0][0], M64282FP_SENSOR_W*sizeof(img[0][0])); for (y = 0; y < M64282FP_SENSOR_H; ++y) { tmp[M64282FP_SENSOR_W] = img[y][0]; for (x = 0; x < M64282FP_SENSOR_W; ++x) { int px = img[y][x]; int ms = img[min(y+1, M64282FP_SENSOR_H-1)][x]; int me = img[y][min(x+1, M64282FP_SENSOR_W-1)]; int mn = tmp[x]; int mw = tmp[M64282FP_SENSOR_W]; img[y][x] = k[0]*px+((a*(k[1]*px+k[2]*mn+k[3]*mw+k[4]*me+k[5]*ms))/4); tmp[x] = px; tmp[M64282FP_SENSOR_W] = px; } } } static void do_1d_filtering(int img[M64282FP_SENSOR_H][M64282FP_SENSOR_W], uint8_t P, uint8_t M) { unsigned int x, y; for (y = 0; y < M64282FP_SENSOR_H; ++y) { for (x = 0; x < M64282FP_SENSOR_W; ++x) { int px = img[y][x]; int s1 = img[min(y+1, M64282FP_SENSOR_H-1)][x]; int s2 = img[min(y+2, M64282FP_SENSOR_H-1)][x]; int s3 = img[min(y+3, M64282FP_SENSOR_H-1)][x]; int value = 0; if (P & 0x01) { value += px; } if (P & 0x02) { value += s1; } if (P & 0x04) { value += s2; } if (P & 0x08) { value += s3; } if (M & 0x01) { value -= px; } if (M & 0x02) { value -= s1; } if (M & 0x04) { value -= s2; } if (M & 0x08) { value -= s3; } img[y][x] = value; } } } void process_m64282fp_image( uint8_t img[M64282FP_SENSOR_H][M64282FP_SENSOR_W], const uint8_t regs[M64282FP_REGS_COUNT]) { unsigned int x, y; int tmp[M64282FP_SENSOR_H][M64282FP_SENSOR_W]; static const int kernels[6][6] = { /* px +a*(px +mn +mw +me +ms) */ { 1, 2, 0, -1, -1, 0 }, /* horiz enhancement */ { 0, 2, 0, -1, -1, 0 }, /* horiz extraction */ { 1, 2, -1, 0, 0, -1 }, /* vert enhancement */ { 0, 2, -1, 0, 0, -1 }, /* vert extraction */ { 1, 4, -1, -1, -1, -1 }, /* 2d enhancement */ { 0, 4, -1, -1, -1, -1 }, /* 2d extraction */ }; /* edge ratio (alpha) Q.2 format */ #define Q2(x) (4*x) static const int alpha_lut[8] = { Q2(2/4), Q2(3/4), Q2(1), Q2(5/4), Q2(2), Q2(3), Q2(4), Q2(5) }; #undef Q2 /* apply exposure effect */ uint16_t ext_exposure = 0x0300; /* 0x0300: could be other value */ uint16_t exposure = (regs[M64282FP_C_HI] << 8) | regs[M64282FP_C_LO]; /* TODO: handle the zero-exposure case */ for (y = 0; y < M64282FP_SENSOR_H; ++y) { for (x = 0; x < M64282FP_SENSOR_W; ++x) { int v = img[y][x]; v = ((v * exposure) / ext_exposure); v = ((v - 128) / 8) + 128; /* adapt to 3.1V / 5V */ img[y][x] = clamp(v, 0, 255); } } /* invert image when I bit is set */ if (regs[M64282FP_E_I_V] & 0x8) { for (y = 0; y < M64282FP_SENSOR_H; ++y) { for (x = 0; x < M64282FP_SENSOR_W; ++x) { img[y][x] = 255 - img[y][x]; } } } /* make signed */ for (y = 0; y < M64282FP_SENSOR_H; ++y) { for (x = 0; x < M64282FP_SENSOR_W; ++x) { tmp[y][x] = img[y][x] - 128; } } unsigned int mode = (((regs[M64282FP_N_VH_G] & 0x80) >> 7) << 3) /* N */ | (((regs[M64282FP_N_VH_G] & 0x60) >> 5) << 1) /* VH */ | (((regs[M64282FP_E_I_V] & 0x80) >> 7) << 0); /* E3 */ int alpha = alpha_lut[(regs[M64282FP_E_I_V] & 0x70) >> 4]; switch(mode) { case 0x0: /* 0000: positive image */ do_1d_filtering(tmp, regs[M64282FP_P], regs[M64282FP_M]); break; case 0x1: /* 0001: undocumented - bug ??? */ memset(tmp, 0, sizeof(tmp)); break; case 0x2: /* 0010: horiz enhancement */ do_kernel_filtering(tmp, alpha, kernels[0]); do_1d_filtering(tmp, regs[M64282FP_P], regs[M64282FP_M]); break; case 0x3: /* 0011: horiz extraction */ do_kernel_filtering(tmp, alpha, kernels[1]); do_1d_filtering(tmp, regs[M64282FP_P], regs[M64282FP_M]); break; case 0xc: /* 1100: vert enhancement */ do_kernel_filtering(tmp, alpha, kernels[2]); break; case 0xd: /* 1101: vert extraction */ do_kernel_filtering(tmp, alpha, kernels[3]); break; case 0xe: /* 1110: 2D enhancement */ do_kernel_filtering(tmp, alpha, kernels[4]); break; case 0xf: /* 1111: 2D extraction */ do_kernel_filtering(tmp, alpha, kernels[5]); break; default: break; } /* back to 0..255 range */ for (y = 0; y < M64282FP_SENSOR_H; ++y) { for (x = 0; x < M64282FP_SENSOR_W; ++x) { img[y][x] = clamp(128 + tmp[y][x], 0, 255); } } /* gain and level control are not emulated */ } mupen64plus-core-src-2.6.0/src/device/gb/m64282fp.h000066400000000000000000000037661464506436200214410ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - m64282fp.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_GB_M64282FP_H #define M64P_DEVICE_GB_M64282FP_H #include enum { M64282FP_SENSOR_W = 128, M64282FP_SENSOR_H = 128, }; enum m64282fp_registers { M64282FP_Z_O, M64282FP_N_VH_G, M64282FP_C_LO, M64282FP_C_HI, M64282FP_P, M64282FP_M, M64282FP_X, M64282FP_E_I_V, M64282FP_REGS_COUNT }; void process_m64282fp_image( uint8_t img[M64282FP_SENSOR_H][M64282FP_SENSOR_W], const uint8_t regs[M64282FP_REGS_COUNT]); #endif mupen64plus-core-src-2.6.0/src/device/gb/mbc3_rtc.c000066400000000000000000000075661464506436200217420ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - mbc3_rtc.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "mbc3_rtc.h" #include "backends/api/clock_backend.h" #include /* TODO: halt bit is not implemented */ static void update_rtc_regs(struct mbc3_rtc* rtc) { /* compute elapsed time since last update */ time_t now = rtc->iclock->get_time(rtc->clock); time_t diff = now - rtc->last_time; rtc->last_time = now; /* increment regs */ if (diff > 0) { rtc->regs[MBC3_RTC_SECONDS] += (int)(diff % 60); if (rtc->regs[MBC3_RTC_SECONDS] >= 60) { rtc->regs[MBC3_RTC_SECONDS] -= 60; ++rtc->regs[MBC3_RTC_MINUTES]; } diff /= 60; rtc->regs[MBC3_RTC_MINUTES] += (int)(diff % 60); if (rtc->regs[MBC3_RTC_MINUTES] >= 60) { rtc->regs[MBC3_RTC_MINUTES] -= 60; ++rtc->regs[MBC3_RTC_HOURS]; } diff /= 60; rtc->regs[MBC3_RTC_HOURS] += (int)(diff % 24); if (rtc->regs[MBC3_RTC_HOURS] >= 24) { rtc->regs[MBC3_RTC_HOURS] -= 24; ++rtc->regs[MBC3_RTC_DAYS_L]; } diff /= 24; /* update days counter */ unsigned int days = (((rtc->regs[MBC3_RTC_DAYS_H] & 0x01) << 8) | rtc->regs[MBC3_RTC_DAYS_L]) + (int)diff; rtc->regs[MBC3_RTC_DAYS_L] = days & 0xff; rtc->regs[MBC3_RTC_DAYS_H] = (rtc->regs[MBC3_RTC_DAYS_H] & ~0x01) | (days & 0x100); /* set carry bit if days overflow */ if (days > 511) { rtc->regs[MBC3_RTC_DAYS_H] |= 0x80; } } } void init_mbc3_rtc(struct mbc3_rtc* rtc, void* clock, const struct clock_backend_interface* iclock) { rtc->clock = clock; rtc->iclock = iclock; } void poweron_mbc3_rtc(struct mbc3_rtc* rtc) { memset(rtc->regs, 0, MBC3_RTC_REGS_COUNT); memset(rtc->latched_regs, 0, MBC3_RTC_REGS_COUNT); rtc->latch = 0; rtc->last_time = 0; } uint8_t read_mbc3_rtc_regs(struct mbc3_rtc* rtc, unsigned int reg) { if (rtc->latch) { return rtc->latched_regs[reg]; } update_rtc_regs(rtc); return rtc->regs[reg]; } void write_mbc3_rtc_regs(struct mbc3_rtc* rtc, unsigned int reg, uint8_t value) { rtc->regs[reg] = value; } void latch_mbc3_rtc_regs(struct mbc3_rtc* rtc, uint8_t data) { if (rtc->latch == 0 && data == 1) { update_rtc_regs(rtc); memcpy(rtc->latched_regs, rtc->regs, MBC3_RTC_REGS_COUNT); } rtc->latch = data & 0x1; } mupen64plus-core-src-2.6.0/src/device/gb/mbc3_rtc.h000066400000000000000000000053601464506436200217350ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - mbc3_rtc.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_GB_MBC3_RTC_H #define M64P_DEVICE_GB_MBC3_RTC_H #include #include struct clock_backend_interface; enum mbc3_rtc_registers { MBC3_RTC_SECONDS, /* 0-59 */ MBC3_RTC_MINUTES, /* 0-59 */ MBC3_RTC_HOURS, /* 0-23 */ MBC3_RTC_DAYS_L, /* Days Counter is 16 bit wide */ MBC3_RTC_DAYS_H, /* bits 0-8: days counter (0-511) */ /* bits 9-13: zeros ? */ /* bits 14: halt (0: stop timer, 1: active timer) */ /* bits 15: carry (0: no overflow, 1: couter overflowed) */ MBC3_RTC_REGS_COUNT }; struct mbc3_rtc { uint8_t regs[MBC3_RTC_REGS_COUNT]; unsigned int latch; uint8_t latched_regs[MBC3_RTC_REGS_COUNT]; time_t last_time; void* clock; const struct clock_backend_interface* iclock; }; void init_mbc3_rtc(struct mbc3_rtc* rtc, void* clock, const struct clock_backend_interface* iclock); void poweron_mbc3_rtc(struct mbc3_rtc* rtc); uint8_t read_mbc3_rtc_regs(struct mbc3_rtc* rtc, unsigned int reg); void write_mbc3_rtc_regs(struct mbc3_rtc* rtc, unsigned int reg, uint8_t value); void latch_mbc3_rtc_regs(struct mbc3_rtc* rtc, uint8_t data); #endif mupen64plus-core-src-2.6.0/src/device/memory/000077500000000000000000000000001464506436200210045ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/memory/memory.c000066400000000000000000000236401464506436200224650ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - memory.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "memory.h" #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/device.h" #include "device/rcp/rsp/rsp_core.h" #include "device/pif/pif.h" #ifdef DBG #include #include "device/r4300/r4300_core.h" #include "debugger/dbg_breakpoints.h" #include "debugger/dbg_memory.h" #endif #include #include #include #include #ifdef _WIN32 #include #endif #ifdef DBG enum { BP_CHECK_READ = 0x1, BP_CHECK_WRITE = 0x2, }; void read_with_bp_checks(void* opaque, uint32_t address, uint32_t* value) { struct r4300_core* r4300 = (struct r4300_core*)opaque; uint16_t region = address >> 16; /* only check bp if active */ if (r4300->mem->bp_checks[region] & BP_CHECK_READ) { check_breakpoints_on_mem_access(*r4300_pc(r4300)-0x4, address, 4, M64P_BKP_FLAG_ENABLED | M64P_BKP_FLAG_READ); } mem_read32(&r4300->mem->saved_handlers[region], address, value); } void write_with_bp_checks(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct r4300_core* r4300 = (struct r4300_core*)opaque; uint16_t region = address >> 16; /* only check bp if active */ if (r4300->mem->bp_checks[region] & BP_CHECK_WRITE) { check_breakpoints_on_mem_access(*r4300_pc(r4300)-0x4, address, 4, M64P_BKP_FLAG_ENABLED | M64P_BKP_FLAG_WRITE); } mem_write32(&r4300->mem->saved_handlers[region], address, value, mask); } void activate_memory_break_read(struct memory* mem, uint32_t address) { uint16_t region = address >> 16; struct mem_handler* dbg_handler = &mem->dbg_handler; struct mem_handler* handler = &mem->handlers[region]; struct mem_handler* saved_handler = &mem->saved_handlers[region]; unsigned char* bp_check = &mem->bp_checks[region]; /* if neither read nor write bp is active, set dbg_handler */ if (!(*bp_check & (BP_CHECK_READ | BP_CHECK_WRITE))) { *saved_handler = *handler; *handler = *dbg_handler; } /* activate bp read */ *bp_check |= BP_CHECK_READ; } void deactivate_memory_break_read(struct memory* mem, uint32_t address) { uint16_t region = address >> 16; struct mem_handler* handler = &mem->handlers[region]; struct mem_handler* saved_handler = &mem->saved_handlers[region]; unsigned char* bp_check = &mem->bp_checks[region]; /* desactivate bp read */ *bp_check &= ~BP_CHECK_READ; /* if neither read nor write bp is active, restore handler */ if (!(*bp_check & (BP_CHECK_READ | BP_CHECK_WRITE))) { *handler = *saved_handler; } } void activate_memory_break_write(struct memory* mem, uint32_t address) { uint16_t region = address >> 16; struct mem_handler* dbg_handler = &mem->dbg_handler; struct mem_handler* handler = &mem->handlers[region]; struct mem_handler* saved_handler = &mem->saved_handlers[region]; unsigned char* bp_check = &mem->bp_checks[region]; /* if neither read nor write bp is active, set dbg_handler */ if (!(*bp_check & (BP_CHECK_READ | BP_CHECK_WRITE))) { *saved_handler = *handler; *handler = *dbg_handler; } /* activate bp write */ *bp_check |= BP_CHECK_WRITE; } void deactivate_memory_break_write(struct memory* mem, uint32_t address) { uint16_t region = address >> 16; struct mem_handler* handler = &mem->handlers[region]; struct mem_handler* saved_handler = &mem->saved_handlers[region]; unsigned char* bp_check = &mem->bp_checks[region]; /* desactivate bp write */ *bp_check &= ~BP_CHECK_WRITE; /* if neither read nor write bp is active, restore handler */ if (!(*bp_check & (BP_CHECK_READ | BP_CHECK_WRITE))) { *handler = *saved_handler; } } int get_memory_type(struct memory* mem, uint32_t address) { return mem->memtype[address >> 16]; } #else void read_with_bp_checks(void* opaque, uint32_t address, uint32_t* value) { } void write_with_bp_checks(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { } #endif void init_memory(struct memory* mem, struct mem_mapping* mappings, size_t mappings_count, void* base, struct mem_handler* dbg_handler) { size_t m; #ifdef DBG memset(mem->bp_checks, 0, 0x10000*sizeof(mem->bp_checks[0])); memcpy(&mem->dbg_handler, dbg_handler, sizeof(*dbg_handler)); #endif mem->base = base; for(m = 0; m < mappings_count; ++m) { apply_mem_mapping(mem, &mappings[m]); } } static void map_region(struct memory* mem, uint16_t region, int type, const struct mem_handler* handler) { #ifdef DBG /* set region type */ mem->memtype[region] = type; /* set handler */ if (lookup_breakpoint(((uint32_t)region << 16), 0x10000, M64P_BKP_FLAG_ENABLED) != -1) { mem->saved_handlers[region] = *handler; mem->handlers[region] = mem->dbg_handler; } else #endif { (void)type; mem->handlers[region] = *handler; } } void apply_mem_mapping(struct memory* mem, const struct mem_mapping* mapping) { size_t i; uint16_t begin = mapping->begin >> 16; uint16_t end = mapping->end >> 16; for (i = begin; i <= end; ++i) { map_region(mem, i, mapping->type, &mapping->handler); } } /* For paraLLEl-RDP which needs to import RDRAM as a host pointer with potentially 64k of alignment. */ enum { MB_RDRAM_DRAM_ALIGNMENT_REQUIREMENT = 64 * 1024 }; enum { MB_RDRAM_DRAM = 0, MB_CART_ROM = MB_RDRAM_DRAM + RDRAM_MAX_SIZE, MB_RSP_MEM = MB_CART_ROM + CART_ROM_MAX_SIZE, MB_DD_ROM = MB_RSP_MEM + SP_MEM_SIZE, MB_PIF_MEM = MB_DD_ROM + DD_ROM_MAX_SIZE, MB_MAX_SIZE = MB_PIF_MEM + PIF_ROM_SIZE + PIF_RAM_SIZE, MB_MAX_SIZE_FULL = 0x20000000 }; /* Use LSB of mem_base pointer to encode mem_base mode * 1: compressed, 0: full */ #define MEM_BASE_MODE(mem_base) ((uintptr_t)(mem_base) & 0x1) #define MEM_BASE_PTR(mem_base) ((void*)((uintptr_t)(mem_base) & ~0x1)) #define SET_MEM_BASE_MODE(mem_base) (mem_base = (void*)((uintptr_t)(mem_base) | 0x1)) void* init_mem_base(void) { void* mem_base; /* First try the full mem base alloc */ #ifdef _WIN32 mem_base = _aligned_malloc(MB_MAX_SIZE_FULL, MB_RDRAM_DRAM_ALIGNMENT_REQUIREMENT); #else if (posix_memalign(&mem_base, MB_RDRAM_DRAM_ALIGNMENT_REQUIREMENT, MB_MAX_SIZE_FULL) != 0) mem_base = NULL; #endif if (mem_base == NULL) { /* if it failed, try the compressed mem base alloc */ mem_base = malloc(MB_MAX_SIZE); if (mem_base != NULL) { /* Compressed mem base mode has LSB = 1 */ assert(MEM_BASE_MODE(mem_base) == 0); SET_MEM_BASE_MODE(mem_base); DebugMessage(M64MSG_INFO, "Using compressed mem base"); } } else { /* Full mem base mode has LSB = 0 */ assert(MEM_BASE_MODE(mem_base) == 0); DebugMessage(M64MSG_INFO, "Using full mem base"); } return mem_base; } void release_mem_base(void* mem_base) { #ifdef _WIN32 if (MEM_BASE_MODE(mem_base) == 0) _aligned_free(MEM_BASE_PTR(mem_base)); else #endif free(MEM_BASE_PTR(mem_base)); } uint32_t* mem_base_u32(void* mem_base, uint32_t address) { uint32_t* mem; if (MEM_BASE_MODE(mem_base) == 0) { /* In full mem base mode, use simple pointer arithmetic */ mem = (uint32_t*)((uint8_t*)mem_base + address); } else { /* In compressed mem base mode, select appropriate mem_base offset */ mem_base = MEM_BASE_PTR(mem_base); if (address < RDRAM_MAX_SIZE) { mem = (uint32_t*)((uint8_t*)mem_base + (address - MM_RDRAM_DRAM + MB_RDRAM_DRAM)); } else if (address >= MM_CART_ROM) { if ((address & UINT32_C(0xfff00000)) == MM_PIF_MEM) { mem = (uint32_t*)((uint8_t*)mem_base + (address - MM_PIF_MEM + MB_PIF_MEM)); } else { mem = (uint32_t*)((uint8_t*)mem_base + (address - MM_CART_ROM + MB_CART_ROM)); } } else if ((address & UINT32_C(0xfe000000)) == MM_DD_ROM) { mem = (uint32_t*)((uint8_t*)mem_base + (address - MM_DD_ROM + MB_DD_ROM)); } else if ((address & UINT32_C(0xffffe000)) == MM_RSP_MEM) { mem = (uint32_t*)((uint8_t*)mem_base + (address - MM_RSP_MEM + MB_RSP_MEM)); } else { mem = NULL; } } return mem; } mupen64plus-core-src-2.6.0/src/device/memory/memory.h000066400000000000000000000075471464506436200225020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - memory.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_MEMORY_MEMORY_H #define M64P_DEVICE_MEMORY_MEMORY_H #include #include #include "osal/preproc.h" enum { RDRAM_MAX_SIZE = 0x800000 }; enum { CART_ROM_MAX_SIZE = 0x4000000 }; enum { DD_ROM_MAX_SIZE = 0x400000 }; typedef void (*read32fn)(void*,uint32_t,uint32_t*); typedef void (*write32fn)(void*,uint32_t,uint32_t,uint32_t); struct mem_handler { void* opaque; read32fn read32; write32fn write32; }; struct mem_mapping { uint32_t begin; uint32_t end; /* inclusive */ int type; struct mem_handler handler; }; struct memory { struct mem_handler handlers[0x10000]; void* base; #ifdef DBG int memtype[0x10000]; unsigned char bp_checks[0x10000]; struct mem_handler saved_handlers[0x10000]; struct mem_handler dbg_handler; #endif }; static osal_inline void masked_write(uint32_t* dst, uint32_t value, uint32_t mask) { *dst = (*dst & ~mask) | (value & mask); } void init_memory(struct memory* mem, struct mem_mapping* mappings, size_t mappings_count, void* base, struct mem_handler* dbg_handler); static osal_inline const struct mem_handler* mem_get_handler(const struct memory* mem, uint32_t address) { return &mem->handlers[address >> 16]; } static osal_inline void mem_read32(const struct mem_handler* handler, uint32_t address, uint32_t* value) { handler->read32(handler->opaque, address, value); } static osal_inline void mem_write32(const struct mem_handler* handler, uint32_t address, uint32_t value, uint32_t mask) { handler->write32(handler->opaque, address, value, mask); } void apply_mem_mapping(struct memory* mem, const struct mem_mapping* mapping); void* init_mem_base(void); void release_mem_base(void* mem_base); uint32_t* mem_base_u32(void* mem_base, uint32_t address); void read_with_bp_checks(void* opaque, uint32_t address, uint32_t* value); void write_with_bp_checks(void* opaque, uint32_t address, uint32_t value, uint32_t mask); #ifdef DBG void activate_memory_break_read(struct memory* mem, uint32_t address); void deactivate_memory_break_read(struct memory* mem, uint32_t address); void activate_memory_break_write(struct memory* mem, uint32_t address); void deactivate_memory_break_write(struct memory* mem, uint32_t address); int get_memory_type(struct memory* mem, uint32_t address); #endif #endif mupen64plus-core-src-2.6.0/src/device/pif/000077500000000000000000000000001464506436200202525ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/pif/bootrom_hle.c000066400000000000000000000150301464506436200227260ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - bootrom_hle.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "bootrom_hle.h" #include #include #include "api/m64p_types.h" #include "device/device.h" #include "device/r4300/r4300_core.h" #include "device/rcp/ai/ai_controller.h" #include "device/rcp/pi/pi_controller.h" #include "device/rcp/rsp/rsp_core.h" #include "device/rcp/si/si_controller.h" #include "device/rcp/vi/vi_controller.h" #include "main/rom.h" static unsigned int get_tv_type(void) { switch(ROM_PARAMS.systemtype) { default: case SYSTEM_NTSC: return 1; case SYSTEM_PAL: return 0; case SYSTEM_MPAL: return 2; } } void pif_bootrom_hle_execute(struct r4300_core* r4300) { if (r4300->start_address == 0xbfc00000) return; uint32_t pif24; unsigned int seed; /* seed (depends on CIC version) */ unsigned int rom_type; /* 0:Cart, 1:DD */ unsigned int reset_type; /* 0:ColdReset, 1:NMI */ unsigned int s7; /* ??? */ uint32_t bsd_dom1_config; unsigned int tv_type = get_tv_type(); /* 0:PAL, 1:NTSC, 2:MPAL */ int64_t* r4300_gpregs = r4300_regs(r4300); uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); /* setup CP0 registers */ cp0_regs[CP0_STATUS_REG] = 0x34000000; cp0_regs[CP0_CONFIG_REG] = 0x7006e463; /* XXX: wait for SP to finish last operation (poll halt) */ /* stop RSP (halt + clear interrupts) */ r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_RSP_REGS + 4*SP_STATUS_REG, 0x0a, ~UINT32_C(0)); /* XXX: wait for SP DMA to finish (poll busy) */ /* stop PI (reset, clear interrupt) */ r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_PI_REGS + 4*PI_STATUS_REG, 0x3, ~UINT32_C(0)); /* blank screen */ r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_VI_REGS + 4*VI_V_INTR_REG, 1023, ~UINT32_C(0)); r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_VI_REGS + 4*VI_CURRENT_REG, 0, ~UINT32_C(0)); r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_VI_REGS + 4*VI_H_START_REG, 0, ~UINT32_C(0)); /* mute sound */ r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_AI_REGS + 4*AI_DRAM_ADDR_REG, 0, ~UINT32_C(0)); r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_AI_REGS + 4*AI_LEN_REG, 0, ~UINT32_C(0)); /* XXX: wait for SP DMA to finish (poll busy) */ /* XXX: copy IPL2 to IMEM (partialy done later as required by CIC x105) * and transfer execution to IPL2 */ /* XXX: wait for PIF_3c[7] to be cleared */ /* read and parse pif24 */ r4300_read_aligned_word(r4300, R4300_KSEG1 + MM_PIF_MEM + PIF_ROM_SIZE + 0x24, &pif24); rom_type = (pif24 >> 19) & 0x01; s7 = (pif24 >> 18) & 0x01; reset_type = (pif24 >> 17) & 0x01; seed = (pif24 >> 8) & 0xff; /* setup s3-s7 registers (needed by OS) */ r4300_gpregs[19] = rom_type; /* s3 */ r4300_gpregs[20] = tv_type; /* s4 */ r4300_gpregs[21] = reset_type; /* s5 */ r4300_gpregs[22] = seed; /* s6 */ r4300_gpregs[23] = s7; /* s7 */ /* XXX: wait for SI_RD_BUSY to be cleared, set PIF_3c[4] */ /* configure ROM access * XXX: we skip the first temporary configuration */ uint32_t rom_base = (rom_type == 0) ? MM_CART_ROM : MM_DD_ROM; r4300_read_aligned_word(r4300, R4300_KSEG1 + rom_base, &bsd_dom1_config); r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_PI_REGS + 4*PI_BSD_DOM1_LAT_REG, (bsd_dom1_config ) & 0xff, ~UINT32_C(0)); r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_PI_REGS + 4*PI_BSD_DOM1_PWD_REG, (bsd_dom1_config >> 8) & 0xff, ~UINT32_C(0)); r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_PI_REGS + 4*PI_BSD_DOM1_PGS_REG, (bsd_dom1_config >> 16) & 0x0f, ~UINT32_C(0)); r4300_write_aligned_word(r4300, R4300_KSEG1 + MM_PI_REGS + 4*PI_BSD_DOM1_RLS_REG, (bsd_dom1_config >> 20) & 0x03, ~UINT32_C(0)); /* XXX: if XBus is used, wait until DPC_pipe_busy is cleared */ /* copy IPL3 to dmem */ memcpy((unsigned char*)mem_base_u32(r4300->mem->base, MM_RSP_MEM + 0x40), (unsigned char*)mem_base_u32(r4300->mem->base, rom_base + 0x40), 0xfc0); /* XXX: compute IPL3 checksum */ /* XXX: wait for SI_RD_BUSY to be cleared, set PIF_30 */ /* XXX: wait for SI_RD_BUSY to be cleared, set PIF_34 */ /* XXX: wait for SI_RD_BUSY to be cleared, set PIF_3c[5] */ /* XXX: wait for PIF_3c[7] to be set */ /* XXX: wait for SI_RD_BUSY to be cleared, set PIF_3c[6] */ /* required by CIC x105 */ uint32_t* imem = mem_base_u32(r4300->mem->base, MM_RSP_MEM + 0x1000); imem[0x0000/4] = 0x3c0dbfc0; imem[0x0004/4] = 0x8da807fc; imem[0x0008/4] = 0x25ad07c0; imem[0x000c/4] = 0x31080080; imem[0x0010/4] = 0x5500fffc; imem[0x0014/4] = 0x3c0dbfc0; imem[0x0018/4] = 0x8da80024; imem[0x001c/4] = 0x3c0bb000; /* required by CIC x105 */ r4300_gpregs[11] = INT64_C(0xffffffffa4000040); /* t3 */ r4300_gpregs[29] = INT64_C(0xffffffffa4001ff0); /* sp */ r4300_gpregs[31] = INT64_C(0xffffffffa4001550); /* ra */ /* XXX: should prepare execution of IPL3 in DMEM here : * e.g. jump to 0xa4000040 */ *r4300_cp0_last_addr(&r4300->cp0) = 0xa4000040; } mupen64plus-core-src-2.6.0/src/device/pif/bootrom_hle.h000066400000000000000000000034261464506436200227410ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - bootrom_hle.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2016 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_PIF_BOOTROM_HLE_H #define M64P_DEVICE_PIF_BOOTROM_HLE_H struct r4300_core; /* Simulates end result of PIFBootROM execution. * This bypasses entirely the execution of real PIFBootROM */ void pif_bootrom_hle_execute(struct r4300_core* r4300); #endif mupen64plus-core-src-2.6.0/src/device/pif/cic.c000066400000000000000000000064751464506436200211700ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cic.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "cic.h" #include #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #define __STDC_FORMAT_MACROS #include void init_cic_using_ipl3(struct cic* cic, const void* ipl3) { size_t i; uint64_t crc = 0; static const struct cic cics[] = { { "5101", CIC_5101, 0xac }, { "X101", CIC_X101, 0x3f }, { "X102", CIC_X102, 0x3f }, { "X103", CIC_X103, 0x78 }, { "X105", CIC_X105, 0x91 }, { "X106", CIC_X106, 0x85 }, { "5167", CIC_5167, 0xdd }, { "8303", CIC_8303, 0xdd }, { "8401", CIC_8401, 0xdd }, { "8501", CIC_8501, 0xde } }; for (i = 0; i < 0xfc0/4; i++) crc += ((uint32_t*)ipl3)[i]; switch(crc) { default: DebugMessage(M64MSG_WARNING, "Unknown CIC type (%016" PRIX64 ")! using CIC 6102.", crc); /* fall through */ case UINT64_C(0x000000D057C85244): i = 2; break; /* CIC_X102 */ case UINT64_C(0x000000D0027FDF31): /* CIC_X101 */ case UINT64_C(0x000000CFFB631223): i = 1; break; /* CIC_X101 */ case UINT64_C(0x000000D6497E414B): i = 3; break; /* CIC_X103 */ case UINT64_C(0x0000011A49F60E96): i = 4; break; /* CIC_X105 */ case UINT64_C(0x000000D6D5BE5580): i = 5; break; /* CIC_X106 */ case UINT64_C(0x000001053BC19870): i = 6; break; /* CIC 5167 */ case UINT64_C(0x000000A5F80BF620): i = 0; break; /* CIC 5101 */ case UINT64_C(0x000000D2E53EF008): i = 7; break; /* CIC 8303 */ case UINT64_C(0x000000D2E53EF39F): i = 8; break; /* CIC 8401 */ case UINT64_C(0x000000D2E53E5DDA): i = 9; break; /* CIC 8501 */ } memcpy(cic, &cics[i], sizeof(*cic)); DebugMessage(M64MSG_INFO, "Using CIC type %s", cic->name); } mupen64plus-core-src-2.6.0/src/device/pif/cic.h000066400000000000000000000036041464506436200211640ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cic.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_CIC_H #define M64P_DEVICE_SI_CIC_H enum cic_version { CIC_X101, CIC_X102, CIC_X103, CIC_X105, CIC_X106, CIC_5101, CIC_5167, CIC_8303, CIC_8401, CIC_8501 }; struct cic { const char* name; enum cic_version version; unsigned int seed; }; void init_cic_using_ipl3(struct cic* cic, const void* ipl3); #endif mupen64plus-core-src-2.6.0/src/device/pif/n64_cic_nus_6105.c000066400000000000000000000140031464506436200232010ustar00rootroot00000000000000/* * Copyright 2011 X-Scale. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY X-Scale ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL X-Scale OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of X-Scale. * * This software provides an algorithm that emulates the protection scheme of * N64 PIF/CIC-NUS-6105, by determining the proper response to each challenge. * It was synthesized after a careful, exhaustive and detailed analysis of the * challenge/response pairs stored in the 'pif2.dat' file from Project 64. * These challenge/response pairs were the only resource used during this * project. There was no kind of physical access to N64 hardware. * * This project would have never been possible without the contribuitions of * the following individuals and organizations: * * - Oman: For being at the right place at the right time and being brave * enough to pay a personal price so we could understand in a much deeper * way how this magical console really works. We owe you so much. * * - Jovis: For all the positive energy and impressive hacking spirit that you * shared with the N64 community. You were absolutely instrumental in * several key events that shaped the N64 community in the last 14 years. * Even if you're not physically with us anymore, your heritage, your * knowledge and your attitude will never be forgotten. * * 'The candle that burns twice as bright burns half as long.' * * - LaC: For the endless contributions that you've given to the N64 community * since the early days, when N64 was the next big thing. I've always * admired the deep knowledge that you've gathered about the most little * hardware details. Recently, you challanged us to find a small and * concise algorithm that would emulate the behaviour of CIC-NUS-6105 * challenge/response protection scheme and here is the final result. * LaC, Oman and Jovis were definitly the dream team of N64 reversing in * the late 90's. Without your contributions, we would be much poorer. * * - marshall: For keeping the N64 scene alive during the last decade, when * most people lost interest and moved along to different projects. You * are the force that has been keeping us all together in the later * years. When almost nobody cared about N64 anymore, you were always * there, spreading the word, developing in the console, and lately, * making impressive advances on the hardware side. I wish the best * success to your new 64drive project. * * - hcs: For your contributions to the better understanding of the inner * workings of the Reality Co-Processor (RCP). Your skills have impressed * me for a long time now. And without your precious help by sharing your * kownledge, I would have never understood the immense importance of * Oman, Jovis and LaC achievements. Thank you ! * * - Azimer & Tooie: For sharing with the N64 community your findings about the * challenge/response pair used in 'Jet Force Gemini' and the 267 * challenge/response pairs used in 'Banjo Tooie', all stored in the * 'pif2.dat' file of Project 64. They were instrumental to the final * success of this endeavour. * * - Silicon Graphics, Inc. (SGI): For creating MIPS R4000, MIPS R4300 and * Reality Co-Processor (RCP). You were the ultimate dream creator during * the late 80's and early 90's. A very special word of gratitude goes to * the two teams that during those years created RCP and MIPS R4300. They * were technological breakthroughs back then. * * On a personal note, I would like to show my deepest gratitude to _Bijou_, * for being always a source of endless hope and inspiration. * * -= X-Scale =- (#n64dev@EFnet) */ #include "n64_cic_nus_6105.h" void n64_cic_nus_6105(char chl[], char rsp[], int len) { static const char lut0[0x10] = { 0x4, 0x7, 0xA, 0x7, 0xE, 0x5, 0xE, 0x1, 0xC, 0xF, 0x8, 0xF, 0x6, 0x3, 0x6, 0x9 }; static const char lut1[0x10] = { 0x4, 0x1, 0xA, 0x7, 0xE, 0x5, 0xE, 0x1, 0xC, 0x9, 0x8, 0x5, 0x6, 0x3, 0xC, 0x9 }; char key; const char* lut; int i, sgn, mag, mod; for (key = 0xB, lut = lut0, i = 0; i < len; i++) { rsp[i] = (key + 5 * chl[i]) & 0xF; key = lut[(int) rsp[i]]; sgn = (rsp[i] >> 3) & 0x1; mag = ((sgn == 1) ? ~rsp[i] : rsp[i]) & 0x7; mod = (mag % 3 == 1) ? sgn : 1 - sgn; if (lut == lut1 && (rsp[i] == 0x1 || rsp[i] == 0x9)) mod = 1; if (lut == lut1 && (rsp[i] == 0xB || rsp[i] == 0xE)) mod = 0; lut = (mod == 1) ? lut1 : lut0; } } mupen64plus-core-src-2.6.0/src/device/pif/n64_cic_nus_6105.h000066400000000000000000000124251464506436200232140ustar00rootroot00000000000000/* * Copyright 2011 X-Scale. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY X-Scale ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL X-Scale OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of X-Scale. * * This software provides an algorithm that emulates the protection scheme of * N64 PIF/CIC-NUS-6105, by determining the proper response to each challenge. * It was synthesized after a careful, exhaustive and detailed analysis of the * challenge/response pairs stored in the 'pif2.dat' file from Project 64. * These challenge/response pairs were the only resource used during this * project. There was no kind of physical access to N64 hardware. * * This project would have never been possible without the contribuitions of * the following individuals and organizations: * * - Oman: For being at the right place at the right time and being brave * enough to pay a personal price so we could understand in a much deeper * way how this magical console really works. We owe you so much. * * - Jovis: For all the positive energy and impressive hacking spirit that you * shared with the N64 community. You were absolutely instrumental in * several key events that shaped the N64 community in the last 14 years. * Even if you're not physically with us anymore, your heritage, your * knowledge and your attitude will never be forgotten. * * 'The candle that burns twice as bright burns half as long.' * * - LaC: For the endless contributions that you've given to the N64 community * since the early days, when N64 was the next big thing. I've always * admired the deep knowledge that you've gathered about the most little * hardware details. Recently, you challanged us to find a small and * concise algorithm that would emulate the behaviour of CIC-NUS-6105 * challenge/response protection scheme and here is the final result. * LaC, Oman and Jovis were definitly the dream team of N64 reversing in * the late 90's. Without your contributions, we would be much poorer. * * - marshall: For keeping the N64 scene alive during the last decade, when * most people lost interest and moved along to different projects. You * are the force that has been keeping us all together in the later * years. When almost nobody cared about N64 anymore, you were always * there, spreading the word, developing in the console, and lately, * making impressive advances on the hardware side. I wish the best * success to your new 64drive project. * * - hcs: For your contributions to the better understanding of the inner * workings of the Reality Co-Processor (RCP). Your skills have impressed * me for a long time now. And without your precious help by sharing your * kownledge, I would have never understood the immense importance of * Oman, Jovis and LaC achievements. Thank you ! * * - Azimer & Tooie: For sharing with the N64 community your findings about the * challenge/response pair used in 'Jet Force Gemini' and the 267 * challenge/response pairs used in 'Banjo Tooie', all stored in the * 'pif2.dat' file of Project 64. They were instrumental to the final * success of this endeavour. * * - Silicon Graphics, Inc. (SGI): For creating MIPS R4000, MIPS R4300 and * Reality Co-Processor (RCP). You were the ultimate dream creator during * the late 80's and early 90's. A very special word of gratitude goes to * the two teams that during those years created RCP and MIPS R4300. They * were technological breakthroughs back then. * * On a personal note, I would like to show my deepest gratitude to _Bijou_, * for being always a source of endless hope and inspiration. * * -= X-Scale =- (#n64dev@EFnet) */ #ifndef N64_CIC_NUS_6105_H #define N64_CIC_NUS_6105_H #define CHL_LEN 0x20 void n64_cic_nus_6105(char chl[], char rsp[], int len); #endif /* N64_CIC_NUS_6105_H */ mupen64plus-core-src-2.6.0/src/device/pif/pif.c000066400000000000000000000255441464506436200212060ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - pif.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "pif.h" #include "n64_cic_nus_6105.h" #include #include #include #include "api/callbacks.h" #include "api/m64p_plugin.h" #include "api/m64p_types.h" #include "backends/api/joybus.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rcp/si/si_controller.h" #include "plugin/plugin.h" #include "main/netplay.h" #define __STDC_FORMAT_MACROS #include //#define DEBUG_PIF #ifdef DEBUG_PIF void print_pif(struct pif* pif) { int i; for (i=0; i<(64/8); i++) { DebugMessage(M64MSG_INFO, "%02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8 " | %02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8, pif->ram[i*8+0], pif->ram[i*8+1],pif->ram[i*8+2], pif->ram[i*8+3], pif->ram[i*8+4], pif->ram[i*8+5],pif->ram[i*8+6], pif->ram[i*8+7]); } for(i = 0; i < PIF_CHANNELS_COUNT; ++i) { if (pif->channels[i].tx != NULL) { DebugMessage(M64MSG_INFO, "Channel %u, tx=%02x rx=%02x cmd=%02x", i, *(pif->channels[i].tx), *(pif->channels[i].rx), pif->channels[i].tx_buf[0]); } } } #endif static void process_channel(struct pif_channel* channel) { /* don't process channel if it has been disabled */ if (channel->tx == NULL) { return; } /* reset Tx/Rx just in case */ *channel->tx &= 0x3f; *channel->rx &= 0x3f; /* set NoResponse if no device is connected */ if (channel->ijbd == NULL) { *channel->rx |= 0x80; return; } /* do device processing */ channel->ijbd->process(channel->jbd, channel->tx, channel->tx_buf, channel->rx, channel->rx_buf); } static void post_setup_channel(struct pif_channel* channel) { if ((channel->ijbd == NULL) || (channel->ijbd->post_setup == NULL)) { return; } channel->ijbd->post_setup(channel->jbd, channel->tx, channel->tx_buf, channel->rx, channel->rx_buf); } void disable_pif_channel(struct pif_channel* channel) { channel->tx = NULL; channel->rx = NULL; channel->tx_buf = NULL; channel->rx_buf = NULL; } size_t setup_pif_channel(struct pif_channel* channel, uint8_t* buf) { uint8_t tx = buf[0] & 0x3f; uint8_t rx = buf[1] & 0x3f; /* XXX: check out of bounds accesses */ channel->tx = buf; channel->rx = buf + 1; channel->tx_buf = buf + 2; channel->rx_buf = buf + 2 + tx; post_setup_channel(channel); return 2 + tx + rx; } void init_pif(struct pif* pif, uint8_t* pif_base, void* jbds[PIF_CHANNELS_COUNT], const struct joybus_device_interface* ijbds[PIF_CHANNELS_COUNT], const uint8_t* ipl3, struct r4300_core* r4300, struct si_controller* si) { size_t i; pif->base = pif_base; pif->ram = pif_base + 0x7c0; for (i = 0; i < PIF_CHANNELS_COUNT; ++i) { pif->channels[i].jbd = jbds[i]; pif->channels[i].ijbd = ijbds[i]; } init_cic_using_ipl3(&pif->cic, ipl3); pif->r4300 = r4300; pif->si = si; } void reset_pif(struct pif* pif, unsigned int reset_type) { size_t i; /* HACK: for allowing pifbootrom execution */ unsigned int rom_type = (pif->cic.version == CIC_8303 || pif->cic.version == CIC_8401 || pif->cic.version == CIC_8501) ? 1 : 0; unsigned int s7 = 0; /* 0:ColdReset, 1:NMI */ assert((reset_type & ~0x1) == 0); /* disable channel processing */ for (i = 0; i < PIF_CHANNELS_COUNT; ++i) { disable_pif_channel(&pif->channels[i]); } /* set PIF_24 with reset informations */ uint32_t* pif24 = (uint32_t*)(pif->ram + 0x24); *pif24 = (uint32_t) (((rom_type & 0x1) << 19) | ((s7 & 0x1) << 18) | ((reset_type & 0x1) << 17) | ((pif->cic.seed & 0xff) << 8) | 0x3f); *pif24 = fromhl(*pif24); /* clear PIF flags */ pif->ram[0x3f] = 0x00; } void setup_channels_format(struct pif* pif) { size_t i = 0; size_t k = 0; while (i < PIF_RAM_SIZE && k < PIF_CHANNELS_COUNT) { switch(pif->ram[i]) { case 0x00: /* skip channel */ disable_pif_channel(&pif->channels[k++]); ++i; break; case 0xff: /* dummy data */ ++i; break; case 0xfe: /* end of channel setup - remaining channels are disabled */ while (k < PIF_CHANNELS_COUNT) { disable_pif_channel(&pif->channels[k++]); } break; case 0xfd: /* channel reset - send reset command and discard the results */ { static uint8_t dummy_reset_buffer[PIF_CHANNELS_COUNT][6]; /* setup reset command Tx=1, Rx=3, cmd=0xff */ dummy_reset_buffer[k][0] = 0x01; dummy_reset_buffer[k][1] = 0x03; dummy_reset_buffer[k][2] = 0xff; setup_pif_channel(&pif->channels[k], dummy_reset_buffer[k]); ++k; ++i; } break; default: /* setup channel */ /* HACK?: some games sends bogus PIF commands while accessing controller paks * Yoshi Story, Top Gear Rally 2, Indiana Jones, ... * When encountering such commands, we skip this bogus byte. */ if ((i+1 < PIF_RAM_SIZE) && (pif->ram[i+1] == 0xfe)) { ++i; continue; } if ((i + 2) >= PIF_RAM_SIZE) { DebugMessage(M64MSG_WARNING, "Truncated PIF command ! Stopping PIF channel processing"); i = PIF_RAM_SIZE; continue; } i += setup_pif_channel(&pif->channels[k++], &pif->ram[i]); } } /* Zilmar-Spec plugin expect a call with control_id = -1 when RAM processing is done */ if (input.controllerCommand) { input.controllerCommand(-1, NULL); } #ifdef DEBUG_PIF DebugMessage(M64MSG_INFO, "PIF setup channel"); print_pif(pif); #endif } static void process_cic_challenge(struct pif* pif) { char challenge[30], response[30]; size_t i; /* format the 'challenge' message into 30 nibbles for X-Scale's CIC code */ for (i = 0; i < 15; ++i) { challenge[i*2] = (pif->ram[0x30+i] >> 4) & 0x0f; challenge[i*2+1] = pif->ram[0x30+i] & 0x0f; } /* calculate the proper response for the given challenge (X-Scale's algorithm) */ n64_cic_nus_6105(challenge, response, CHL_LEN - 2); pif->ram[0x2e] = 0; pif->ram[0x2f] = 0; /* re-format the 'response' into a byte stream */ for (i = 0; i < 15; ++i) { pif->ram[0x30+i] = (response[i*2] << 4) + response[i*2+1]; } #ifdef DEBUG_PIF DebugMessage(M64MSG_INFO, "PIF cic challenge"); print_pif(pif); #endif } void poweron_pif(struct pif* pif) { memset(pif->ram, 0, PIF_RAM_SIZE); reset_pif(pif, 0); /* cold reset */ } void read_pif_mem(void* opaque, uint32_t address, uint32_t* value) { struct pif* pif = (struct pif*)opaque; uint32_t addr = pif_address(address); memcpy(value, pif->base + addr, sizeof(*value)); if (addr >= PIF_ROM_SIZE) *value = tohl(*value); } void write_pif_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct pif* pif = (struct pif*)opaque; uint32_t addr = pif_address(address); if (addr < PIF_ROM_SIZE) { DebugMessage(M64MSG_ERROR, "Invalid write to PIF ROM: %08" PRIX32, address); return; } masked_write((uint32_t*)(&pif->base[addr]), fromhl(value), fromhl(mask)); pif->si->dma_dir = SI_DMA_WRITE; cp0_update_count(pif->r4300); pif->si->regs[SI_STATUS_REG] |= (SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY); add_interrupt_event(&pif->r4300->cp0, SI_INT, pif->si->dma_duration); } void process_pif_ram(struct pif* pif) { uint8_t flags = pif->ram[0x3f]; uint8_t clrmask = 0x00; size_t k; if (flags == 0) { #ifdef DEBUG_PIF DebugMessage(M64MSG_INFO, "PIF process pif ram status=0x00"); print_pif(pif); #endif return; } if (flags & 0x01) { /* setup channels then clear format flag */ setup_channels_format(pif); clrmask |= 0x01; } if (flags & 0x02) { /* disable channel processing when doing CIC challenge */ for (k = 0; k < PIF_CHANNELS_COUNT; ++k) { disable_pif_channel(&pif->channels[k]); } /* CIC Challenge */ process_cic_challenge(pif); clrmask |= 0x02; } if (flags & 0x08) { clrmask |= 0x08; } if (flags & 0x30) { pif->ram[0x3f] = 0x80; } #ifdef DEBUG_PIF if (flags & 0xf4) { DebugMessage(M64MSG_ERROR, "error in process_pif_ram(): %" PRIX8, flags); } #endif pif->ram[0x3f] &= ~clrmask; } void update_pif_ram(struct pif* pif) { size_t k; /* perform PIF/Channel communications */ for (k = 0; k < PIF_CHANNELS_COUNT; ++k) { process_channel(&pif->channels[k]); } /* Zilmar-Spec plugin expect a call with control_id = -1 when RAM processing is done */ if (input.readController) { input.readController(-1, NULL); } netplay_update_input(pif); #ifdef DEBUG_PIF DebugMessage(M64MSG_INFO, "PIF post read"); print_pif(pif); #endif } void hw2_int_handler(void* opaque) { struct pif* pif = (struct pif*)opaque; raise_maskable_interrupt(pif->r4300, CP0_CAUSE_IP4); } mupen64plus-core-src-2.6.0/src/device/pif/pif.h000066400000000000000000000060241464506436200212030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - pif.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_SI_PIF_H #define M64P_DEVICE_SI_PIF_H #include #include #include "cic.h" #include "osal/preproc.h" struct joybus_device_interface; struct r4300_core; struct si_controller; enum { PIF_ROM_SIZE = 0x7c0 }; enum { PIF_RAM_SIZE = 0x40 }; enum { PIF_CHANNELS_COUNT = 5 }; struct pif_channel { void* jbd; const struct joybus_device_interface* ijbd; uint8_t* tx; uint8_t* tx_buf; uint8_t* rx; uint8_t* rx_buf; }; void disable_pif_channel(struct pif_channel* channel); size_t setup_pif_channel(struct pif_channel* channel, uint8_t* buf); struct pif { uint8_t* base; uint8_t* ram; struct pif_channel channels[PIF_CHANNELS_COUNT]; struct cic cic; struct r4300_core* r4300; struct si_controller* si; }; static osal_inline uint32_t pif_address(uint32_t address) { return (address & 0xfffc); } void init_pif(struct pif* pif, uint8_t* pif_base, void* jbds[PIF_CHANNELS_COUNT], const struct joybus_device_interface* ijbds[PIF_CHANNELS_COUNT], const uint8_t* ipl3, struct r4300_core* r4300, struct si_controller* si); void poweron_pif(struct pif* pif); void reset_pif(struct pif* pif, unsigned int reset_type); void setup_channels_format(struct pif* pif); void read_pif_mem(void* opaque, uint32_t address, uint32_t* value); void write_pif_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void process_pif_ram(struct pif* pif); void update_pif_ram(struct pif* pif); void hw2_int_handler(void* opaque); #endif mupen64plus-core-src-2.6.0/src/device/r4300/000077500000000000000000000000001464506436200202445ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/cached_interp.c000066400000000000000000000776751464506436200232260ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cached_interp.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "cached_interp.h" #include #include #include #define __STDC_FORMAT_MACROS #include #include #include "api/callbacks.h" #include "api/debugger.h" #include "api/m64p_types.h" #include "device/r4300/r4300_core.h" #include "device/r4300/idec.h" #include "main/main.h" #include "osal/preproc.h" #ifdef DBG #include "debugger/dbg_debugger.h" #endif // ----------------------------------------------------------- // Cached interpreter functions (and fallback for dynarec). // ----------------------------------------------------------- #ifdef DBG #define UPDATE_DEBUGGER() if (g_DebuggerActive) update_debugger(*r4300_pc(r4300)) #else #define UPDATE_DEBUGGER() do { } while(0) #endif #define DECLARE_R4300 struct r4300_core* r4300 = &g_dev.r4300; #define PCADDR *r4300_pc(r4300) #ifdef NEW_DYNAREC #define ADD_TO_PC(x) \ if (r4300->emumode != EMUMODE_DYNAREC) \ (*r4300_pc_struct(r4300)) += x; \ else \ { \ assert(*r4300_pc_struct(r4300) == &r4300->new_dynarec_hot_state.fake_pc); \ r4300->new_dynarec_hot_state.pcaddr += x*4; \ } #else #define ADD_TO_PC(x) (*r4300_pc_struct(r4300)) += x; #endif #define DECLARE_INSTRUCTION(name) void cached_interp_##name(void) #define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \ void cached_interp_##name(void) \ { \ DECLARE_R4300 \ const int take_jump = (condition); \ const uint32_t jump_target = (destination); \ int64_t *link_register = (link); \ if (cop1 && check_cop1_unusable(r4300)) return; \ if (link_register != &r4300_regs(r4300)[0]) \ { \ *link_register = SE32(*r4300_pc(r4300) + 8); \ } \ if (!likely || take_jump) \ { \ (*r4300_pc_struct(r4300))++; \ r4300->delay_slot=1; \ UPDATE_DEBUGGER(); \ (*r4300_pc_struct(r4300))->ops(); \ cp0_update_count(r4300); \ r4300->delay_slot=0; \ if (take_jump && !r4300->skip_jump) \ { \ (*r4300_pc_struct(r4300))=r4300->cached_interp.actual->block+((jump_target-r4300->cached_interp.actual->start)>>2); \ } \ } \ else \ { \ (*r4300_pc_struct(r4300)) += 2; \ cp0_update_count(r4300); \ } \ r4300->cp0.last_addr = *r4300_pc(r4300); \ if (*r4300_cp0_cycle_count(&r4300->cp0) >= 0) gen_interrupt(r4300); \ } \ \ void cached_interp_##name##_OUT(void) \ { \ DECLARE_R4300 \ const int take_jump = (condition); \ const uint32_t jump_target = (destination); \ int64_t *link_register = (link); \ if (cop1 && check_cop1_unusable(r4300)) return; \ if (link_register != &r4300_regs(r4300)[0]) \ { \ *link_register = SE32(*r4300_pc(r4300) + 8); \ } \ if (!likely || take_jump) \ { \ (*r4300_pc_struct(r4300))++; \ r4300->delay_slot=1; \ UPDATE_DEBUGGER(); \ (*r4300_pc_struct(r4300))->ops(); \ cp0_update_count(r4300); \ r4300->delay_slot=0; \ if (take_jump && !r4300->skip_jump) \ { \ generic_jump_to(r4300, jump_target); \ } \ } \ else \ { \ (*r4300_pc_struct(r4300)) += 2; \ cp0_update_count(r4300); \ } \ r4300->cp0.last_addr = *r4300_pc(r4300); \ if (*r4300_cp0_cycle_count(&r4300->cp0) >= 0) gen_interrupt(r4300); \ } \ \ void cached_interp_##name##_IDLE(void) \ { \ DECLARE_R4300 \ uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \ int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); \ const int take_jump = (condition); \ if (cop1 && check_cop1_unusable(r4300)) return; \ if (take_jump) \ { \ cp0_update_count(r4300); \ if(*cp0_cycle_count < 0) \ { \ cp0_regs[CP0_COUNT_REG] -= *cp0_cycle_count; \ *cp0_cycle_count = 0; \ } \ } \ cached_interp_##name(); \ } /* These macros allow direct access to parsed opcode fields. */ #define rrt *(*r4300_pc_struct(r4300))->f.r.rt #define rrd *(*r4300_pc_struct(r4300))->f.r.rd #define rfs (*r4300_pc_struct(r4300))->f.r.nrd #define rrs *(*r4300_pc_struct(r4300))->f.r.rs #define rsa (*r4300_pc_struct(r4300))->f.r.sa #define irt *(*r4300_pc_struct(r4300))->f.i.rt #define ioffset (*r4300_pc_struct(r4300))->f.i.immediate #define iimmediate (*r4300_pc_struct(r4300))->f.i.immediate #define irs *(*r4300_pc_struct(r4300))->f.i.rs #define ibase *(*r4300_pc_struct(r4300))->f.i.rs #define jinst_index (*r4300_pc_struct(r4300))->f.j.inst_index #define lfbase (*r4300_pc_struct(r4300))->f.lf.base #define lfft (*r4300_pc_struct(r4300))->f.lf.ft #define lfoffset (*r4300_pc_struct(r4300))->f.lf.offset #define cfft (*r4300_pc_struct(r4300))->f.cf.ft #define cffs (*r4300_pc_struct(r4300))->f.cf.fs #define cffd (*r4300_pc_struct(r4300))->f.cf.fd /* 32 bits macros */ #ifndef M64P_BIG_ENDIAN #define rrt32 *((int32_t*) (*r4300_pc_struct(r4300))->f.r.rt) #define rrd32 *((int32_t*) (*r4300_pc_struct(r4300))->f.r.rd) #define rrs32 *((int32_t*) (*r4300_pc_struct(r4300))->f.r.rs) #define irs32 *((int32_t*) (*r4300_pc_struct(r4300))->f.i.rs) #define irt32 *((int32_t*) (*r4300_pc_struct(r4300))->f.i.rt) #else #define rrt32 *((int32_t*) (*r4300_pc_struct(r4300))->f.r.rt + 1) #define rrd32 *((int32_t*) (*r4300_pc_struct(r4300))->f.r.rd + 1) #define rrs32 *((int32_t*) (*r4300_pc_struct(r4300))->f.r.rs + 1) #define irs32 *((int32_t*) (*r4300_pc_struct(r4300))->f.i.rs + 1) #define irt32 *((int32_t*) (*r4300_pc_struct(r4300))->f.i.rt + 1) #endif #include "mips_instructions.def" // ----------------------------------------------------------- // Flow control 'fake' instructions // ----------------------------------------------------------- void cached_interp_FIN_BLOCK(void) { DECLARE_R4300 if (!r4300->delay_slot) { generic_jump_to(r4300, ((*r4300_pc_struct(r4300))-1)->addr+4); /* #ifdef DBG if (g_DebuggerActive) update_debugger(*r4300_pc(r4300)); #endif Used by dynarec only, check should be unnecessary */ (*r4300_pc_struct(r4300))->ops(); } else { struct precomp_block *blk = r4300->cached_interp.actual; struct precomp_instr *inst = (*r4300_pc_struct(r4300)); generic_jump_to(r4300, ((*r4300_pc_struct(r4300))-1)->addr+4); /* #ifdef DBG if (g_DebuggerActive) update_debugger(*r4300_pc(r4300)); #endif Used by dynarec only, check should be unnecessary */ if (!r4300->skip_jump) { (*r4300_pc_struct(r4300))->ops(); r4300->cached_interp.actual = blk; (*r4300_pc_struct(r4300)) = inst+1; } else (*r4300_pc_struct(r4300))->ops(); } } void cached_interp_NOTCOMPILED(void) { DECLARE_R4300 uint32_t *mem = fast_mem_access(r4300, r4300->cached_interp.blocks[*r4300_pc(r4300)>>12]->start); #ifdef DBG DebugMessage(M64MSG_INFO, "NOTCOMPILED: addr = %x ops = %lx", *r4300_pc(r4300), (long) (*r4300_pc_struct(r4300))->ops); #endif if (mem == NULL) { DebugMessage(M64MSG_ERROR, "not compiled exception"); } else { r4300->cached_interp.recompile_block(r4300, mem, r4300->cached_interp.blocks[*r4300_pc(r4300) >> 12], *r4300_pc(r4300)); } /* #ifdef DBG if (g_DebuggerActive) update_debugger(*r4300_pc(r4300)); #endif The preceeding update_debugger SHOULD be unnecessary since it should have been called before NOTCOMPILED would have been executed */ (*r4300_pc_struct(r4300))->ops(); } void cached_interp_NOTCOMPILED2(void) { cached_interp_NOTCOMPILED(); } /* TODO: implement them properly */ #define cached_interp_BC0F cached_interp_NI #define cached_interp_BC0F_IDLE cached_interp_NI #define cached_interp_BC0F_OUT cached_interp_NI #define cached_interp_BC0FL cached_interp_NI #define cached_interp_BC0FL_IDLE cached_interp_NI #define cached_interp_BC0FL_OUT cached_interp_NI #define cached_interp_BC0T cached_interp_NI #define cached_interp_BC0T_IDLE cached_interp_NI #define cached_interp_BC0T_OUT cached_interp_NI #define cached_interp_BC0TL cached_interp_NI #define cached_interp_BC0TL_IDLE cached_interp_NI #define cached_interp_BC0TL_OUT cached_interp_NI #define cached_interp_BC2F cached_interp_NI #define cached_interp_BC2F_IDLE cached_interp_NI #define cached_interp_BC2F_OUT cached_interp_NI #define cached_interp_BC2FL cached_interp_NI #define cached_interp_BC2FL_IDLE cached_interp_NI #define cached_interp_BC2FL_OUT cached_interp_NI #define cached_interp_BC2T cached_interp_NI #define cached_interp_BC2T_IDLE cached_interp_NI #define cached_interp_BC2T_OUT cached_interp_NI #define cached_interp_BC2TL cached_interp_NI #define cached_interp_BC2TL_IDLE cached_interp_NI #define cached_interp_BC2TL_OUT cached_interp_NI #define cached_interp_CFC0 cached_interp_NI #define cached_interp_CTC0 cached_interp_NI #define cached_interp_DMTC0 cached_interp_MTC0 #define cached_interp_DCFC2 cached_interp_RESERVED_COP2 #define cached_interp_LDC2 cached_interp_RESERVED_COP2 #define cached_interp_DCTC2 cached_interp_RESERVED_COP2 #define cached_interp_LWC2 cached_interp_RESERVED_COP2 #define cached_interp_LLD cached_interp_NI #define cached_interp_SCD cached_interp_NI #define cached_interp_SDC2 cached_interp_RESERVED_COP2 #define cached_interp_SWC2 cached_interp_RESERVED_COP2 #define cached_interp_JR_IDLE cached_interp_NI #define cached_interp_JALR_IDLE cached_interp_NI #define cached_interp_CP1_ABS cached_interp_RESERVED #define cached_interp_CP1_ADD cached_interp_RESERVED #define cached_interp_CP1_CEIL_L cached_interp_RESERVED #define cached_interp_CP1_CEIL_W cached_interp_RESERVED #define cached_interp_CP1_C_EQ cached_interp_RESERVED #define cached_interp_CP1_C_F cached_interp_RESERVED #define cached_interp_CP1_C_LE cached_interp_RESERVED #define cached_interp_CP1_C_LT cached_interp_RESERVED #define cached_interp_CP1_C_NGE cached_interp_RESERVED #define cached_interp_CP1_C_NGL cached_interp_RESERVED #define cached_interp_CP1_C_NGLE cached_interp_RESERVED #define cached_interp_CP1_C_NGT cached_interp_RESERVED #define cached_interp_CP1_C_OLE cached_interp_RESERVED #define cached_interp_CP1_C_OLT cached_interp_RESERVED #define cached_interp_CP1_C_SEQ cached_interp_RESERVED #define cached_interp_CP1_C_SF cached_interp_RESERVED #define cached_interp_CP1_C_UEQ cached_interp_RESERVED #define cached_interp_CP1_C_ULE cached_interp_RESERVED #define cached_interp_CP1_C_ULT cached_interp_RESERVED #define cached_interp_CP1_C_UN cached_interp_RESERVED #define cached_interp_CP1_CVT_D cached_interp_RESERVED #define cached_interp_CP1_CVT_L cached_interp_RESERVED #define cached_interp_CP1_CVT_S cached_interp_RESERVED #define cached_interp_CP1_CVT_W cached_interp_RESERVED #define cached_interp_CP1_DIV cached_interp_RESERVED #define cached_interp_CP1_FLOOR_L cached_interp_RESERVED #define cached_interp_CP1_FLOOR_W cached_interp_RESERVED #define cached_interp_CP1_MOV cached_interp_RESERVED #define cached_interp_CP1_MUL cached_interp_RESERVED #define cached_interp_CP1_NEG cached_interp_RESERVED #define cached_interp_CP1_ROUND_L cached_interp_RESERVED #define cached_interp_CP1_ROUND_W cached_interp_RESERVED #define cached_interp_CP1_SQRT cached_interp_RESERVED #define cached_interp_CP1_SUB cached_interp_RESERVED #define cached_interp_CP1_TRUNC_L cached_interp_RESERVED #define cached_interp_CP1_TRUNC_W cached_interp_RESERVED #define X(op) cached_interp_##op static void (*const ci_table[R4300_OPCODES_COUNT])(void) = { #include "opcodes.md" }; #undef X /* return 0:normal, 1:idle, 2:out */ static int infer_jump_sub_type(uint32_t target, uint32_t pc, uint32_t next_iw, const struct precomp_block* block) { /* test if jumping to same location with empty delay slot */ if (target == pc) { if (next_iw == 0) { return 1; } } else { /* test if target is outside of block, or if we're at the end of block */ if (target < block->start || target >= block->end || (pc == (block->end - 4))) { return 2; } } /* regular jump */ return 0; } enum r4300_opcode r4300_decode(struct precomp_instr* inst, struct r4300_core* r4300, const struct r4300_idec* idec, uint32_t iw, uint32_t next_iw, const struct precomp_block* block) { /* assume instr->addr is already setup */ uint8_t dummy; enum r4300_opcode opcode = idec->opcode; switch(idec->opcode) { case R4300_OP_JALR: /* use the OUT version since we don't know until runtime * if we're going to jump inside or outside of block */ opcode += 2; inst->f.r.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.r.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.r.rd = IDEC_U53(r4300, iw, idec->u53[0], &inst->f.r.nrd); idec_u53(iw, idec->u53[3], &inst->f.r.sa); break; case R4300_OP_JR: /* use the OUT version since we don't know until runtime * if we're going to jump inside or outside of block */ opcode += 2; /* XXX: mips_instruction.def expects i-type */ inst->f.i.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.i.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.i.immediate = (int16_t)iw; break; case R4300_OP_J: case R4300_OP_JAL: inst->f.j.inst_index = (iw & UINT32_C(0x3ffffff)); /* select normal, idle or out jump type */ opcode += infer_jump_sub_type((inst->addr & ~0xfffffff) | (idec_imm(iw, idec) & 0xfffffff), inst->addr, next_iw, block); break; case R4300_OP_BC0F: case R4300_OP_BC0FL: case R4300_OP_BC0T: case R4300_OP_BC0TL: case R4300_OP_BC1F: case R4300_OP_BC1FL: case R4300_OP_BC1T: case R4300_OP_BC1TL: case R4300_OP_BC2F: case R4300_OP_BC2FL: case R4300_OP_BC2T: case R4300_OP_BC2TL: case R4300_OP_BEQ: case R4300_OP_BEQL: case R4300_OP_BGEZ: case R4300_OP_BGEZAL: case R4300_OP_BGEZALL: case R4300_OP_BGEZL: case R4300_OP_BGTZ: case R4300_OP_BGTZL: case R4300_OP_BLEZ: case R4300_OP_BLEZL: case R4300_OP_BLTZ: case R4300_OP_BLTZAL: case R4300_OP_BLTZALL: case R4300_OP_BLTZL: case R4300_OP_BNE: case R4300_OP_BNEL: inst->f.i.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.i.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.i.immediate = (int16_t)iw; /* select normal, idle or out branch type */ opcode += infer_jump_sub_type(inst->addr + inst->f.i.immediate*4 + 4, inst->addr, next_iw, block); break; case R4300_OP_ADD: case R4300_OP_ADDU: case R4300_OP_AND: case R4300_OP_DADD: case R4300_OP_DADDU: case R4300_OP_DSLL: case R4300_OP_DSLL32: case R4300_OP_DSLLV: case R4300_OP_DSRA: case R4300_OP_DSRA32: case R4300_OP_DSRAV: case R4300_OP_DSRL: case R4300_OP_DSRL32: case R4300_OP_DSRLV: case R4300_OP_DSUB: case R4300_OP_DSUBU: case R4300_OP_MFHI: case R4300_OP_MFLO: case R4300_OP_NOR: case R4300_OP_OR: case R4300_OP_SLL: case R4300_OP_SLLV: case R4300_OP_SLT: case R4300_OP_SLTU: case R4300_OP_SRA: case R4300_OP_SRAV: case R4300_OP_SRL: case R4300_OP_SRLV: case R4300_OP_SUB: case R4300_OP_SUBU: case R4300_OP_XOR: inst->f.r.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.r.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.r.rd = IDEC_U53(r4300, iw, idec->u53[0], &inst->f.r.nrd); idec_u53(iw, idec->u53[3], &inst->f.r.sa); /* optimization: nopify instruction when r0 is the destination register (rd) */ if (inst->f.r.nrd == 0) { opcode = R4300_OP_NOP; } break; case R4300_OP_ADDI: case R4300_OP_ADDIU: case R4300_OP_ANDI: case R4300_OP_DADDI: case R4300_OP_DADDIU: case R4300_OP_LB: case R4300_OP_LBU: case R4300_OP_LD: case R4300_OP_LDL: case R4300_OP_LDR: case R4300_OP_LH: case R4300_OP_LHU: case R4300_OP_LL: case R4300_OP_LLD: case R4300_OP_LUI: case R4300_OP_LW: case R4300_OP_LWL: case R4300_OP_LWR: case R4300_OP_LWU: case R4300_OP_ORI: case R4300_OP_SC: case R4300_OP_SLTI: case R4300_OP_SLTIU: case R4300_OP_XORI: inst->f.i.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.i.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.i.immediate = (int16_t)iw; /* optimization: nopify instruction when r0 is the destination register (rt) */ if (dummy == 0) { opcode = R4300_OP_NOP; } break; case R4300_OP_LDC1: case R4300_OP_LWC1: case R4300_OP_SDC1: case R4300_OP_SWC1: idec_u53(iw, idec->u53[2], &inst->f.lf.base); idec_u53(iw, idec->u53[1], &inst->f.lf.ft); inst->f.lf.offset = (uint16_t)iw; break; case R4300_OP_CFC0: case R4300_OP_CFC1: case R4300_OP_CFC2: case R4300_OP_DCFC1: case R4300_OP_DCFC2: case R4300_OP_DMFC0: case R4300_OP_DMFC1: case R4300_OP_DMFC2: case R4300_OP_MFC0: case R4300_OP_MFC1: case R4300_OP_MFC2: inst->f.r.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.r.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.r.rd = IDEC_U53(r4300, iw, idec->u53[0], &inst->f.r.nrd); idec_u53(iw, idec->u53[3], &inst->f.r.sa); /* optimization: nopify instruction when r0 is the destination register (rt) */ if (dummy == 0) { opcode = R4300_OP_NOP; } break; #define CP1_S_D(op) \ case R4300_OP_CP1_##op: \ idec_u53(iw, idec->u53[3], &dummy); \ idec_u53(iw, idec->u53[2], &inst->f.cf.fs); \ idec_u53(iw, idec->u53[1], &inst->f.cf.ft); \ idec_u53(iw, idec->u53[0], &inst->f.cf.fd); \ switch(dummy) \ { \ case 0x10: inst->ops = cached_interp_##op##_S; return idec->opcode; \ case 0x11: inst->ops = cached_interp_##op##_D; return idec->opcode; \ default: opcode = R4300_OP_RESERVED; \ } \ break; CP1_S_D(ABS) CP1_S_D(ADD) CP1_S_D(CEIL_L) CP1_S_D(CEIL_W) CP1_S_D(C_EQ) CP1_S_D(C_F) CP1_S_D(C_LE) CP1_S_D(C_LT) CP1_S_D(C_NGE) CP1_S_D(C_NGL) CP1_S_D(C_NGLE) CP1_S_D(C_NGT) CP1_S_D(C_OLE) CP1_S_D(C_OLT) CP1_S_D(C_SEQ) CP1_S_D(C_SF) CP1_S_D(C_UEQ) CP1_S_D(C_ULE) CP1_S_D(C_ULT) CP1_S_D(C_UN) CP1_S_D(CVT_L) CP1_S_D(CVT_W) CP1_S_D(DIV) CP1_S_D(FLOOR_L) CP1_S_D(FLOOR_W) CP1_S_D(MOV) CP1_S_D(MUL) CP1_S_D(NEG) CP1_S_D(ROUND_L) CP1_S_D(ROUND_W) CP1_S_D(SQRT) CP1_S_D(SUB) CP1_S_D(TRUNC_L) CP1_S_D(TRUNC_W) #undef CP1_S_D case R4300_OP_CP1_CVT_D: idec_u53(iw, idec->u53[3], &dummy); idec_u53(iw, idec->u53[2], &inst->f.cf.fs); idec_u53(iw, idec->u53[1], &inst->f.cf.ft); idec_u53(iw, idec->u53[0], &inst->f.cf.fd); switch(dummy) { case 0x10: inst->ops = cached_interp_CVT_D_S; return idec->opcode; case 0x14: inst->ops = cached_interp_CVT_D_W; return idec->opcode; case 0x15: inst->ops = cached_interp_CVT_D_L; return idec->opcode; default: opcode = R4300_OP_RESERVED; } break; case R4300_OP_CP1_CVT_S: idec_u53(iw, idec->u53[3], &dummy); idec_u53(iw, idec->u53[2], &inst->f.cf.fs); idec_u53(iw, idec->u53[1], &inst->f.cf.ft); idec_u53(iw, idec->u53[0], &inst->f.cf.fd); switch(dummy) { case 0x11: inst->ops = cached_interp_CVT_S_D; return idec->opcode; case 0x14: inst->ops = cached_interp_CVT_S_W; return idec->opcode; case 0x15: inst->ops = cached_interp_CVT_S_L; return idec->opcode; default: opcode = R4300_OP_RESERVED; } break; case R4300_OP_CTC0: case R4300_OP_CTC1: case R4300_OP_DCTC1: case R4300_OP_CTC2: case R4300_OP_DCTC2: case R4300_OP_DDIV: case R4300_OP_DDIVU: case R4300_OP_DIV: case R4300_OP_DIVU: case R4300_OP_DMTC0: case R4300_OP_DMTC1: case R4300_OP_DMTC2: case R4300_OP_DMULT: case R4300_OP_DMULTU: case R4300_OP_MTC0: case R4300_OP_MTC1: case R4300_OP_MTC2: case R4300_OP_MTHI: case R4300_OP_MTLO: case R4300_OP_MULT: case R4300_OP_MULTU: case R4300_OP_NOP: case R4300_OP_TEQ: case R4300_OP_TGE: case R4300_OP_TGEU: case R4300_OP_TLT: case R4300_OP_TLTU: case R4300_OP_TNE: inst->f.r.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.r.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.r.rd = IDEC_U53(r4300, iw, idec->u53[0], &inst->f.r.nrd); idec_u53(iw, idec->u53[3], &inst->f.r.sa); break; case R4300_OP_LDC2: case R4300_OP_LWC2: case R4300_OP_SB: case R4300_OP_SCD: case R4300_OP_SD: case R4300_OP_SDC2: case R4300_OP_SDL: case R4300_OP_SDR: case R4300_OP_SH: case R4300_OP_SW: case R4300_OP_SWC2: case R4300_OP_SWL: case R4300_OP_SWR: case R4300_OP_TEQI: case R4300_OP_TGEI: case R4300_OP_TGEIU: case R4300_OP_TLTI: case R4300_OP_TLTIU: case R4300_OP_TNEI: inst->f.i.rs = IDEC_U53(r4300, iw, idec->u53[2], &dummy); inst->f.i.rt = IDEC_U53(r4300, iw, idec->u53[1], &dummy); inst->f.i.immediate = (int16_t)iw; break; case R4300_OP_BREAK: case R4300_OP_CACHE: case R4300_OP_ERET: case R4300_OP_SYNC: case R4300_OP_SYSCALL: case R4300_OP_TLBP: case R4300_OP_TLBR: case R4300_OP_TLBWI: case R4300_OP_TLBWR: case R4300_OP_RESERVED: /* no need for additonal instruction parsing */ break; default: DebugMessage(M64MSG_ERROR, "invalid instruction: %08x", iw); assert(0); break; } /* set appropriate handler */ inst->ops = ci_table[opcode]; /* propagate opcode info to allow further processing */ return opcode; } static uint32_t update_invalid_addr(struct r4300_core* r4300, uint32_t addr) { char* const invalid_code = r4300->cached_interp.invalid_code; if ((addr & UINT32_C(0xc0000000)) == UINT32_C(0x80000000)) { if (invalid_code[addr>>12]) { invalid_code[(addr^0x20000000)>>12] = 1; } if (invalid_code[(addr^0x20000000)>>12]) { invalid_code[addr>>12] = 1; } return addr; } else { uint32_t paddr = virtual_to_physical_address(r4300, addr, 2); if (paddr) { uint32_t beg_paddr = paddr - (addr - (addr & ~0xfff)); update_invalid_addr(r4300, paddr); if (invalid_code[(beg_paddr+0x000)>>12]) { invalid_code[addr>>12] = 1; } if (invalid_code[(beg_paddr+0xffc)>>12]) { invalid_code[addr>>12] = 1; } if (invalid_code[addr>>12]) { invalid_code[(beg_paddr+0x000)>>12] = 1; } if (invalid_code[addr>>12]) { invalid_code[(beg_paddr+0xffc)>>12] = 1; } } return paddr; } } int get_block_length(const struct precomp_block *block) { return (block->end-block->start)/4; } size_t get_block_memsize(const struct precomp_block *block) { int length = get_block_length(block); return ((length+1)+(length>>2)) * sizeof(struct precomp_instr); } void cached_interp_init_block(struct r4300_core* r4300, uint32_t address) { int i, length; struct precomp_block** block = &r4300->cached_interp.blocks[address >> 12]; /* allocate block */ if (*block == NULL) { *block = malloc(sizeof(struct precomp_block)); (*block)->block = NULL; (*block)->start = address & ~UINT32_C(0xfff); (*block)->end = (address & ~UINT32_C(0xfff)) + 0x1000; } struct precomp_block* b = *block; length = get_block_length(b); #ifdef DBG DebugMessage(M64MSG_INFO, "init block %" PRIX32 " - %" PRIX32, b->start, b->end); #endif /* allocate block instructions */ if (!b->block) { size_t memsize = get_block_memsize(b); b->block = (struct precomp_instr*)malloc(memsize); if (!b->block) { DebugMessage(M64MSG_ERROR, "Memory error: couldn't allocate memory for cached interpreter."); return; } memset(b->block, 0, memsize); } /* reset block instructions (addr + ops) */ for (i = 0; i < length; ++i) { b->block[i].addr = b->start + 4*i; b->block[i].ops = cached_interp_NOTCOMPILED; } /* here we're marking the block as a valid code even if it's not compiled * yet as the game should have already set up the code correctly. */ r4300->cached_interp.invalid_code[b->start>>12] = 0; if (b->end < UINT32_C(0x80000000) || b->start >= UINT32_C(0xc0000000)) { uint32_t paddr = virtual_to_physical_address(r4300, b->start, 2); r4300->cached_interp.invalid_code[paddr>>12] = 0; cached_interp_init_block(r4300, paddr); paddr += b->end - b->start - 4; r4300->cached_interp.invalid_code[paddr>>12] = 0; cached_interp_init_block(r4300, paddr); } else { uint32_t alt_addr = b->start ^ UINT32_C(0x20000000); if (r4300->cached_interp.invalid_code[alt_addr>>12]) { cached_interp_init_block(r4300, alt_addr); } } } void cached_interp_free_block(struct precomp_block* block) { if (block->block) { free(block->block); block->block = NULL; } } void cached_interp_recompile_block(struct r4300_core* r4300, const uint32_t* iw, struct precomp_block* block, uint32_t func) { int i, length, length2, finished; struct precomp_instr* inst; enum r4300_opcode opcode; /* ??? not sure why we need these 2 different tests */ int block_start_in_tlb = ((block->start & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)); int block_not_in_tlb = (block->start >= UINT32_C(0xc0000000) || block->end < UINT32_C(0x80000000)); length = get_block_length(block); length2 = length - 2 + (length >> 2); /* reset xxhash */ block->xxhash = 0; for (i = (func & 0xFFF) / 4, finished = 0; finished != 2; ++i) { inst = block->block + i; /* set decoded instruction address */ inst->addr = block->start + i * 4; if (block_start_in_tlb) { uint32_t address2 = virtual_to_physical_address(r4300, inst->addr, 0); if (r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops == cached_interp_NOTCOMPILED) { r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops = cached_interp_NOTCOMPILED2; } } /* decode instruction */ opcode = r4300_decode(inst, r4300, r4300_get_idec(iw[i]), iw[i], iw[i+1], block); /* decode ending conditions */ if (i >= length2) { finished = 2; } if (i >= (length-1) && (block->start == UINT32_C(0xa4000000) || block_not_in_tlb)) { finished = 2; } if (opcode == R4300_OP_ERET || finished == 1) { finished = 2; } if (/*i >= length && */ (opcode == R4300_OP_J || opcode == R4300_OP_J_OUT || opcode == R4300_OP_JR || opcode == R4300_OP_JR_OUT) && !(i >= (length-1) && block_not_in_tlb)) { finished = 1; } } if (i >= length) { inst = block->block + i; inst->addr = block->start + i*4; inst->ops = cached_interp_FIN_BLOCK; ++i; if (i <= length2) // useful when last opcode is a jump { inst = block->block + i; inst->addr = block->start + i*4; inst->ops = cached_interp_FIN_BLOCK; i++; } } #ifdef DBG DebugMessage(M64MSG_INFO, "block recompiled (%" PRIX32 "-%" PRIX32 ")", func, block->start+i*4); #endif } void cached_interpreter_jump_to(struct r4300_core* r4300, uint32_t address) { struct cached_interp* const cinterp = &r4300->cached_interp; if (r4300->skip_jump) { return; } if (!update_invalid_addr(r4300, address)) { return; } /* setup new block if invalid */ if (cinterp->invalid_code[address >> 12]) { r4300->cached_interp.init_block(r4300, address); } /* set new PC */ cinterp->actual = cinterp->blocks[address >> 12]; (*r4300_pc_struct(r4300)) = cinterp->actual->block + ((address - cinterp->actual->start) >> 2); } void init_blocks(struct cached_interp* cinterp) { size_t i; for (i = 0; i < 0x100000; ++i) { cinterp->invalid_code[i] = 1; cinterp->blocks[i] = NULL; } } void free_blocks(struct cached_interp* cinterp) { size_t i; for (i = 0; i < 0x100000; ++i) { if (cinterp->blocks[i]) { cinterp->free_block(cinterp->blocks[i]); free(cinterp->blocks[i]); cinterp->blocks[i] = NULL; } } } void invalidate_cached_code_hacktarux(struct r4300_core* r4300, uint32_t address, size_t size) { size_t i; uint32_t addr; uint32_t addr_max; if (size == 0) { /* invalidate everthing */ memset(r4300->cached_interp.invalid_code, 1, 0x100000); } else { /* invalidate blocks (if necessary) */ addr_max = address+size; for(addr = address; addr < addr_max; addr += 4) { i = (addr >> 12); if (r4300->cached_interp.invalid_code[i] == 0) { if (r4300->cached_interp.blocks[i] == NULL || r4300->cached_interp.blocks[i]->block[(addr & 0xfff) / 4].ops != r4300->cached_interp.not_compiled) { r4300->cached_interp.invalid_code[i] = 1; /* go directly to next i */ addr &= ~0xfff; addr |= 0xffc; } } else { /* go directly to next i */ addr &= ~0xfff; addr |= 0xffc; } } } } void run_cached_interpreter(struct r4300_core* r4300) { while (!*r4300_stop(r4300)) { #ifdef COMPARE_CORE if ((*r4300_pc_struct(r4300))->ops == cached_interp_FIN_BLOCK && ((*r4300_pc_struct(r4300))->addr < 0x80000000 || (*r4300_pc_struct(r4300))->addr >= 0xc0000000)) virtual_to_physical_address(r4300, (*r4300_pc_struct(r4300))->addr, 2); CoreCompareCallback(); #endif #ifdef DBG if (g_DebuggerActive) update_debugger((*r4300_pc_struct(r4300))->addr); #endif (*r4300_pc_struct(r4300))->ops(); } } mupen64plus-core-src-2.6.0/src/device/r4300/cached_interp.h000066400000000000000000000255631464506436200232200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cached_interp.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_CACHED_INTERP_H #define M64P_DEVICE_R4300_CACHED_INTERP_H #include #include #include "idec.h" struct r4300_core; struct cached_interp; struct r4300_idec; struct precomp_block; struct precomp_instr; enum r4300_opcode r4300_decode(struct precomp_instr* inst, struct r4300_core* r4300, const struct r4300_idec* idec, uint32_t iw, uint32_t next_iw, const struct precomp_block* block); int get_block_length(const struct precomp_block *block); size_t get_block_memsize(const struct precomp_block *block); void cached_interp_init_block(struct r4300_core* r4300, uint32_t address); void cached_interp_free_block(struct precomp_block* block); void cached_interp_recompile_block(struct r4300_core* r4300, const uint32_t* iw, struct precomp_block* block, uint32_t func); void init_blocks(struct cached_interp* cinterp); void free_blocks(struct cached_interp* cinterp); void invalidate_cached_code_hacktarux(struct r4300_core* r4300, uint32_t address, size_t size); void run_cached_interpreter(struct r4300_core* r4300); /* Jumps to the given address. This is for the cached interpreter. */ void cached_interpreter_jump_to(struct r4300_core* r4300, uint32_t address); void cached_interp_FIN_BLOCK(void); void cached_interp_NOTCOMPILED(void); void cached_interp_NOTCOMPILED2(void); void cached_interp_NI(void); void cached_interp_RESERVED(void); void cached_interp_LB(void); void cached_interp_LBU(void); void cached_interp_LH(void); void cached_interp_LHU(void); void cached_interp_LL(void); void cached_interp_LW(void); void cached_interp_LWU(void); void cached_interp_LWL(void); void cached_interp_LWR(void); void cached_interp_LD(void); void cached_interp_LDL(void); void cached_interp_LDR(void); void cached_interp_SB(void); void cached_interp_SH(void); void cached_interp_SC(void); void cached_interp_SW(void); void cached_interp_SWL(void); void cached_interp_SWR(void); void cached_interp_SD(void); void cached_interp_SDL(void); void cached_interp_SDR(void); void cached_interp_ADD(void); void cached_interp_ADDU(void); void cached_interp_ADDI(void); void cached_interp_ADDIU(void); void cached_interp_DADD(void); void cached_interp_DADDU(void); void cached_interp_DADDI(void); void cached_interp_DADDIU(void); void cached_interp_SUB(void); void cached_interp_SUBU(void); void cached_interp_DSUB(void); void cached_interp_DSUBU(void); void cached_interp_SLT(void); void cached_interp_SLTU(void); void cached_interp_SLTI(void); void cached_interp_SLTIU(void); void cached_interp_AND(void); void cached_interp_ANDI(void); void cached_interp_OR(void); void cached_interp_ORI(void); void cached_interp_XOR(void); void cached_interp_XORI(void); void cached_interp_NOR(void); void cached_interp_LUI(void); void cached_interp_NOP(void); void cached_interp_SLL(void); void cached_interp_SLLV(void); void cached_interp_DSLL(void); void cached_interp_DSLLV(void); void cached_interp_DSLL32(void); void cached_interp_SRL(void); void cached_interp_SRLV(void); void cached_interp_DSRL(void); void cached_interp_DSRLV(void); void cached_interp_DSRL32(void); void cached_interp_SRA(void); void cached_interp_SRAV(void); void cached_interp_DSRA(void); void cached_interp_DSRAV(void); void cached_interp_DSRA32(void); void cached_interp_MULT(void); void cached_interp_MULTU(void); void cached_interp_DMULT(void); void cached_interp_DMULTU(void); void cached_interp_DIV(void); void cached_interp_DIVU(void); void cached_interp_DDIV(void); void cached_interp_DDIVU(void); void cached_interp_MFHI(void); void cached_interp_MTHI(void); void cached_interp_MFLO(void); void cached_interp_MTLO(void); void cached_interp_J(void); void cached_interp_J_OUT(void); void cached_interp_J_IDLE(void); void cached_interp_JAL(void); void cached_interp_JAL_OUT(void); void cached_interp_JAL_IDLE(void); void cached_interp_JR(void); void cached_interp_JR_OUT(void); void cached_interp_JALR(void); void cached_interp_JALR_OUT(void); void cached_interp_BEQ(void); void cached_interp_BEQ_OUT(void); void cached_interp_BEQ_IDLE(void); void cached_interp_BEQL(void); void cached_interp_BEQL_OUT(void); void cached_interp_BEQL_IDLE(void); void cached_interp_BNE(void); void cached_interp_BNE_OUT(void); void cached_interp_BNE_IDLE(void); void cached_interp_BNEL(void); void cached_interp_BNEL_OUT(void); void cached_interp_BNEL_IDLE(void); void cached_interp_BLEZ(void); void cached_interp_BLEZ_OUT(void); void cached_interp_BLEZ_IDLE(void); void cached_interp_BLEZL(void); void cached_interp_BLEZL_OUT(void); void cached_interp_BLEZL_IDLE(void); void cached_interp_BGTZ(void); void cached_interp_BGTZ_OUT(void); void cached_interp_BGTZ_IDLE(void); void cached_interp_BGTZL(void); void cached_interp_BGTZL_OUT(void); void cached_interp_BGTZL_IDLE(void); void cached_interp_BLTZ(void); void cached_interp_BLTZ_OUT(void); void cached_interp_BLTZ_IDLE(void); void cached_interp_BLTZAL(void); void cached_interp_BLTZAL_OUT(void); void cached_interp_BLTZAL_IDLE(void); void cached_interp_BLTZL(void); void cached_interp_BLTZL_OUT(void); void cached_interp_BLTZL_IDLE(void); void cached_interp_BLTZALL(void); void cached_interp_BLTZALL_OUT(void); void cached_interp_BLTZALL_IDLE(void); void cached_interp_BGEZ(void); void cached_interp_BGEZ_OUT(void); void cached_interp_BGEZ_IDLE(void); void cached_interp_BGEZAL(void); void cached_interp_BGEZAL_OUT(void); void cached_interp_BGEZAL_IDLE(void); void cached_interp_BGEZL(void); void cached_interp_BGEZL_OUT(void); void cached_interp_BGEZL_IDLE(void); void cached_interp_BGEZALL(void); void cached_interp_BGEZALL_OUT(void); void cached_interp_BGEZALL_IDLE(void); void cached_interp_BC1F(void); void cached_interp_BC1F_OUT(void); void cached_interp_BC1F_IDLE(void); void cached_interp_BC1FL(void); void cached_interp_BC1FL_OUT(void); void cached_interp_BC1FL_IDLE(void); void cached_interp_BC1T(void); void cached_interp_BC1T_OUT(void); void cached_interp_BC1T_IDLE(void); void cached_interp_BC1TL(void); void cached_interp_BC1TL_OUT(void); void cached_interp_BC1TL_IDLE(void); void cached_interp_CACHE(void); void cached_interp_ERET(void); void cached_interp_SYNC(void); void cached_interp_SYSCALL(void); void cached_interp_TGE(void); void cached_interp_TGEU(void); void cached_interp_TGEI(void); void cached_interp_TGEIU(void); void cached_interp_TLT(void); void cached_interp_TLTU(void); void cached_interp_TLTI(void); void cached_interp_TLTIU(void); void cached_interp_TEQ(void); void cached_interp_TEQI(void); void cached_interp_TNE(void); void cached_interp_TNEI(void); void cached_interp_TLBP(void); void cached_interp_TLBR(void); void cached_interp_TLBWR(void); void cached_interp_TLBWI(void); void cached_interp_MFC0(void); void cached_interp_MTC0(void); void cached_interp_LWC1(void); void cached_interp_LDC1(void); void cached_interp_SWC1(void); void cached_interp_SDC1(void); void cached_interp_MFC1(void); void cached_interp_DMFC1(void); void cached_interp_CFC1(void); void cached_interp_MTC1(void); void cached_interp_DMTC1(void); void cached_interp_CTC1(void); void cached_interp_ABS_S(void); void cached_interp_ABS_D(void); void cached_interp_ADD_S(void); void cached_interp_ADD_D(void); void cached_interp_DIV_S(void); void cached_interp_DIV_D(void); void cached_interp_MOV_S(void); void cached_interp_MOV_D(void); void cached_interp_MUL_S(void); void cached_interp_MUL_D(void); void cached_interp_NEG_S(void); void cached_interp_NEG_D(void); void cached_interp_SQRT_S(void); void cached_interp_SQRT_D(void); void cached_interp_SUB_S(void); void cached_interp_SUB_D(void); void cached_interp_TRUNC_W_S(void); void cached_interp_TRUNC_W_D(void); void cached_interp_TRUNC_L_S(void); void cached_interp_TRUNC_L_D(void); void cached_interp_ROUND_W_S(void); void cached_interp_ROUND_W_D(void); void cached_interp_ROUND_L_S(void); void cached_interp_ROUND_L_D(void); void cached_interp_CEIL_W_S(void); void cached_interp_CEIL_W_D(void); void cached_interp_CEIL_L_S(void); void cached_interp_CEIL_L_D(void); void cached_interp_FLOOR_W_S(void); void cached_interp_FLOOR_W_D(void); void cached_interp_FLOOR_L_S(void); void cached_interp_FLOOR_L_D(void); void cached_interp_CVT_S_D(void); void cached_interp_CVT_S_W(void); void cached_interp_CVT_S_L(void); void cached_interp_CVT_D_S(void); void cached_interp_CVT_D_W(void); void cached_interp_CVT_D_L(void); void cached_interp_CVT_W_S(void); void cached_interp_CVT_W_D(void); void cached_interp_CVT_L_S(void); void cached_interp_CVT_L_D(void); void cached_interp_C_F_S(void); void cached_interp_C_F_D(void); void cached_interp_C_UN_S(void); void cached_interp_C_UN_D(void); void cached_interp_C_EQ_S(void); void cached_interp_C_EQ_D(void); void cached_interp_C_UEQ_S(void); void cached_interp_C_UEQ_D(void); void cached_interp_C_OLT_S(void); void cached_interp_C_OLT_D(void); void cached_interp_C_ULT_S(void); void cached_interp_C_ULT_D(void); void cached_interp_C_OLE_S(void); void cached_interp_C_OLE_D(void); void cached_interp_C_ULE_S(void); void cached_interp_C_ULE_D(void); void cached_interp_C_SF_S(void); void cached_interp_C_SF_D(void); void cached_interp_C_NGLE_S(void); void cached_interp_C_NGLE_D(void); void cached_interp_C_SEQ_S(void); void cached_interp_C_SEQ_D(void); void cached_interp_C_NGL_S(void); void cached_interp_C_NGL_D(void); void cached_interp_C_LT_S(void); void cached_interp_C_LT_D(void); void cached_interp_C_NGE_S(void); void cached_interp_C_NGE_D(void); void cached_interp_C_LE_S(void); void cached_interp_C_LE_D(void); void cached_interp_C_NGT_S(void); void cached_interp_C_NGT_D(void); #endif /* M64P_DEVICE_R4300_CACHED_INTERP_H */ mupen64plus-core-src-2.6.0/src/device/r4300/cp0.c000066400000000000000000000224071464506436200210770ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cp0.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "cp0.h" #include "r4300_core.h" #include "new_dynarec/new_dynarec.h" #include "recomp.h" #ifdef COMPARE_CORE #include "api/debugger.h" #endif #ifdef DBG #include "debugger/dbg_debugger.h" #endif /* global functions */ void init_cp0(struct cp0* cp0, unsigned int count_per_op, unsigned int count_per_op_denom_pot, struct new_dynarec_hot_state* new_dynarec_hot_state, const struct interrupt_handler* interrupt_handlers) { cp0->count_per_op = count_per_op; cp0->count_per_op_denom_pot = count_per_op_denom_pot; #ifdef NEW_DYNAREC cp0->new_dynarec_hot_state = new_dynarec_hot_state; #endif memcpy(cp0->interrupt_handlers, interrupt_handlers, CP0_INTERRUPT_HANDLERS_COUNT*sizeof(*interrupt_handlers)); } void poweron_cp0(struct cp0* cp0) { uint32_t* cp0_regs; unsigned int* cp0_next_interrupt; int* cp0_cycle_count; cp0_regs = r4300_cp0_regs(cp0); cp0_next_interrupt = r4300_cp0_next_interrupt(cp0); cp0_cycle_count = r4300_cp0_cycle_count(cp0); memset(cp0_regs, 0, CP0_REGS_COUNT * sizeof(cp0_regs[0])); cp0_regs[CP0_RANDOM_REG] = UINT32_C(31); cp0_regs[CP0_STATUS_REG]= UINT32_C(0x34000000); cp0_regs[CP0_CONFIG_REG]= UINT32_C(0x6e463); cp0_regs[CP0_PREVID_REG] = UINT32_C(0xb10); cp0_regs[CP0_COUNT_REG] = UINT32_C(0x5000); cp0_regs[CP0_CAUSE_REG] = UINT32_C(0x5c); cp0_regs[CP0_CONTEXT_REG] = UINT32_C(0x7ffff0); cp0_regs[CP0_EPC_REG] = UINT32_C(0xffffffff); cp0_regs[CP0_BADVADDR_REG] = UINT32_C(0xffffffff); cp0_regs[CP0_ERROREPC_REG] = UINT32_C(0xffffffff); /* XXX: clarify what is done on poweron, in soft_reset and in execute... */ cp0->interrupt_unsafe_state = 0; *cp0_next_interrupt = 0; *cp0_cycle_count = 0; cp0->last_addr = UINT32_C(0xbfc00000); init_interrupt(cp0); poweron_tlb(&cp0->tlb); } uint32_t* r4300_cp0_regs(struct cp0* cp0) { #ifndef NEW_DYNAREC return cp0->regs; #else /* New dynarec uses a different memory layout */ return cp0->new_dynarec_hot_state->cp0_regs; #endif } uint64_t* r4300_cp0_latch(struct cp0* cp0) { #ifndef NEW_DYNAREC return &cp0->latch; #else /* New dynarec uses a different memory layout */ return &cp0->new_dynarec_hot_state->cp0_latch; #endif } uint32_t* r4300_cp0_last_addr(struct cp0* cp0) { return &cp0->last_addr; } unsigned int* r4300_cp0_next_interrupt(struct cp0* cp0) { return &cp0->next_interrupt; } int* r4300_cp0_cycle_count(struct cp0* cp0) { #ifndef NEW_DYNAREC return &cp0->cycle_count; #else /* New dynarec uses a different memory layout */ return &cp0->new_dynarec_hot_state->cycle_count; #endif } int check_cop1_unusable(struct r4300_core* r4300) { uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); if (!(cp0_regs[CP0_STATUS_REG] & CP0_STATUS_CU1)) { cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_CPU | CP0_CAUSE_CE1; exception_general(r4300); return 1; } return 0; } int check_cop2_unusable(struct r4300_core* r4300) { uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); if (!(cp0_regs[CP0_STATUS_REG] & CP0_STATUS_CU2)) { cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_CPU | CP0_CAUSE_CE2; exception_general(r4300); return 1; } return 0; } void cp0_update_count(struct r4300_core* r4300) { struct cp0* cp0 = &r4300->cp0; uint32_t* cp0_regs = r4300_cp0_regs(cp0); #ifdef NEW_DYNAREC if (r4300->emumode != EMUMODE_DYNAREC) { #endif uint32_t count = ((*r4300_pc(r4300) - cp0->last_addr) >> 2) * cp0->count_per_op; if (r4300->cp0.count_per_op_denom_pot) { count += (1 << r4300->cp0.count_per_op_denom_pot) - 1; count >>= r4300->cp0.count_per_op_denom_pot; } cp0_regs[CP0_COUNT_REG] += count; *r4300_cp0_cycle_count(cp0) += count; cp0->last_addr = *r4300_pc(r4300); #ifdef NEW_DYNAREC } else cp0_regs[CP0_COUNT_REG] = *r4300_cp0_next_interrupt(cp0) + *r4300_cp0_cycle_count(cp0); #endif #ifdef COMPARE_CORE if (r4300->delay_slot) CoreCompareCallback(); #endif /*#ifdef DBG if (g_DebuggerActive && !r4300->delay_slot) update_debugger(*r4300_pc(r4300)); #endif */ } static void exception_epilog(struct r4300_core* r4300) { #ifndef NO_ASM #ifndef NEW_DYNAREC if (r4300->emumode == EMUMODE_DYNAREC) { dyna_jump(); if (!r4300->recomp.dyna_interp) { r4300->delay_slot = 0; } } #endif #endif #ifndef NEW_DYNAREC if (r4300->emumode != EMUMODE_DYNAREC || r4300->recomp.dyna_interp) { r4300->recomp.dyna_interp = 0; #else if (r4300->emumode != EMUMODE_DYNAREC) { #endif if (r4300->delay_slot) { r4300->skip_jump = *r4300_pc(r4300); *r4300_cp0_next_interrupt(&r4300->cp0) = 0; *r4300_cp0_cycle_count(&r4300->cp0) = 0; } } } void TLB_refill_exception(struct r4300_core* r4300, uint32_t address, int w) { uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); int usual_handler = 0, i; if (r4300->emumode != EMUMODE_DYNAREC && w != 2) { cp0_update_count(r4300); } cp0_regs[CP0_CAUSE_REG] = (w == 1) ? CP0_CAUSE_EXCCODE_TLBS : CP0_CAUSE_EXCCODE_TLBL; cp0_regs[CP0_BADVADDR_REG] = address; cp0_regs[CP0_CONTEXT_REG] = (cp0_regs[CP0_CONTEXT_REG] & UINT32_C(0xFF80000F)) | ((address >> 9) & UINT32_C(0x007FFFF0)); cp0_regs[CP0_ENTRYHI_REG] = address & UINT32_C(0xFFFFE000); if (cp0_regs[CP0_STATUS_REG] & CP0_STATUS_EXL) { generic_jump_to(r4300, UINT32_C(0x80000180)); if (r4300->delay_slot == 1 || r4300->delay_slot == 3) { cp0_regs[CP0_CAUSE_REG] |= CP0_CAUSE_BD; } else { cp0_regs[CP0_CAUSE_REG] &= ~CP0_CAUSE_BD; } } else { if (r4300->emumode != EMUMODE_PURE_INTERPRETER) { cp0_regs[CP0_EPC_REG] = (w != 2) ? *r4300_pc(r4300) : address; } else { cp0_regs[CP0_EPC_REG] = *r4300_pc(r4300); } cp0_regs[CP0_CAUSE_REG] &= ~CP0_CAUSE_BD; cp0_regs[CP0_STATUS_REG] |= CP0_STATUS_EXL; if (address >= UINT32_C(0x80000000) && address < UINT32_C(0xc0000000)) { usual_handler = 1; } for (i = 0; i < 32; i++) { if (/*r4300->cp0.tlb.entries[i].v_even &&*/ address >= r4300->cp0.tlb.entries[i].start_even && address <= r4300->cp0.tlb.entries[i].end_even) { usual_handler = 1; } if (/*r4300->cp0.tlb.entries[i].v_odd &&*/ address >= r4300->cp0.tlb.entries[i].start_odd && address <= r4300->cp0.tlb.entries[i].end_odd) { usual_handler = 1; } } generic_jump_to(r4300, (usual_handler) ? UINT32_C(0x80000180) : UINT32_C(0x80000000)); } if (r4300->delay_slot == 1 || r4300->delay_slot == 3) { cp0_regs[CP0_CAUSE_REG] |= CP0_CAUSE_BD; cp0_regs[CP0_EPC_REG] -= 4; } else { cp0_regs[CP0_CAUSE_REG] &= ~CP0_CAUSE_BD; } if (w != 2) { cp0_regs[CP0_EPC_REG] -= 4; } r4300->cp0.last_addr = *r4300_pc(r4300); exception_epilog(r4300); } void exception_general(struct r4300_core* r4300) { uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); cp0_update_count(r4300); cp0_regs[CP0_STATUS_REG] |= CP0_STATUS_EXL; cp0_regs[CP0_EPC_REG] = *r4300_pc(r4300); if (r4300->delay_slot == 1 || r4300->delay_slot == 3) { cp0_regs[CP0_CAUSE_REG] |= CP0_CAUSE_BD; cp0_regs[CP0_EPC_REG] -= 4; } else { cp0_regs[CP0_CAUSE_REG] &= ~CP0_CAUSE_BD; } generic_jump_to(r4300, UINT32_C(0x80000180)); r4300->cp0.last_addr = *r4300_pc(r4300); exception_epilog(r4300); } mupen64plus-core-src-2.6.0/src/device/r4300/cp0.h000066400000000000000000000200671464506436200211040ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cp0.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_CP0_H #define M64P_DEVICE_R4300_CP0_H #include #include "interrupt.h" #include "tlb.h" #include "new_dynarec/new_dynarec.h" /* Status register definitions */ #define CP0_STATUS_IE UINT32_C(0x00000001) #define CP0_STATUS_EXL UINT32_C(0x00000002) #define CP0_STATUS_ERL UINT32_C(0x00000004) /* Execution modes */ #define CP0_STATUS_MODE_K (UINT32_C(0 ) << 3) #define CP0_STATUS_MODE_S (UINT32_C(1 ) << 3) #define CP0_STATUS_MODE_U (UINT32_C(2 ) << 3) #define CP0_STATUS_MODE_MASK (UINT32_C(0x3) << 3) #define CP0_STATUS_UX UINT32_C(0x00000020) #define CP0_STATUS_SX UINT32_C(0x00000040) #define CP0_STATUS_KX UINT32_C(0x00000080) #define CP0_STATUS_IM0 UINT32_C(0x00000100) #define CP0_STATUS_IM1 UINT32_C(0x00000200) #define CP0_STATUS_IM2 UINT32_C(0x00000400) #define CP0_STATUS_IM3 UINT32_C(0x00000800) #define CP0_STATUS_IM4 UINT32_C(0x00001000) #define CP0_STATUS_IM5 UINT32_C(0x00002000) #define CP0_STATUS_IM6 UINT32_C(0x00004000) #define CP0_STATUS_IM7 UINT32_C(0x00008000) /* bit 16 and 17 are left for compatibility */ #define CP0_STATUS_CH UINT32_C(0x00040000) /* bit 19 is zero */ #define CP0_STATUS_SR UINT32_C(0x00100000) #define CP0_STATUS_TS UINT32_C(0x00200000) #define CP0_STATUS_BEV UINT32_C(0x00400000) #define CP0_STATUS_RSVD UINT32_C(0x00800000) #define CP0_STATUS_ITS UINT32_C(0x01000000) #define CP0_STATUS_RE UINT32_C(0x02000000) #define CP0_STATUS_FR UINT32_C(0x04000000) #define CP0_STATUS_RP UINT32_C(0x08000000) #define CP0_STATUS_CU0 UINT32_C(0x10000000) #define CP0_STATUS_CU1 UINT32_C(0x20000000) #define CP0_STATUS_CU2 UINT32_C(0x40000000) #define CP0_STATUS_CU3 UINT32_C(0x80000000) /* Cause register definitions */ /* Execution Codes */ #define CP0_CAUSE_EXCCODE_INT (UINT32_C(0 ) << 2) #define CP0_CAUSE_EXCCODE_MOD (UINT32_C(1 ) << 2) #define CP0_CAUSE_EXCCODE_TLBL (UINT32_C(2 ) << 2) #define CP0_CAUSE_EXCCODE_TLBS (UINT32_C(3 ) << 2) #define CP0_CAUSE_EXCCODE_ADEL (UINT32_C(4 ) << 2) #define CP0_CAUSE_EXCCODE_ADES (UINT32_C(5 ) << 2) #define CP0_CAUSE_EXCCODE_IBE (UINT32_C(6 ) << 2) #define CP0_CAUSE_EXCCODE_DBE (UINT32_C(7 ) << 2) #define CP0_CAUSE_EXCCODE_SYS (UINT32_C(8 ) << 2) #define CP0_CAUSE_EXCCODE_BP (UINT32_C(9 ) << 2) #define CP0_CAUSE_EXCCODE_RI (UINT32_C(10) << 2) #define CP0_CAUSE_EXCCODE_CPU (UINT32_C(11) << 2) #define CP0_CAUSE_EXCCODE_OV (UINT32_C(12) << 2) #define CP0_CAUSE_EXCCODE_TR (UINT32_C(13) << 2) /* 14 is reserved */ #define CP0_CAUSE_EXCCODE_FPE (UINT32_C(15) << 2) /* 16-22 are reserved */ #define CP0_CAUSE_EXCCODE_WATCH (UINT32_C(23) << 2) /* 24-31 are reserved */ #define CP0_CAUSE_EXCCODE_MASK (UINT32_C(0x1f) << 2) /* Interrupt Pending */ #define CP0_CAUSE_IP0 UINT32_C(0x00000100) /* sw0 */ #define CP0_CAUSE_IP1 UINT32_C(0x00000200) /* sw1 */ #define CP0_CAUSE_IP2 UINT32_C(0x00000400) /* rcp */ #define CP0_CAUSE_IP3 UINT32_C(0x00000800) /* cart */ #define CP0_CAUSE_IP4 UINT32_C(0x00001000) /* pif */ #define CP0_CAUSE_IP5 UINT32_C(0x00002000) #define CP0_CAUSE_IP6 UINT32_C(0x00004000) #define CP0_CAUSE_IP7 UINT32_C(0x00008000) /* timer */ #define CP0_CAUSE_CE1 UINT32_C(0x10000000) #define CP0_CAUSE_CE2 UINT32_C(0x20000000) #define CP0_CAUSE_BD UINT32_C(0x80000000) enum r4300_cp0_registers { CP0_INDEX_REG, CP0_RANDOM_REG, CP0_ENTRYLO0_REG, CP0_ENTRYLO1_REG, CP0_CONTEXT_REG, CP0_PAGEMASK_REG, CP0_WIRED_REG, CP0_UNUSED_7, CP0_BADVADDR_REG, CP0_COUNT_REG, CP0_ENTRYHI_REG, CP0_COMPARE_REG, CP0_STATUS_REG, CP0_CAUSE_REG, CP0_EPC_REG, CP0_PREVID_REG, CP0_CONFIG_REG, CP0_LLADDR_REG, CP0_WATCHLO_REG, CP0_WATCHHI_REG, CP0_XCONTEXT_REG, CP0_UNUSED_21, CP0_UNUSED_22, CP0_UNUSED_23, CP0_UNUSED_24, CP0_UNUSED_25, CP0_PARITYERR_REG, CP0_CACHEERR_REG, CP0_TAGLO_REG, CP0_TAGHI_REG, CP0_ERROREPC_REG, CP0_UNUSED_31, CP0_REGS_COUNT }; enum { INTERRUPT_NODES_POOL_CAPACITY = 16 }; struct interrupt_event { int type; unsigned int count; }; struct node { struct interrupt_event data; struct node *next; }; struct pool { struct node nodes [INTERRUPT_NODES_POOL_CAPACITY]; struct node* stack[INTERRUPT_NODES_POOL_CAPACITY]; size_t index; }; struct interrupt_queue { struct pool pool; struct node* first; }; struct interrupt_handler { void* opaque; void (*callback)(void*); }; enum { CP0_INTERRUPT_HANDLERS_COUNT = 16 }; enum { INTR_UNSAFE_R4300 = 0x01, INTR_UNSAFE_RSP = 0x02, }; struct cp0 { #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ uint32_t regs[CP0_REGS_COUNT]; uint64_t latch; #endif /* set to avoid savestates/reset if state may be inconsistent * (e.g. in the middle of an instruction) */ unsigned int interrupt_unsafe_state; struct interrupt_queue q; unsigned int next_interrupt; #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ int cycle_count; #endif struct interrupt_handler interrupt_handlers[CP0_INTERRUPT_HANDLERS_COUNT]; #ifdef NEW_DYNAREC /* New dynarec uses a different memory layout */ struct new_dynarec_hot_state* new_dynarec_hot_state; #endif uint32_t last_addr; unsigned int count_per_op; unsigned int count_per_op_denom_pot; struct tlb tlb; }; #ifndef NEW_DYNAREC #define R4300_CP0_REGS_OFFSET (\ offsetof(struct r4300_core, cp0) + \ offsetof(struct cp0, regs)) #else #define R4300_CP0_REGS_OFFSET (\ offsetof(struct r4300_core, new_dynarec_hot_state) + \ offsetof(struct new_dynarec_hot_state, cp0_regs)) #endif void init_cp0(struct cp0* cp0, unsigned int count_per_op, unsigned int count_per_op_denom_pot, struct new_dynarec_hot_state* new_dynarec_hot_state, const struct interrupt_handler* interrupt_handlers); void poweron_cp0(struct cp0* cp0); uint32_t* r4300_cp0_regs(struct cp0* cp0); uint64_t* r4300_cp0_latch(struct cp0* cp0); uint32_t* r4300_cp0_last_addr(struct cp0* cp0); unsigned int* r4300_cp0_next_interrupt(struct cp0* cp0); /* cycle_count is a negative number representing the number of cycles left until next interrupt is taken. Next interrupt is taken whether cycle_count value is positive or null */ int* r4300_cp0_cycle_count(struct cp0* cp0); int check_cop1_unusable(struct r4300_core* r4300); int check_cop2_unusable(struct r4300_core* r4300); void cp0_update_count(struct r4300_core* r4300); void TLB_refill_exception(struct r4300_core* r4300, uint32_t address, int w); void exception_general(struct r4300_core* r4300); #endif /* M64P_DEVICE_R4300_CP0_H */ mupen64plus-core-src-2.6.0/src/device/r4300/cp1.c000066400000000000000000000114751464506436200211030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cp1.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "cp0.h" #include "cp1.h" #include "new_dynarec/new_dynarec.h" #define FCR31_FS_BIT UINT32_C(0x1000000) #ifdef M64P_BIG_ENDIAN #define DOUBLE_HALF_XOR 1 #else #define DOUBLE_HALF_XOR 0 #endif void init_cp1(struct cp1* cp1, struct new_dynarec_hot_state* new_dynarec_hot_state) { #ifdef NEW_DYNAREC cp1->new_dynarec_hot_state = new_dynarec_hot_state; #endif } void poweron_cp1(struct cp1* cp1) { memset(cp1->regs, 0, 32 * sizeof(cp1->regs[0])); *r4300_cp1_fcr0(cp1) = UINT32_C(0xA00); *r4300_cp1_fcr31(cp1) = 0; set_fpr_pointers(cp1, UINT32_C(0x34000000)); /* c0_status value at poweron */ #ifdef OSAL_SSE cp1->flush_mode = _MM_GET_FLUSH_ZERO_MODE(); #endif update_x86_rounding_mode(cp1); } cp1_reg* r4300_cp1_regs(struct cp1* cp1) { return cp1->regs; } float** r4300_cp1_regs_simple(struct cp1* cp1) { #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ return cp1->regs_simple; #else return cp1->new_dynarec_hot_state->cp1_regs_simple; #endif } double** r4300_cp1_regs_double(struct cp1* cp1) { #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ return cp1->regs_double; #else return cp1->new_dynarec_hot_state->cp1_regs_double; #endif } uint32_t* r4300_cp1_fcr0(struct cp1* cp1) { #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ return &cp1->fcr0; #else return &cp1->new_dynarec_hot_state->cp1_fcr0; #endif } uint32_t* r4300_cp1_fcr31(struct cp1* cp1) { #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ return &cp1->fcr31; #else return &cp1->new_dynarec_hot_state->cp1_fcr31; #endif } void set_fpr_pointers(struct cp1* cp1, uint32_t newStatus) { int i; // update the FPR register pointers if ((newStatus & CP0_STATUS_FR) == 0) { for (i = 0; i < 32; i++) { (r4300_cp1_regs_simple(cp1))[i] = &cp1->regs[i & ~1].float32[i & 1 ^ DOUBLE_HALF_XOR]; (r4300_cp1_regs_double(cp1))[i] = &cp1->regs[i & ~1].float64; } } else { for (i = 0; i < 32; i++) { (r4300_cp1_regs_simple(cp1))[i] = &cp1->regs[i].float32[DOUBLE_HALF_XOR]; (r4300_cp1_regs_double(cp1))[i] = &cp1->regs[i].float64; } } } /* XXX: This shouldn't really be here, but rounding_mode is used by the * Hacktarux JIT and updated by CTC1 and saved states. Figure out a better * place for this. */ void update_x86_rounding_mode(struct cp1* cp1) { uint32_t fcr31 = *r4300_cp1_fcr31(cp1); #ifdef OSAL_SSE uint32_t flush_mode; if (fcr31 & 2) flush_mode = (fcr31 & FCR31_FS_BIT) ? _MM_FLUSH_ZERO_OFF : _MM_FLUSH_ZERO_ON; else flush_mode = _MM_FLUSH_ZERO_ON; if (flush_mode != cp1->flush_mode) { _MM_SET_FLUSH_ZERO_MODE(flush_mode); cp1->flush_mode = flush_mode; } #endif switch (fcr31 & 3) { case 0: /* Round to nearest, or to even if equidistant */ cp1->rounding_mode = UINT32_C(0x33F); break; case 1: /* Truncate (toward 0) */ cp1->rounding_mode = UINT32_C(0xF3F); break; case 2: /* Round up (toward +Inf) */ cp1->rounding_mode = UINT32_C(0xB3F); break; case 3: /* Round down (toward -Inf) */ cp1->rounding_mode = UINT32_C(0x73F); break; } } mupen64plus-core-src-2.6.0/src/device/r4300/cp1.h000066400000000000000000000102011464506436200210720ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cp1.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_CP1_H #define M64P_DEVICE_R4300_CP1_H #include #include "osal/preproc.h" #include "new_dynarec/new_dynarec.h" typedef union { int64_t dword; double float64; float float32[2]; }cp1_reg; struct cp1 { cp1_reg regs[32]; #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ uint32_t fcr0; uint32_t fcr31; float* regs_simple[32]; double* regs_double[32]; #endif /* This is the x86 version of the rounding mode contained in FCR31. * It should not really be here. Its size should also really be uint16_t, * because FLDCW (Floating-point LoaD Control Word) loads 16-bit control * words. However, x86/gcop1.c and x86-64/gcop1.c update this variable * using 32-bit stores. */ uint32_t rounding_mode; #ifdef OSAL_SSE uint32_t flush_mode; #endif #ifdef NEW_DYNAREC /* New dynarec uses a different memory layout */ struct new_dynarec_hot_state* new_dynarec_hot_state; #endif }; #ifndef NEW_DYNAREC #define R4300_CP1_REGS_S_OFFSET (\ offsetof(struct r4300_core, cp1) + \ offsetof(struct cp1, regs_simple)) #else #define R4300_CP1_REGS_S_OFFSET (\ offsetof(struct r4300_core, new_dynarec_hot_state) + \ offsetof(struct new_dynarec_hot_state, cp1_regs_simple)) #endif #ifndef NEW_DYNAREC #define R4300_CP1_REGS_D_OFFSET (\ offsetof(struct r4300_core, cp1) + \ offsetof(struct cp1, regs_double)) #else #define R4300_CP1_REGS_D_OFFSET (\ offsetof(struct r4300_core, new_dynarec_hot_state) + \ offsetof(struct new_dynarec_hot_state, cp1_regs_double)) #endif #ifndef NEW_DYNAREC #define R4300_CP1_FCR0_OFFSET (\ offsetof(struct r4300_core, cp1) + \ offsetof(struct cp1, fcr0)) #else #define R4300_CP1_FCR0_OFFSET (\ offsetof(struct r4300_core, new_dynarec_hot_state) + \ offsetof(struct new_dynarec_hot_state, cp1_fcr0)) #endif #ifndef NEW_DYNAREC #define R4300_CP1_FCR31_OFFSET (\ offsetof(struct r4300_core, cp1) + \ offsetof(struct cp1, fcr31)) #else #define R4300_CP1_FCR31_OFFSET (\ offsetof(struct r4300_core, new_dynarec_hot_state) + \ offsetof(struct new_dynarec_hot_state, cp1_fcr31)) #endif void init_cp1(struct cp1* cp1, struct new_dynarec_hot_state* new_dynarec_hot_state); void poweron_cp1(struct cp1* cp1); cp1_reg* r4300_cp1_regs(struct cp1* cp1); float** r4300_cp1_regs_simple(struct cp1* cp1); double** r4300_cp1_regs_double(struct cp1* cp1); uint32_t* r4300_cp1_fcr0(struct cp1* cp1); uint32_t* r4300_cp1_fcr31(struct cp1* cp1); void set_fpr_pointers(struct cp1* cp1, uint32_t newStatus); void update_x86_rounding_mode(struct cp1* cp1); #endif /* M64P_DEVICE_R4300_CP1_H */ mupen64plus-core-src-2.6.0/src/device/r4300/cp2.c000066400000000000000000000041651464506436200211020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cp2.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "cp0.h" #include "cp1.h" #include "cp2.h" #include "new_dynarec/new_dynarec.h" #define FCR31_FS_BIT UINT32_C(0x2000000) void init_cp2(struct cp2* cp2, struct new_dynarec_hot_state* new_dynarec_hot_state) { #ifdef NEW_DYNAREC cp2->new_dynarec_hot_state = new_dynarec_hot_state; #endif } void poweron_cp2(struct cp2* cp2) { *r4300_cp2_latch(cp2) = 0; } uint64_t* r4300_cp2_latch(struct cp2* cp2) { #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ return &cp2->latch; #else return &cp2->new_dynarec_hot_state->cp2_latch; #endif } mupen64plus-core-src-2.6.0/src/device/r4300/cp2.h000066400000000000000000000040251464506436200211020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cp2.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_CP2_H #define M64P_DEVICE_R4300_CP2_H #include #include "osal/preproc.h" #include "new_dynarec/new_dynarec.h" struct cp2 { uint64_t latch; #ifdef NEW_DYNAREC /* New dynarec uses a different memory layout */ struct new_dynarec_hot_state* new_dynarec_hot_state; #endif }; void init_cp2(struct cp2* cp2, struct new_dynarec_hot_state* new_dynarec_hot_state); void poweron_cp2(struct cp2* cp2); uint64_t* r4300_cp2_latch(struct cp2* cp2); #endif /* M64P_DEVICE_R4300_CP2_H */ mupen64plus-core-src-2.6.0/src/device/r4300/fpu.h000066400000000000000000000726061464506436200212220ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - fpu.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2010 Ari64 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_FPU_H #define M64P_DEVICE_R4300_FPU_H #include #include #ifdef _MSC_VER #define M64P_FPU_INLINE static __inline #include #include static __inline double round(double x) { return floor(x + 0.5); } static __inline float roundf(float x) { return (float)floor(x + 0.5); } static __inline double trunc(double x) { return (double)(int)x; } static __inline float truncf(float x) { return (float)(int)x; } #if !defined(isnan) #define isnan _isnan #endif #else #define M64P_FPU_INLINE static inline #include #endif #define FCR31_CMP_BIT UINT32_C(0x800000) #define FCR31_CAUSE_BITS UINT32_C(0x01F000) #define FCR31_CAUSE_INEXACT_BIT UINT32_C(0x001000) #define FCR31_CAUSE_UNDERFLOW_BIT UINT32_C(0x002000) #define FCR31_CAUSE_OVERFLOW_BIT UINT32_C(0x004000) #define FCR31_CAUSE_DIVBYZERO_BIT UINT32_C(0x008000) #define FCR31_CAUSE_INVALIDOP_BIT UINT32_C(0x010000) #define FCR31_CAUSE_UNIMPLOP_BIT UINT32_C(0x020000) #define FCR31_ENABLE_INEXACT_BIT UINT32_C(0x000080) #define FCR31_ENABLE_UNDERFLOW_BIT UINT32_C(0x000100) #define FCR31_ENABLE_OVERFLOW_BIT UINT32_C(0x000200) #define FCR31_ENABLE_DIVBYZERO_BIT UINT32_C(0x000400) #define FCR31_ENABLE_INVALIDOP_BIT UINT32_C(0x000800) #define FCR31_FLAG_INEXACT_BIT UINT32_C(0x000004) #define FCR31_FLAG_UNDERFLOW_BIT UINT32_C(0x000008) #define FCR31_FLAG_OVERFLOW_BIT UINT32_C(0x000010) #define FCR31_FLAG_DIVBYZERO_BIT UINT32_C(0x000020) #define FCR31_FLAG_INVALIDOP_BIT UINT32_C(0x000040) M64P_FPU_INLINE void set_rounding(uint32_t fcr31) { switch(fcr31 & 3) { case 0: /* Round to nearest, or to even if equidistant */ fesetround(FE_TONEAREST); break; case 1: /* Truncate (toward 0) */ fesetround(FE_TOWARDZERO); break; case 2: /* Round up (toward +Inf) */ fesetround(FE_UPWARD); break; case 3: /* Round down (toward -Inf) */ fesetround(FE_DOWNWARD); break; } } #ifdef ACCURATE_FPU_BEHAVIOR M64P_FPU_INLINE void fpu_reset_cause(uint32_t* fcr31) { (*fcr31) &= ~FCR31_CAUSE_BITS; } M64P_FPU_INLINE void fpu_reset_exceptions() { feclearexcept(FE_ALL_EXCEPT); } M64P_FPU_INLINE int fpu_check_exceptions(uint32_t* fcr31) { int fexceptions; fexceptions = fetestexcept(FE_ALL_EXCEPT) & FE_ALL_EXCEPT; if (fexceptions & FE_DIVBYZERO) { (*fcr31) |= FCR31_CAUSE_DIVBYZERO_BIT; (*fcr31) |= FCR31_FLAG_DIVBYZERO_BIT; } if (fexceptions & FE_INEXACT) { (*fcr31) |= FCR31_CAUSE_INEXACT_BIT; (*fcr31) |= FCR31_FLAG_INEXACT_BIT; } if (fexceptions & FE_UNDERFLOW) { (*fcr31) |= FCR31_CAUSE_UNDERFLOW_BIT; (*fcr31) |= FCR31_FLAG_UNDERFLOW_BIT; } if (fexceptions & FE_OVERFLOW) { (*fcr31) |= FCR31_CAUSE_OVERFLOW_BIT; (*fcr31) |= FCR31_FLAG_OVERFLOW_BIT; } if (fexceptions & FE_INVALID) { (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; } return 0; // TODO: exceptions } M64P_FPU_INLINE void fpu_check_input_float(uint32_t* fcr31, const float* value) { switch (fpclassify(*value)) { default: case FP_SUBNORMAL: // TODO return; case FP_NAN: (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; break; } } M64P_FPU_INLINE void fpu_check_input_double(uint32_t* fcr31, const double* value) { switch (fpclassify(*value)) { default: case FP_SUBNORMAL: // TODO return; case FP_NAN: (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; break; } } M64P_FPU_INLINE void fpu_check_output_float(uint32_t* fcr31, const float* value) { switch (fpclassify(*value)) { case FP_SUBNORMAL: (*fcr31) |= FCR31_CAUSE_UNDERFLOW_BIT; (*fcr31) |= FCR31_FLAG_UNDERFLOW_BIT; (*fcr31) |= FCR31_CAUSE_INEXACT_BIT; (*fcr31) |= FCR31_FLAG_INEXACT_BIT; break; case FP_NAN: break; default: break; } } M64P_FPU_INLINE void fpu_check_output_double(uint32_t* fcr31, const double* value) { switch (fpclassify(*value)) { case FP_SUBNORMAL: (*fcr31) |= FCR31_CAUSE_UNDERFLOW_BIT; (*fcr31) |= FCR31_FLAG_UNDERFLOW_BIT; (*fcr31) |= FCR31_CAUSE_INEXACT_BIT; (*fcr31) |= FCR31_FLAG_INEXACT_BIT; break; case FP_NAN: break; default: break; } } #else M64P_FPU_INLINE void fpu_reset_cause(uint32_t* fcr31) { } M64P_FPU_INLINE void fpu_reset_exceptions() { } M64P_FPU_INLINE int fpu_check_exceptions(uint32_t* fcr31) { return 0; } M64P_FPU_INLINE void fpu_check_input_float(uint32_t* fcr31, const float* value) { } M64P_FPU_INLINE void fpu_check_input_double(uint32_t* fcr31, const double* value) { } M64P_FPU_INLINE void fpu_check_output_float(uint32_t* fcr31, const float* value) { } M64P_FPU_INLINE void fpu_check_output_double(uint32_t* fcr31, const double* value) { } #endif /* ACCURATE_FPU_BEHAVIOR */ M64P_FPU_INLINE void cvt_s_w(uint32_t* fcr31, const int32_t* source, float* dest) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_reset_exceptions(); *dest = (float)*source; fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, dest); } M64P_FPU_INLINE void cvt_d_w(uint32_t* fcr31, const int32_t* source, double* dest) { fpu_reset_cause(fcr31); fpu_reset_exceptions(); *dest = (double)*source; fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, dest); } M64P_FPU_INLINE void cvt_s_l(uint32_t* fcr31, const int64_t* source, float* dest) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_reset_exceptions(); *dest = (float)*source; fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, dest); } M64P_FPU_INLINE void cvt_d_l(uint32_t* fcr31, const int64_t* source, double* dest) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_reset_exceptions(); *dest = (double)*source; fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, dest); } M64P_FPU_INLINE void cvt_d_s(uint32_t* fcr31, const float* source, double* dest) { fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source); fpu_reset_exceptions(); *dest = (double)*source; fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, dest); } M64P_FPU_INLINE void cvt_s_d(uint32_t* fcr31, const double* source, float* dest) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source); fpu_reset_exceptions(); *dest = (float)*source; fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, dest); } M64P_FPU_INLINE void round_l_s(const float* source, int64_t* dest) { float remainder = *source - floorf(*source); if (remainder == 0.5) { if (*source < 0) { *dest = (int64_t)truncf(*source) % 2 != 0 ? (int64_t)floorf(*source) : (int64_t) ceilf(*source); } else { *dest = (int64_t)truncf(*source) % 2 != 0 ? (int64_t)ceilf(*source) : (int64_t)floorf(*source); } } else { *dest = (int64_t)roundf(*source); } } M64P_FPU_INLINE void round_w_s(const float* source, int32_t* dest) { float remainder = *source - floorf(*source); if (remainder == 0.5) { if (*source < 0) { *dest = (int32_t)truncf(*source) % 2 != 0 ? (int32_t)floorf(*source) : (int32_t)ceilf(*source); } else { *dest = (int32_t)truncf(*source) % 2 != 0 ? (int32_t)ceilf(*source) : (int32_t)floorf(*source); } } else { *dest = (int32_t)roundf(*source); } } M64P_FPU_INLINE void trunc_l_s(const float* source, int64_t* dest) { *dest = (int64_t)truncf(*source); } M64P_FPU_INLINE void trunc_w_s(const float* source, int32_t* dest) { *dest = (int32_t)truncf(*source); } M64P_FPU_INLINE void ceil_l_s(const float* source, int64_t* dest) { *dest = (int64_t)ceilf(*source); } M64P_FPU_INLINE void ceil_w_s(const float* source, int32_t* dest) { *dest = (int32_t)ceilf(*source); } M64P_FPU_INLINE void floor_l_s(const float* source, int64_t* dest) { *dest = (int64_t)floorf(*source); } M64P_FPU_INLINE void floor_w_s(const float* source, int32_t* dest) { *dest = (int32_t)floorf(*source); } M64P_FPU_INLINE void round_l_d(const double* source, int64_t* dest) { double remainder = *source - floor(*source); if (remainder == 0.5) { if (*source < 0) { *dest = (int64_t)trunc(*source) % 2 != 0 ? (int64_t)floor(*source) : (int64_t)ceil(*source); } else { *dest = (int64_t)trunc(*source) % 2 != 0 ? (int64_t)ceil(*source) : (int64_t)floor(*source); } } else { *dest = (int64_t)round(*source); } } M64P_FPU_INLINE void round_w_d(const double* source, int32_t* dest) { double remainder = *source - floor(*source); if (remainder == 0.5) { if (*source < 0) { *dest = (int32_t)trunc(*source) % 2 != 0 ? (int32_t)floor(*source) : (int32_t)ceil(*source); } else { *dest = (int32_t)trunc(*source) % 2 != 0 ? (int32_t)ceil(*source) : (int32_t)floor(*source); } } else { *dest = (int32_t)round(*source); } } M64P_FPU_INLINE void trunc_l_d(const double* source, int64_t* dest) { *dest = (int64_t)trunc(*source); } M64P_FPU_INLINE void trunc_w_d(const double* source, int32_t* dest) { *dest = (int32_t)trunc(*source); } M64P_FPU_INLINE void ceil_l_d(const double* source, int64_t* dest) { *dest = (int64_t)ceil(*source); } M64P_FPU_INLINE void ceil_w_d(const double* source, int32_t* dest) { *dest = (int32_t)ceil(*source); } M64P_FPU_INLINE void floor_l_d(const double* source, int64_t* dest) { *dest = (int64_t)floor(*source); } M64P_FPU_INLINE void floor_w_d(const double* source, int32_t* dest) { *dest = (int32_t)floor(*source); } M64P_FPU_INLINE void cvt_w_s(uint32_t* fcr31, const float* source, int32_t* dest) { fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source); fpu_reset_exceptions(); switch(*fcr31 & 3) { case 0: round_w_s(source, dest); return; case 1: trunc_w_s(source, dest); return; case 2: ceil_w_s (source, dest); return; case 3: floor_w_s(source, dest); return; } fpu_check_exceptions(fcr31); } M64P_FPU_INLINE void cvt_w_d(uint32_t* fcr31, const double* source, int32_t* dest) { fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source); fpu_reset_exceptions(); switch(*fcr31 & 3) { case 0: round_w_d(source, dest); return; case 1: trunc_w_d(source, dest); return; case 2: ceil_w_d (source, dest); return; case 3: floor_w_d(source, dest); return; } fpu_check_exceptions(fcr31); } M64P_FPU_INLINE void cvt_l_s(uint32_t* fcr31, const float* source, int64_t* dest) { fpu_reset_cause(fcr31); fpu_reset_exceptions(); switch(*fcr31 & 3) { case 0: round_l_s(source, dest); return; case 1: trunc_l_s(source, dest); return; case 2: ceil_l_s (source, dest); return; case 3: floor_l_s(source, dest); return; } fpu_check_exceptions(fcr31); } M64P_FPU_INLINE void cvt_l_d(uint32_t* fcr31, const double* source, int64_t* dest) { fpu_reset_cause(fcr31); fpu_reset_exceptions(); switch(*fcr31 & 3) { case 0: round_l_d(source, dest); return; case 1: trunc_l_d(source, dest); return; case 2: ceil_l_d (source, dest); return; case 3: floor_l_d(source, dest); return; } fpu_check_exceptions(fcr31); } M64P_FPU_INLINE void c_f_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if ((isnan(*source) || isnan(*target))) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 &= ~FCR31_CMP_BIT; } M64P_FPU_INLINE void c_un_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if ((isnan(*source) || isnan(*target))) { (*fcr31) |= FCR31_CMP_BIT; return; } *fcr31 = (isnan(*source) || isnan(*target)) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_eq_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ueq_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_olt_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ult_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ole_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ule_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 &~ FCR31_CMP_BIT); } M64P_FPU_INLINE void c_sf_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 &= ~FCR31_CMP_BIT; } M64P_FPU_INLINE void c_ngle_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 &= ~FCR31_CMP_BIT; } M64P_FPU_INLINE void c_seq_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 &~ FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ngl_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_lt_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_nge_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_le_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ngt_s(uint32_t* fcr31, const float* source, const float* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_f_d(uint32_t* fcr31) { fpu_reset_cause(fcr31); *fcr31 &= ~FCR31_CMP_BIT; } M64P_FPU_INLINE void c_un_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; return; } *fcr31 = (isnan(*source) || isnan(*target)) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_eq_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ueq_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_olt_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ult_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ole_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ule_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_sf_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 &= ~FCR31_CMP_BIT; } M64P_FPU_INLINE void c_ngle_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 &= ~FCR31_CMP_BIT; } M64P_FPU_INLINE void c_seq_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ngl_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source == *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_lt_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_nge_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source < *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_le_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) &= ~FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void c_ngt_d(uint32_t* fcr31, const double* source, const double* target) { fpu_reset_cause(fcr31); if (isnan(*source) || isnan(*target)) { (*fcr31) |= FCR31_CMP_BIT; (*fcr31) |= FCR31_CAUSE_INVALIDOP_BIT; (*fcr31) |= FCR31_FLAG_INVALIDOP_BIT; return; } *fcr31 = (*source <= *target) ? (*fcr31 | FCR31_CMP_BIT) : (*fcr31 & ~FCR31_CMP_BIT); } M64P_FPU_INLINE void add_s(uint32_t* fcr31, const float* source1, const float* source2, float* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source1); fpu_check_input_float(fcr31, source2); fpu_reset_exceptions(); *target = *source1 + *source2; fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, target); } M64P_FPU_INLINE void sub_s(uint32_t* fcr31, const float* source1, const float* source2, float* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source1); fpu_check_input_float(fcr31, source2); fpu_reset_exceptions(); *target = *source1 - *source2; fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, target); } M64P_FPU_INLINE void mul_s(uint32_t* fcr31, const float* source1, const float* source2, float* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source1); fpu_check_input_float(fcr31, source2); fpu_reset_exceptions(); *target = *source1 * *source2; fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, target); } M64P_FPU_INLINE void div_s(uint32_t* fcr31, const float* source1, const float* source2, float* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source1); fpu_check_input_float(fcr31, source2); fpu_reset_exceptions(); *target = *source1 / *source2; fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, target); } M64P_FPU_INLINE void sqrt_s(uint32_t* fcr31, const float* source, float* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source); fpu_reset_exceptions(); *target = sqrtf(*source); fpu_check_exceptions(fcr31); fpu_check_output_float(fcr31, target); } M64P_FPU_INLINE void abs_s(uint32_t* fcr31, const float* source, float* target) { fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source); *target = fabsf(*source); fpu_check_output_float(fcr31, target); } M64P_FPU_INLINE void mov_s(const float* source, float* target) { *target = *source; } M64P_FPU_INLINE void neg_s(uint32_t* fcr31, const float* source, float* target) { fpu_reset_cause(fcr31); fpu_check_input_float(fcr31, source); *target = - *source; fpu_check_output_float(fcr31, target); } M64P_FPU_INLINE void add_d(uint32_t* fcr31, const double* source1, const double* source2, double* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source1); fpu_check_input_double(fcr31, source2); fpu_reset_exceptions(); *target = *source1 + *source2; fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, target); } M64P_FPU_INLINE void sub_d(uint32_t* fcr31, const double* source1, const double* source2, double* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source1); fpu_check_input_double(fcr31, source2); fpu_reset_exceptions(); *target = *source1 - *source2; fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, target); } M64P_FPU_INLINE void mul_d(uint32_t* fcr31, const double* source1, const double* source2, double* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source1); fpu_check_input_double(fcr31, source2); fpu_reset_exceptions(); *target = *source1 * *source2; fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, target); } M64P_FPU_INLINE void div_d(uint32_t* fcr31, const double* source1, const double* source2, double* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source1); fpu_check_input_double(fcr31, source2); fpu_reset_exceptions(); *target = *source1 / *source2; fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, target); } M64P_FPU_INLINE void sqrt_d(uint32_t* fcr31, const double* source, double* target) { set_rounding(*fcr31); fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source); fpu_reset_exceptions(); *target = sqrt(*source); fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, target); } M64P_FPU_INLINE void abs_d(uint32_t* fcr31, const double* source, double* target) { fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source); fpu_reset_exceptions(); *target = fabs(*source); fpu_check_exceptions(fcr31); fpu_check_output_double(fcr31, target); } M64P_FPU_INLINE void mov_d(const double* source, double* target) { *target = *source; } M64P_FPU_INLINE void neg_d(uint32_t* fcr31, const double* source, double* target) { fpu_reset_cause(fcr31); fpu_check_input_double(fcr31, source); *target = - *source; fpu_check_output_double(fcr31, target); } #endif /* M64P_DEVICE_R4300_FPU_H */ mupen64plus-core-src-2.6.0/src/device/r4300/idec.c000066400000000000000000000701301464506436200213150ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - idec.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2018 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "idec.h" #include "r4300_core.h" #include /* define registers/small constants instruction fields */ #define U53_NONE U53(IDEC_REGTYPE_NONE, 0) #define U53_SA U53(IDEC_REGTYPE_NONE, 6) #define U53_RD U53(IDEC_REGTYPE_GPR, 11) #define U53_RT U53(IDEC_REGTYPE_GPR, 16) #define U53_RS U53(IDEC_REGTYPE_GPR, 21) #define U53_FD U53(IDEC_REGTYPE_FPR, 6) #define U53_FDS U53(IDEC_REGTYPE_FPR32, 6) #define U53_FDD U53(IDEC_REGTYPE_FPR64, 6) #define U53_FDW U53(IDEC_REGTYPE_FPR32, 6) #define U53_FDL U53(IDEC_REGTYPE_FPR64, 6) #define U53_FCR U53(IDEC_REGTYPE_FCR, 11) #define U53_FS U53(IDEC_REGTYPE_FPR, 11) #define U53_FS32 U53(IDEC_REGTYPE_FPR32, 11) #define U53_FS64 U53(IDEC_REGTYPE_FPR64, 11) #define U53_FT U53(IDEC_REGTYPE_FPR, 16) #define U53_FT32 U53(IDEC_REGTYPE_FPR32, 16) #define U53_FT64 U53(IDEC_REGTYPE_FPR64, 16) #define U53_FMT U53(IDEC_REGTYPE_NONE, 21) #define U53_CACHEOP U53(IDEC_REGTYPE_NONE, 16) #define U53_CPR0 U53(IDEC_REGTYPE_CPR0, 11) /* disabled because not part of r4300 */ #define U53_CCR0 U53(IDEC_REGTYPE_NONE, 11) #define U53_CCR2 U53(IDEC_REGTYPE_NONE, 11) #define U53_CPR2D U53(IDEC_REGTYPE_NONE, 11) #define U53_CPR2T U53(IDEC_REGTYPE_NONE, 16) /* define immediate instruction fields */ /* imask, smask, lshift */ #define IMM_NONE 0, 0, 0 #define IMM_OFFSET 0xffff, 0x8000, 0 #define IMM_OFFSET4 0xffff, 0x8000, 2 #define IMM_LUI 0xffff, 0x8000, 16 #define IMM_SIMM 0xffff, 0x8000, 0 #define IMM_ZIMM 0xffff, 0x0000, 0 #define IMM_TARGET 0x3ffffff, 0x0000, 2 /* define instruction decoders IMM, RD/FD, RT/FT, RS/FS, FMT/SA */ #define IDEC_NONE IMM_NONE, { U53_NONE, U53_NONE, U53_NONE, U53_NONE } #define IDEC_CACHEOP_BASE_OFFSET IMM_OFFSET, { U53_NONE, U53_CACHEOP, U53_RS, U53_NONE } #define IDEC_FD_FS_FMT IMM_NONE, { U53_FD, U53_NONE, U53_FS, U53_FMT } #define IDEC_FDS_FS_FMT IMM_NONE, { U53_FDS, U53_NONE, U53_FS, U53_FMT } #define IDEC_FDD_FS_FMT IMM_NONE, { U53_FDD, U53_NONE, U53_FS, U53_FMT } #define IDEC_FDW_FS_FMT IMM_NONE, { U53_FDW, U53_NONE, U53_FS, U53_FMT } #define IDEC_FDL_FS_FMT IMM_NONE, { U53_FDL, U53_NONE, U53_FS, U53_FMT } #define IDEC_FD_FS_FT_FMT IMM_NONE, { U53_FD, U53_FT, U53_FS, U53_FMT } #define IDEC_FS_FT_FMT IMM_NONE, { U53_NONE, U53_FT, U53_FS, U53_FMT } #define IDEC_OFFSET IMM_OFFSET4, { U53_NONE, U53_NONE, U53_NONE, U53_NONE } #define IDEC_RD IMM_NONE, { U53_RD, U53_NONE, U53_NONE, U53_NONE } #define IDEC_RD_RS IMM_NONE, { U53_RD, U53_NONE, U53_RS, U53_NONE } #define IDEC_RD_RS_RT IMM_NONE, { U53_RD, U53_RT, U53_RS, U53_NONE } #define IDEC_RD_RT_RS IMM_NONE, { U53_RD, U53_RT, U53_RS, U53_NONE } #define IDEC_RD_RT_SA IMM_NONE, { U53_RD, U53_RT, U53_NONE, U53_SA } #define IDEC_RS IMM_NONE, { U53_NONE, U53_NONE, U53_RS, U53_NONE } #define IDEC_RS_OFFSET IMM_OFFSET4, { U53_NONE, U53_NONE, U53_RS, U53_NONE } #define IDEC_RS_RT IMM_NONE, { U53_NONE, U53_RT, U53_RS, U53_NONE } #define IDEC_RS_RT_OFFSET IMM_OFFSET4, { U53_NONE, U53_RT, U53_RS, U53_NONE } #define IDEC_RS_SIMM IMM_SIMM, { U53_NONE, U53_NONE, U53_RS, U53_NONE } #define IDEC_RT_BASE_OFFSET IMM_OFFSET, { U53_NONE, U53_RT, U53_RS, U53_NONE } #define IDEC_CPR2_BASE_OFFSET IMM_OFFSET, { U53_NONE, U53_CPR2T, U53_RS, U53_NONE } #define IDEC_FT32_BASE_OFFSET IMM_OFFSET, { U53_NONE, U53_FT32, U53_RS, U53_NONE } #define IDEC_FT64_BASE_OFFSET IMM_OFFSET, { U53_NONE, U53_FT64, U53_RS, U53_NONE } #define IDEC_RT_LUI IMM_LUI, { U53_NONE, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_CPR0 IMM_NONE, { U53_CPR0, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_FS32 IMM_NONE, { U53_FS32, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_FS64 IMM_NONE, { U53_FS64, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_CPR2 IMM_NONE, { U53_CPR2D, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_CCR0 IMM_NONE, { U53_CCR0, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_FCR IMM_NONE, { U53_FCR, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_CCR2 IMM_NONE, { U53_CCR2, U53_RT, U53_NONE, U53_NONE } #define IDEC_RT_RS_SIMM IMM_SIMM, { U53_NONE, U53_RT, U53_RS, U53_NONE } #define IDEC_RT_RS_ZIMM IMM_ZIMM, { U53_NONE, U53_RT, U53_RS, U53_NONE } #define IDEC_TARGET IMM_TARGET, { U53_NONE, U53_NONE, U53_NONE, U53_NONE } #define RESERVED { R4300_OP_RESERVED, IDEC_NONE } #define ADD { R4300_OP_ADD, IDEC_RD_RS_RT } #define ADDI { R4300_OP_ADDI, IDEC_RT_RS_SIMM } #define ADDIU { R4300_OP_ADDIU, IDEC_RT_RS_SIMM } #define ADDU { R4300_OP_ADDU, IDEC_RD_RS_RT } #define AND { R4300_OP_AND, IDEC_RD_RS_RT } #define ANDI { R4300_OP_ANDI, IDEC_RT_RS_ZIMM } #define BC0F { R4300_OP_BC0F, IDEC_OFFSET } #define BC1F { R4300_OP_BC1F, IDEC_OFFSET } #define BC2F { R4300_OP_BC2F, IDEC_OFFSET } #define BC0FL { R4300_OP_BC0FL, IDEC_OFFSET } #define BC1FL { R4300_OP_BC1FL, IDEC_OFFSET } #define BC2FL { R4300_OP_BC2FL, IDEC_OFFSET } #define BC0T { R4300_OP_BC0T, IDEC_OFFSET } #define BC1T { R4300_OP_BC1T, IDEC_OFFSET } #define BC2T { R4300_OP_BC2T, IDEC_OFFSET } #define BC0TL { R4300_OP_BC0TL, IDEC_OFFSET } #define BC1TL { R4300_OP_BC1TL, IDEC_OFFSET } #define BC2TL { R4300_OP_BC2TL, IDEC_OFFSET } #define BEQ { R4300_OP_BEQ, IDEC_RS_RT_OFFSET } #define BEQL { R4300_OP_BEQL, IDEC_RS_RT_OFFSET } #define BGEZ { R4300_OP_BGEZ, IDEC_RS_OFFSET } #define BGEZAL { R4300_OP_BGEZAL, IDEC_RS_OFFSET } #define BGEZALL { R4300_OP_BGEZALL, IDEC_RS_OFFSET } #define BGEZL { R4300_OP_BGEZL, IDEC_RS_OFFSET } #define BGTZ { R4300_OP_BGTZ, IDEC_RS_OFFSET } #define BGTZL { R4300_OP_BGTZL, IDEC_RS_OFFSET } #define BLEZ { R4300_OP_BLEZ, IDEC_RS_OFFSET } #define BLEZL { R4300_OP_BLEZL, IDEC_RS_OFFSET } #define BLTZ { R4300_OP_BLTZ, IDEC_RS_OFFSET } #define BLTZAL { R4300_OP_BLTZAL, IDEC_RS_OFFSET } #define BLTZALL { R4300_OP_BLTZALL, IDEC_RS_OFFSET } #define BLTZL { R4300_OP_BLTZL, IDEC_RS_OFFSET } #define BNE { R4300_OP_BNE, IDEC_RS_RT_OFFSET } #define BNEL { R4300_OP_BNEL, IDEC_RS_RT_OFFSET } #define BREAK { R4300_OP_BREAK, IDEC_NONE } #define CACHE { R4300_OP_CACHE, IDEC_CACHEOP_BASE_OFFSET } #define CFC0 { R4300_OP_CFC0, IDEC_RT_CCR0 } #define CFC1 { R4300_OP_CFC1, IDEC_RT_FCR } #define DCFC1 { R4300_OP_DCFC1, IDEC_RT_FCR } #define CFC2 { R4300_OP_CFC2, IDEC_RT_CCR2 } #define DCFC2 { R4300_OP_DCFC2, IDEC_RT_CCR2 } #define CP1_ABS { R4300_OP_CP1_ABS, IDEC_FD_FS_FMT } #define CP1_ADD { R4300_OP_CP1_ADD, IDEC_FD_FS_FT_FMT } #define CP1_C_EQ { R4300_OP_CP1_C_EQ, IDEC_FS_FT_FMT } #define CP1_C_F { R4300_OP_CP1_C_F, IDEC_FS_FT_FMT } #define CP1_C_LE { R4300_OP_CP1_C_LE, IDEC_FS_FT_FMT } #define CP1_C_LT { R4300_OP_CP1_C_LT, IDEC_FS_FT_FMT } #define CP1_C_NGE { R4300_OP_CP1_C_NGE, IDEC_FS_FT_FMT } #define CP1_C_NGLE { R4300_OP_CP1_C_NGLE, IDEC_FS_FT_FMT } #define CP1_C_NGL { R4300_OP_CP1_C_NGL, IDEC_FS_FT_FMT } #define CP1_C_NGT { R4300_OP_CP1_C_NGT, IDEC_FS_FT_FMT } #define CP1_C_OLE { R4300_OP_CP1_C_OLE, IDEC_FS_FT_FMT } #define CP1_C_OLT { R4300_OP_CP1_C_OLT, IDEC_FS_FT_FMT } #define CP1_C_SEQ { R4300_OP_CP1_C_SEQ, IDEC_FS_FT_FMT } #define CP1_C_SF { R4300_OP_CP1_C_SF, IDEC_FS_FT_FMT } #define CP1_C_UEQ { R4300_OP_CP1_C_UEQ, IDEC_FS_FT_FMT } #define CP1_C_ULE { R4300_OP_CP1_C_ULE, IDEC_FS_FT_FMT } #define CP1_C_ULT { R4300_OP_CP1_C_ULT, IDEC_FS_FT_FMT } #define CP1_C_UN { R4300_OP_CP1_C_UN, IDEC_FS_FT_FMT } #define CP1_CEIL_L { R4300_OP_CP1_CEIL_L, IDEC_FDL_FS_FMT } #define CP1_CEIL_W { R4300_OP_CP1_CEIL_W, IDEC_FDW_FS_FMT } #define CP1_CVT_D { R4300_OP_CP1_CVT_D, IDEC_FDD_FS_FMT } #define CP1_CVT_L { R4300_OP_CP1_CVT_L, IDEC_FDL_FS_FMT } #define CP1_CVT_S { R4300_OP_CP1_CVT_S, IDEC_FDS_FS_FMT } #define CP1_CVT_W { R4300_OP_CP1_CVT_W, IDEC_FDW_FS_FMT } #define CP1_DIV { R4300_OP_CP1_DIV, IDEC_FD_FS_FT_FMT } #define CP1_FLOOR_L { R4300_OP_CP1_FLOOR_L, IDEC_FDL_FS_FMT } #define CP1_FLOOR_W { R4300_OP_CP1_FLOOR_W, IDEC_FDW_FS_FMT } #define CP1_MOV { R4300_OP_CP1_MOV, IDEC_FD_FS_FMT } #define CP1_MUL { R4300_OP_CP1_MUL, IDEC_FD_FS_FT_FMT } #define CP1_NEG { R4300_OP_CP1_NEG, IDEC_FD_FS_FMT } #define CP1_ROUND_L { R4300_OP_CP1_ROUND_L, IDEC_FDL_FS_FMT } #define CP1_ROUND_W { R4300_OP_CP1_ROUND_W, IDEC_FDW_FS_FMT } #define CP1_SQRT { R4300_OP_CP1_SQRT, IDEC_FD_FS_FMT } #define CP1_SUB { R4300_OP_CP1_SUB, IDEC_FD_FS_FT_FMT } #define CP1_TRUNC_L { R4300_OP_CP1_TRUNC_L, IDEC_FDL_FS_FMT } #define CP1_TRUNC_W { R4300_OP_CP1_TRUNC_W, IDEC_FDW_FS_FMT } #define CTC0 { R4300_OP_CTC0, IDEC_RT_CCR0 } #define CTC1 { R4300_OP_CTC1, IDEC_RT_FCR } #define DCTC1 { R4300_OP_DCTC1, IDEC_RT_FCR } #define CTC2 { R4300_OP_CTC2, IDEC_RT_CCR2 } #define DCTC2 { R4300_OP_DCTC2, IDEC_RT_CCR2 } #define DADD { R4300_OP_DADD, IDEC_RD_RS_RT } #define DADDI { R4300_OP_DADDI, IDEC_RT_RS_SIMM } #define DADDIU { R4300_OP_DADDIU, IDEC_RT_RS_SIMM } #define DADDU { R4300_OP_DADDU, IDEC_RD_RS_RT } #define DDIV { R4300_OP_DDIV, IDEC_RS_RT } #define DDIVU { R4300_OP_DDIVU, IDEC_RS_RT } #define DIV { R4300_OP_DIV, IDEC_RS_RT } #define DIVU { R4300_OP_DIVU, IDEC_RS_RT } #define DMFC0 { R4300_OP_DMFC0, IDEC_RT_CPR0 } #define DMFC1 { R4300_OP_DMFC1, IDEC_RT_FS64 } #define DMFC2 { R4300_OP_DMFC2, IDEC_RT_CPR2 } #define DMTC0 { R4300_OP_DMTC0, IDEC_RT_CPR0 } #define DMTC1 { R4300_OP_DMTC1, IDEC_RT_FS64 } #define DMTC2 { R4300_OP_DMTC2, IDEC_RT_CPR2 } #define DMULT { R4300_OP_DMULT, IDEC_RS_RT } #define DMULTU { R4300_OP_DMULTU, IDEC_RS_RT } #define DSLL { R4300_OP_DSLL, IDEC_RD_RT_SA } #define DSLLV { R4300_OP_DSLLV, IDEC_RD_RT_RS } #define DSLL32 { R4300_OP_DSLL32, IDEC_RD_RT_SA } #define DSRA { R4300_OP_DSRA, IDEC_RD_RT_SA } #define DSRAV { R4300_OP_DSRAV, IDEC_RD_RT_RS } #define DSRA32 { R4300_OP_DSRA32, IDEC_RD_RT_SA } #define DSRL { R4300_OP_DSRL, IDEC_RD_RT_SA } #define DSRLV { R4300_OP_DSRLV, IDEC_RD_RT_RS } #define DSRL32 { R4300_OP_DSRL32, IDEC_RD_RT_SA } #define DSUB { R4300_OP_DSUB, IDEC_RD_RS_RT } #define DSUBU { R4300_OP_DSUBU, IDEC_RD_RS_RT } #define ERET { R4300_OP_ERET, IDEC_NONE } #define J { R4300_OP_J, IDEC_TARGET } #define JAL { R4300_OP_JAL, IDEC_TARGET } #define JALR { R4300_OP_JALR, IDEC_RD_RS } #define JR { R4300_OP_JR, IDEC_RS } #define LB { R4300_OP_LB, IDEC_RT_BASE_OFFSET } #define LBU { R4300_OP_LBU, IDEC_RT_BASE_OFFSET } #define LD { R4300_OP_LD, IDEC_RT_BASE_OFFSET } #define LDC1 { R4300_OP_LDC1, IDEC_FT64_BASE_OFFSET } #define LDC2 { R4300_OP_LDC2, IDEC_CPR2_BASE_OFFSET } #define LDL { R4300_OP_LDL, IDEC_RT_BASE_OFFSET } #define LDR { R4300_OP_LDR, IDEC_RT_BASE_OFFSET } #define LH { R4300_OP_LH, IDEC_RT_BASE_OFFSET } #define LHU { R4300_OP_LHU, IDEC_RT_BASE_OFFSET } #define LL { R4300_OP_LL, IDEC_RT_BASE_OFFSET } #define LLD { R4300_OP_LLD, IDEC_RT_BASE_OFFSET } #define LUI { R4300_OP_LUI, IDEC_RT_LUI } #define LW { R4300_OP_LW, IDEC_RT_BASE_OFFSET } #define LWC1 { R4300_OP_LWC1, IDEC_FT32_BASE_OFFSET } #define LWC2 { R4300_OP_LWC2, IDEC_CPR2_BASE_OFFSET } #define LWL { R4300_OP_LWL, IDEC_RT_BASE_OFFSET } #define LWR { R4300_OP_LWR, IDEC_RT_BASE_OFFSET } #define LWU { R4300_OP_LWU, IDEC_RT_BASE_OFFSET } #define MFC0 { R4300_OP_MFC0, IDEC_RT_CPR0 } #define MFC1 { R4300_OP_MFC1, IDEC_RT_FS32 } #define MFC2 { R4300_OP_MFC2, IDEC_RT_CPR2 } #define MFHI { R4300_OP_MFHI, IDEC_RD } #define MFLO { R4300_OP_MFLO, IDEC_RD } #define MTC0 { R4300_OP_MTC0, IDEC_RT_CPR0 } #define MTC1 { R4300_OP_MTC1, IDEC_RT_FS32 } #define MTC2 { R4300_OP_MTC2, IDEC_RT_CPR2 } #define MTHI { R4300_OP_MTHI, IDEC_RS } #define MTLO { R4300_OP_MTLO, IDEC_RS } #define MULT { R4300_OP_MULT, IDEC_RS_RT } #define MULTU { R4300_OP_MULTU, IDEC_RS_RT } #define NOP { R4300_OP_NOP, IDEC_NONE } #define NOR { R4300_OP_NOR, IDEC_RD_RS_RT } #define OR { R4300_OP_OR, IDEC_RD_RS_RT } #define ORI { R4300_OP_ORI, IDEC_RT_RS_ZIMM } #define SB { R4300_OP_SB, IDEC_RT_BASE_OFFSET } #define SC { R4300_OP_SC, IDEC_RT_BASE_OFFSET } #define SCD { R4300_OP_SCD, IDEC_RT_BASE_OFFSET } #define SD { R4300_OP_SD, IDEC_RT_BASE_OFFSET } #define SDC1 { R4300_OP_SDC1, IDEC_FT64_BASE_OFFSET } #define SDC2 { R4300_OP_SDC2, IDEC_CPR2_BASE_OFFSET } #define SDL { R4300_OP_SDL, IDEC_RT_BASE_OFFSET } #define SDR { R4300_OP_SDR, IDEC_RT_BASE_OFFSET } #define SH { R4300_OP_SH, IDEC_RT_BASE_OFFSET } #define SLL { R4300_OP_SLL, IDEC_RD_RT_SA } #define SLLV { R4300_OP_SLLV, IDEC_RD_RT_RS } #define SLT { R4300_OP_SLT, IDEC_RD_RS_RT } #define SLTI { R4300_OP_SLTI, IDEC_RT_RS_SIMM } #define SLTIU { R4300_OP_SLTIU, IDEC_RT_RS_SIMM } #define SLTU { R4300_OP_SLTU, IDEC_RD_RS_RT } #define SRA { R4300_OP_SRA, IDEC_RD_RT_SA } #define SRAV { R4300_OP_SRAV, IDEC_RD_RT_RS } #define SRL { R4300_OP_SRL, IDEC_RD_RT_SA } #define SRLV { R4300_OP_SRLV, IDEC_RD_RT_RS } #define SUB { R4300_OP_SUB, IDEC_RD_RS_RT } #define SUBU { R4300_OP_SUBU, IDEC_RD_RS_RT } #define SW { R4300_OP_SW, IDEC_RT_BASE_OFFSET } #define SWC1 { R4300_OP_SWC1, IDEC_FT32_BASE_OFFSET } #define SWC2 { R4300_OP_SWC2, IDEC_CPR2_BASE_OFFSET } #define SWL { R4300_OP_SWL, IDEC_RT_BASE_OFFSET } #define SWR { R4300_OP_SWR, IDEC_RT_BASE_OFFSET } #define SYNC { R4300_OP_SYNC, IDEC_NONE } #define SYSCALL { R4300_OP_SYSCALL, IDEC_NONE } #define TEQ { R4300_OP_TEQ, IDEC_RS_RT } #define TEQI { R4300_OP_TEQI, IDEC_RS_SIMM } #define TGE { R4300_OP_TGE, IDEC_RS_RT } #define TGEI { R4300_OP_TGEI, IDEC_RS_SIMM } #define TGEIU { R4300_OP_TGEIU, IDEC_RS_SIMM } #define TGEU { R4300_OP_TGEU, IDEC_RS_RT } #define TLBP { R4300_OP_TLBP, IDEC_NONE } #define TLBR { R4300_OP_TLBR, IDEC_NONE } #define TLBWI { R4300_OP_TLBWI, IDEC_NONE } #define TLBWR { R4300_OP_TLBWR, IDEC_NONE } #define TLT { R4300_OP_TLT, IDEC_RS_RT } #define TLTI { R4300_OP_TLTI, IDEC_RS_SIMM } #define TLTIU { R4300_OP_TLTIU, IDEC_RS_SIMM } #define TLTU { R4300_OP_TLTU, IDEC_RS_RT } #define TNE { R4300_OP_TNE, IDEC_RS_RT } #define TNEI { R4300_OP_TNEI, IDEC_RS_SIMM } #define XOR { R4300_OP_XOR, IDEC_RD_RS_RT } #define XORI { R4300_OP_XORI, IDEC_RT_RS_ZIMM } #define SPECIAL RESERVED #define REGIMM RESERVED #define COP0 RESERVED #define COP1 RESERVED #define COP2 RESERVED static const struct r4300_idec r4300_op_table[] = { /* Main opcodes table * 0-63 */ SPECIAL, REGIMM, J, JAL, BEQ, BNE, BLEZ, BGTZ, ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI, COP0, COP1, COP2, RESERVED, BEQL, BNEL, BLEZL, BGTZL, DADDI, DADDIU, LDL, LDR, RESERVED, RESERVED, RESERVED, RESERVED, LB, LH, LWL, LW, LBU, LHU, LWR, LWU, SB, SH, SWL, SW, SDL, SDR, SWR, CACHE, LL, LWC1, LWC2, RESERVED, LLD, LDC1, LDC2, LD, SC, SWC1, SWC2, RESERVED, SCD, SDC1, SDC2, SD, /* SPECIAL opcodes table * 64-127 */ SLL, RESERVED, SRL, SRA, SLLV, RESERVED, SRLV, SRAV, JR, JALR, RESERVED, RESERVED, SYSCALL, BREAK, RESERVED, SYNC, MFHI, MTHI, MFLO, MTLO, DSLLV, RESERVED, DSRLV, DSRAV, MULT, MULTU, DIV, DIVU, DMULT, DMULTU, DDIV, DDIVU, ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR, RESERVED, RESERVED, SLT, SLTU, DADD, DADDU, DSUB, DSUBU, TGE, TGEU, TLT, TLTU, TEQ, RESERVED, TNE, RESERVED, DSLL, RESERVED, DSRL, DSRA, DSLL32, RESERVED, DSRL32, DSRA32, /* REGIMM opcodes table * 128-159 */ BLTZ, BGEZ, BLTZL, BGEZL, RESERVED, RESERVED, RESERVED, RESERVED, TGEI, TGEIU, TLTI, TLTIU, TEQI, RESERVED, TNEI, RESERVED, BLTZAL, BGEZAL, BLTZALL, BGEZALL, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, /* COP0 opcodes table * 160-167 */ MFC0, DMFC0, CFC0, RESERVED, MTC0, DMTC0, CTC0, RESERVED, /* BC0 opcodes table * 168-175 */ BC0F, BC0T, BC0FL, BC0TL, RESERVED, RESERVED, RESERVED, RESERVED, /* TLB opcodes table * 176-239 */ RESERVED, TLBR, TLBWI, RESERVED, RESERVED, RESERVED, TLBWR, RESERVED, TLBP, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, ERET, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, /* COP1 opcodes table * 240-247 */ MFC1, DMFC1, CFC1, DCFC1, MTC1, DMTC1, CTC1, DCTC1, /* BC1 opcodes table * 248-255 */ BC1F, BC1T, BC1FL, BC1TL, RESERVED, RESERVED, RESERVED, RESERVED, /* FPU opcodes table * 256-319 */ CP1_ADD, CP1_SUB, CP1_MUL, CP1_DIV, CP1_SQRT, CP1_ABS, CP1_MOV, CP1_NEG, CP1_ROUND_L, CP1_TRUNC_L, CP1_CEIL_L, CP1_FLOOR_L, CP1_ROUND_W, CP1_TRUNC_W, CP1_CEIL_W, CP1_FLOOR_W, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, CP1_CVT_S, CP1_CVT_D, RESERVED, RESERVED, CP1_CVT_W, CP1_CVT_L, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, CP1_C_F, CP1_C_UN, CP1_C_EQ, CP1_C_UEQ, CP1_C_OLT, CP1_C_ULT, CP1_C_OLE, CP1_C_ULE, CP1_C_SF, CP1_C_NGLE, CP1_C_SEQ, CP1_C_NGL, CP1_C_LT, CP1_C_NGE, CP1_C_LE, CP1_C_NGT, /* COP2 opcodes table * 320-327 */ MFC2, DMFC2, CFC2, DCFC2, MTC2, DMTC2, CTC2, DCTC2, /* BC2 opcodes table * 328-335 */ BC2F, BC2T, BC2FL, BC2TL, RESERVED, RESERVED, RESERVED, RESERVED, /* Pseudo opcodes * 336 */ NOP }; #define E_INV { 0, 0, 0x00 } #define E_MAIN { 0, 26, 0x3f } #define E_SPECIAL { 64, 0, 0x3f } #define E_REGIMM { 128, 16, 0x1f } #define E_COP0 { 160, 21, 0x07 } #define E_BC0 { 168, 16, 0x07 } #define E_TLB { 176, 0, 0x3f } #define E_COP1 { 240, 21, 0x07 } #define E_BC1 { 248, 16, 0x07 } #define E_FPU { 256, 0, 0x3f } #define E_COP2 { 320, 21, 0x07 } #define E_BC2 { 328, 16, 0x07 } struct r4300_op_escape { uint16_t offset; uint8_t shift; uint8_t mask; }; static const struct r4300_op_escape r4300_escapes_table[] = { /* 000000 - special */ E_SPECIAL, E_SPECIAL, E_SPECIAL, E_SPECIAL, /* 000001 - regimm */ E_REGIMM, E_REGIMM, E_REGIMM, E_REGIMM, /* 000010,001111 - main */ E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, /* 010000 - cop0 */ E_COP0, E_BC0, E_TLB, E_TLB, /* 010001 - cop1 */ E_COP1, E_BC1, E_FPU, E_FPU, /* 010010 - cop2 */ E_COP2, E_BC2, E_INV, E_INV, /* 010011,111111 - main */ E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, E_MAIN, }; const struct r4300_idec* r4300_get_idec(uint32_t iw) { const struct r4300_op_escape* escape; /* handle NOP pseudo instruction */ if (iw == 0) { return &r4300_op_table[336]; } escape = &r4300_escapes_table[(iw >> 24)]; return &r4300_op_table[escape->offset + ((iw >> escape->shift) & escape->mask)]; } size_t idec_u53(uint32_t iw, uint8_t u53, uint8_t* u5) { size_t o = 0; uint8_t r = (iw >> U53_SHIFT(u53)) & 0x1f; switch (U53_TYPE(u53)) { case IDEC_REGTYPE_NONE: o = 0; break; case IDEC_REGTYPE_GPR: o = R4300_REGS_OFFSET + r * sizeof(int64_t); break; case IDEC_REGTYPE_CPR0: o = R4300_CP0_REGS_OFFSET + r * sizeof(uint32_t); break; case IDEC_REGTYPE_FPR32: o = R4300_CP1_REGS_S_OFFSET + r * sizeof(float*); break; case IDEC_REGTYPE_FPR64: o = R4300_CP1_REGS_D_OFFSET + r * sizeof(double*); break; case IDEC_REGTYPE_FPR: switch((iw >> U53_SHIFT(U53_FMT) & 0x1f)) { case 16: /* S */ case 20: /* W */ o = R4300_CP1_REGS_S_OFFSET + r * sizeof(float*); break; case 17: /* D */ case 21: /* L */ o = R4300_CP1_REGS_D_OFFSET + r * sizeof(double*); break; default: /* reserved instruction - (ex: LEGO)*/ break; } break; case IDEC_REGTYPE_FCR: o = (r == 0) ? R4300_CP1_FCR0_OFFSET : R4300_CP1_FCR31_OFFSET; break; default: assert(0); } *u5 = r; return o; } #define X(op) #op const char* g_r4300_opcodes[R4300_OPCODES_COUNT] = { #include "opcodes.md" }; #undef X mupen64plus-core-src-2.6.0/src/device/r4300/idec.h000066400000000000000000000063031464506436200213230ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - idec.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2018 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_IDEC_H #define M64P_DEVICE_R4300_IDEC_H #include "osal/preproc.h" #include #include #define X(op) R4300_OP_##op enum r4300_opcode { #include "opcodes.md" , R4300_OPCODES_COUNT }; #undef X enum r4300_register_type { IDEC_REGTYPE_NONE, IDEC_REGTYPE_GPR, IDEC_REGTYPE_CPR0, // cp0 regs IDEC_REGTYPE_FPR, // cp1: depends on format field IDEC_REGTYPE_FPR32, // cp1: simple, word IDEC_REGTYPE_FPR64, // cp1: double, long IDEC_REGTYPE_FCR // cp1: control reg /* carefull: needs to fit within 3bits in u53 */ }; #define U53(t,s) (((s) << 3)|((t) & 0x7)) #define U53_SHIFT(u) (((u) >> 3) & 0x1f) #define U53_TYPE(u) ((enum r4300_register_type)((u) & 0x7)) /* instruction decode parameters */ struct r4300_idec { enum r4300_opcode opcode; uint32_t i_mask; uint16_t i_smask; uint8_t i_lshift; /* d, t, s, non-reg (5 highest bit encode right shift, 3 lowest bits encode reg type) */ uint8_t u53[4]; /* FIXME?: pad up to 16-bytes for better perf */ }; static osal_inline int64_t sign_extend(uint32_t x, uint16_t m) { /* assume that bits of x above the m are already zeros */ return (int64_t)(x ^ m) - (int64_t)m; } static osal_inline int64_t idec_imm(uint32_t iw, const struct r4300_idec* idec) { return sign_extend((iw & idec->i_mask), idec->i_smask) << idec->i_lshift; } /* Get instruction decoder */ const struct r4300_idec* r4300_get_idec(uint32_t iw); /* decode register */ size_t idec_u53(uint32_t iw, uint8_t u53, uint8_t* u5); #define IDEC_U53(r4300, iw, u53, u5) (void*)(((char*)(r4300)) + idec_u53((iw), (u53), (u5))) extern const char* g_r4300_opcodes[R4300_OPCODES_COUNT]; #endif mupen64plus-core-src-2.6.0/src/device/r4300/instr_counters.c000066400000000000000000000114051464506436200234720ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - instr_counters.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "instr_counters.h" #include #include #include "api/callbacks.h" #include "api/m64p_types.h" /* various constants */ static char instr_name[][10] = { "reserved", "NI", "J", "JAL", "BEQ", "BNE", "BLEZ", "BGTZ", "ADDI", "ADDIU", "SLTI", "SLTIU", "ANDI", "ORI", "XORI", "LUI", "BEQL", "BNEL", "BLEZL", "BGTZL", "DADDI", "DADDIU", "LDL", "LDR", "LB", "LH", "LW", "LWL", "LBU", "LHU", "LWU", "LWR", "SB", "SH", "SW", "SWL", "SWR", "SDL", "SDR", "LWC1", "LDC1", "LD", "LL", "SWC1", "SDC1", "SD", "SC", "BLTZ", "BGEZ", "BLTZL", "BGEZL", "BLTZAL", "BGEZAL", "BLTZALL", "BGEZALL", "SLL", "SRL", "SRA", "SLLV", "SRLV", "SRAV", "JR", "JALR", "SYSCALL", "MFHI", "MTHI", "MFLO", "MTLO", "DSLLV", "DSRLV", "DSRAV", "MULT", "MULTU", "DIV", "DIVU", "DMULT", "DMULTU", "DDIV", "DDIVU", "ADD", "ADDU", "SUB", "SUBU", "AND", "OR", "XOR", "NOR", "SLT", "SLTU", "DADD", "DADDU", "DSUB", "DSUBU", "DSLL", "DSRL", "DSRA", "TEQ", "DSLL32", "DSRL32", "DSRA32", "BC1F", "BC1T", "BC1FL", "BC1TL", "TLBWI", "TLBP", "TLBR", "TLBWR", "ERET", "MFC0", "MTC0", "MFC1", "DMFC1", "CFC1", "MTC1", "DMTC1", "CTC1", "f.CVT", "f.CMP", "f.ADD", "f.SUB", "f.MUL", "f.DIV", "f.SQRT", "f.ABS", "f.MOV", "f.NEG", "f.ROUND", "f.TRUNC", "f.CEIL", "f.FLOOR" }; static unsigned int instr_type[131] = { 9, 10, 6, 6, 7, 7, 7, 7, 3, 3, 4, 4, 3, 4, 4, 0, 7, 7, 7, 7, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 6, 6, 10, 2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 7, 7, 7, 7, 10, 10, 10, 10, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5 }; static char instr_typename[][20] = { "Load", "Store", "Data move/convert", "32-bit math", "64-bit math", "Float Math", "Jump", "Branch", "Exceptions", "Reserved", "Other" }; /* global variable */ unsigned int instr_count[132]; /* global function */ void instr_counters_print(void) { size_t i; unsigned int iTypeCount[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned int iTotal = 0; char line[128], param[24]; DebugMessage(M64MSG_INFO, "Instruction counters:"); line[0] = 0; for (i = 0; i < 131; i++) { sprintf(param, "%8s: %08i ", instr_name[i], instr_count[i]); strcat(line, param); if (i % 5 == 4) { DebugMessage(M64MSG_INFO, "%s", line); line[0] = 0; } iTypeCount[instr_type[i]] += instr_count[i]; iTotal += instr_count[i]; } DebugMessage(M64MSG_INFO, "Instruction type summary (total instructions = %i)", iTotal); for (i = 0; i < 11; i++) { DebugMessage(M64MSG_INFO, "%20s: %04.1f%% (%i)", instr_typename[i], (float) iTypeCount[i] * 100.0 / iTotal, iTypeCount[i]); } } mupen64plus-core-src-2.6.0/src/device/r4300/instr_counters.h000066400000000000000000000033261464506436200235020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - instr_counters.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_INSTR_COUNTERS_H #define M64P_DEVICE_R4300_INSTR_COUNTERS_H extern unsigned int instr_count[132]; void instr_counters_print(void); #endif /* M64P_DEVICE_R4300_INSTR_COUNTERS_H */ mupen64plus-core-src-2.6.0/src/device/r4300/interrupt.c000066400000000000000000000470341464506436200224540ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - interrupt.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define M64P_CORE_PROTOTYPES 1 #include "interrupt.h" #ifdef __MINGW32__ #define _CRT_RAND_S #endif #include #include #include #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/pif/bootrom_hle.h" #include "device/r4300/cached_interp.h" #include "device/r4300/cp0.h" #include "device/r4300/new_dynarec/new_dynarec.h" #include "device/r4300/r4300_core.h" #include "device/r4300/recomp.h" #include "device/rcp/ai/ai_controller.h" #include "device/rcp/vi/vi_controller.h" #include "main/main.h" #include "main/savestates.h" /*************************************************************************** * Pool of Single Linked List Nodes **************************************************************************/ static struct node* alloc_node(struct pool* p); static void free_node(struct pool* p, struct node* node); static void clear_pool(struct pool* p); /* node allocation/deallocation on a given pool */ static struct node* alloc_node(struct pool* p) { /* return NULL if pool is too small */ if (p->index >= INTERRUPT_NODES_POOL_CAPACITY) { return NULL; } return p->stack[p->index++]; } static void free_node(struct pool* p, struct node* node) { if (p->index == 0 || node == NULL) { return; } p->stack[--p->index] = node; } /* release all nodes */ static void clear_pool(struct pool* p) { size_t i; for (i = 0; i < INTERRUPT_NODES_POOL_CAPACITY; ++i) { p->stack[i] = &p->nodes[i]; } p->index = 0; } /*************************************************************************** * Interrupt Queue **************************************************************************/ static void clear_queue(struct interrupt_queue* q) { q->first = NULL; clear_pool(&q->pool); } static int before_event(const struct cp0* cp0, unsigned int evt1, unsigned int evt2, int type2) { const uint32_t* cp0_regs = r4300_cp0_regs((struct cp0*)cp0); /* OK to cast away const qualifier */ uint32_t count = cp0_regs[CP0_COUNT_REG]; int* cp0_cycle_count = r4300_cp0_cycle_count((struct cp0*)cp0); /* At least one other interrupt is pending */ if (*cp0_cycle_count > 0) count -= *cp0_cycle_count; if ((evt1 - count) < (evt2 - count)) return 1; else return 0; } unsigned int add_random_interrupt_time(struct r4300_core* r4300) { if (r4300->randomize_interrupt) { unsigned int value; #ifdef __MINGW32__ rand_s(&value); #else value = rand(); #endif return value % 0x40; } else return 0; } void add_interrupt_event(struct cp0* cp0, int type, unsigned int delay) { const uint32_t* cp0_regs = r4300_cp0_regs(cp0); add_interrupt_event_count(cp0, type, cp0_regs[CP0_COUNT_REG] + delay); } void add_interrupt_event_count(struct cp0* cp0, int type, unsigned int count) { struct node* event; struct node* e; const uint32_t* cp0_regs = r4300_cp0_regs(cp0); unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(cp0); if (get_event(&cp0->q, type)) { DebugMessage(M64MSG_WARNING, "two events of type 0x%x in interrupt queue", type); } event = alloc_node(&cp0->q.pool); if (event == NULL) { DebugMessage(M64MSG_ERROR, "Failed to allocate node for new interrupt event"); return; } event->data.count = count; event->data.type = type; if (cp0->q.first == NULL) { cp0->q.first = event; event->next = NULL; } else if (before_event(cp0, count, cp0->q.first->data.count, cp0->q.first->data.type)) { event->next = cp0->q.first; cp0->q.first = event; } else { for (e = cp0->q.first; e->next != NULL && (!before_event(cp0, count, e->next->data.count, e->next->data.type)); e = e->next); if (e->next == NULL) { e->next = event; event->next = NULL; } else { for(; e->next != NULL && e->next->data.count == count; e = e->next); event->next = e->next; e->next = event; } } *cp0_next_interrupt = cp0->q.first->data.count; *cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - cp0->q.first->data.count; } void remove_interrupt_event(struct cp0* cp0) { struct node* e; const uint32_t* cp0_regs = r4300_cp0_regs(cp0); unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(cp0); e = cp0->q.first; cp0->q.first = e->next; free_node(&cp0->q.pool, e); *cp0_next_interrupt = (cp0->q.first != NULL) ? cp0->q.first->data.count : 0; *cp0_cycle_count = (cp0->q.first != NULL) ? (cp0_regs[CP0_COUNT_REG] - cp0->q.first->data.count) : 0; } unsigned int* get_event(const struct interrupt_queue* q, int type) { struct node* e = q->first; if (e == NULL) { return NULL; } if (e->data.type == type) { return &e->data.count; } for (; e->next != NULL && e->next->data.type != type; e = e->next); return (e->next != NULL) ? &e->next->data.count : NULL; } int get_next_event_type(const struct interrupt_queue* q) { return (q->first == NULL) ? 0 : q->first->data.type; } void remove_event(struct interrupt_queue* q, int type) { struct node* to_del; struct node* e = q->first; if (e == NULL) { return; } if (e->data.type == type) { q->first = e->next; free_node(&q->pool, e); } else { for (; e->next != NULL && e->next->data.type != type; e = e->next); if (e->next != NULL) { to_del = e->next; e->next = to_del->next; free_node(&q->pool, to_del); } } } void translate_event_queue(struct cp0* cp0, unsigned int base) { struct node* e; uint32_t* cp0_regs = r4300_cp0_regs(cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(cp0); remove_event(&cp0->q, COMPARE_INT); remove_event(&cp0->q, SPECIAL_INT); for (e = cp0->q.first; e != NULL; e = e->next) { e->data.count = (e->data.count - cp0_regs[CP0_COUNT_REG]) + base; } cp0_regs[CP0_COUNT_REG] = base; add_interrupt_event_count(cp0, SPECIAL_INT, ((cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000))); /* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */ cp0_regs[CP0_COUNT_REG] += cp0->count_per_op; *cp0_cycle_count += cp0->count_per_op; add_interrupt_event_count(cp0, COMPARE_INT, cp0_regs[CP0_COMPARE_REG]); cp0_regs[CP0_COUNT_REG] -= cp0->count_per_op; /* Update next interrupt in case first event is COMPARE_INT */ *cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - cp0->q.first->data.count; } int save_eventqueue_infos(const struct cp0* cp0, char *buf) { int len; struct node* e; len = 0; for (e = cp0->q.first; e != NULL; e = e->next) { memcpy(buf + len , &e->data.type , 4); memcpy(buf + len + 4, &e->data.count, 4); len += 8; } *((unsigned int*)&buf[len]) = 0xFFFFFFFF; return len+4; } void load_eventqueue_infos(struct cp0* cp0, const char *buf) { int len = 0; uint32_t* cp0_regs = r4300_cp0_regs(cp0); clear_queue(&cp0->q); while (*((const unsigned int*)&buf[len]) != 0xFFFFFFFF) { int type = *((const unsigned int*)&buf[len]); unsigned int count = *((const unsigned int*)&buf[len+4]); add_interrupt_event_count(cp0, type, count); len += 8; } remove_event(&cp0->q, SPECIAL_INT); add_interrupt_event_count(cp0, SPECIAL_INT, ((cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000))); } void init_interrupt(struct cp0* cp0) { clear_queue(&cp0->q); add_interrupt_event_count(cp0, SPECIAL_INT, 0x80000000); add_interrupt_event_count(cp0, COMPARE_INT, 0); } void r4300_check_interrupt(struct r4300_core* r4300, uint32_t cause_ip, int set_cause) { struct node* event; uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(&r4300->cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); if (set_cause) { cp0_regs[CP0_CAUSE_REG] = (cp0_regs[CP0_CAUSE_REG] | cause_ip) & ~CP0_CAUSE_EXCCODE_MASK; } else { cp0_regs[CP0_CAUSE_REG] &= ~cause_ip; } if ((cp0_regs[CP0_STATUS_REG] & (CP0_STATUS_IE | CP0_STATUS_EXL | CP0_STATUS_ERL)) != CP0_STATUS_IE) { return; } if (cp0_regs[CP0_STATUS_REG] & cp0_regs[CP0_CAUSE_REG] & UINT32_C(0xFF00)) { event = alloc_node(&r4300->cp0.q.pool); if (event == NULL) { DebugMessage(M64MSG_ERROR, "Failed to allocate node for new interrupt event"); return; } event->data.count = *cp0_next_interrupt = cp0_regs[CP0_COUNT_REG]; event->data.type = CHECK_INT; *cp0_cycle_count = 0; if (r4300->cp0.q.first == NULL) { r4300->cp0.q.first = event; event->next = NULL; } else { event->next = r4300->cp0.q.first; r4300->cp0.q.first = event; } } } void raise_maskable_interrupt(struct r4300_core* r4300, uint32_t cause_ip) { uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); cp0_regs[CP0_CAUSE_REG] = (cp0_regs[CP0_CAUSE_REG] | cause_ip) & ~CP0_CAUSE_EXCCODE_MASK; if (!(cp0_regs[CP0_STATUS_REG] & cp0_regs[CP0_CAUSE_REG] & UINT32_C(0xff00))) { return; } if ((cp0_regs[CP0_STATUS_REG] & (CP0_STATUS_IE | CP0_STATUS_EXL | CP0_STATUS_ERL)) != CP0_STATUS_IE) { return; } exception_general(r4300); } void compare_int_handler(void* opaque) { struct r4300_core* r4300 = (struct r4300_core*)opaque; uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); /* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */ cp0_regs[CP0_COUNT_REG] += r4300->cp0.count_per_op; *cp0_cycle_count += r4300->cp0.count_per_op; add_interrupt_event_count(&r4300->cp0, COMPARE_INT, cp0_regs[CP0_COMPARE_REG]); cp0_regs[CP0_COUNT_REG] -= r4300->cp0.count_per_op; /* Update next interrupt in case first event is COMPARE_INT */ *cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - r4300->cp0.q.first->data.count; raise_maskable_interrupt(r4300, CP0_CAUSE_IP7); } void check_int_handler(void* opaque) { exception_general((struct r4300_core*)opaque); } /* Special interrupt is a fake interrupt which porpose is to ensure the number of cycles between current cycle and next interrupt will never exceed 2^31 */ void special_int_handler(void* opaque) { struct cp0* cp0 = (struct cp0*)opaque; const uint32_t* cp0_regs = r4300_cp0_regs(cp0); remove_interrupt_event(cp0); add_interrupt_event_count(cp0, SPECIAL_INT, ((cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000))); } /* XXX: this should only require r4300 struct not device ? */ /* XXX: This is completly WTF ! */ void nmi_int_handler(void* opaque) { struct device* dev = (struct device*)opaque; struct r4300_core* r4300 = &dev->r4300; uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); reset_pif(&dev->pif, 1); // setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR cp0_regs[CP0_STATUS_REG] = (cp0_regs[CP0_STATUS_REG] & ~(CP0_STATUS_SR | CP0_STATUS_TS | UINT32_C(0x00080000))) | (CP0_STATUS_ERL | CP0_STATUS_BEV | CP0_STATUS_SR); cp0_regs[CP0_CAUSE_REG] = 0x00000000; // simulate the soft reset code which would run from the PIF ROM pif_bootrom_hle_execute(r4300); // clear all interrupts, reset interrupt counters back to 0 cp0_regs[CP0_COUNT_REG] = 0; g_gs_vi_counter = 0; init_interrupt(&r4300->cp0); add_interrupt_event(&r4300->cp0, VI_INT, dev->vi.delay); // clear the audio status register so that subsequent write_ai() calls will work properly dev->ai.regs[AI_STATUS_REG] = 0; // set ErrorEPC with the last instruction address cp0_regs[CP0_ERROREPC_REG] = *r4300_pc(r4300); // reset the r4300 internal state invalidate_r4300_cached_code(r4300, 0, 0); // adjust ErrorEPC if we were in a delay slot, and clear the r4300->delay_slot and r4300->recomp.dyna_interp flags if(r4300->delay_slot==1 || r4300->delay_slot==3) { cp0_regs[CP0_ERROREPC_REG]-=4; } r4300->delay_slot = 0; #ifndef NEW_DYNAREC r4300->recomp.dyna_interp = 0; #endif // set next instruction address to reset vector r4300->cp0.last_addr = r4300->start_address; generic_jump_to(r4300, r4300->start_address); } /* XXX: needs to be properly reworked */ void reset_hard_handler(void* opaque) { struct device* dev = (struct device*)opaque; struct r4300_core* r4300 = &dev->r4300; #ifndef NEW_DYNAREC #if defined(__x86_64__) long long save_rsp = r4300->recomp.save_rsp; long long save_rip = r4300->recomp.save_rip; #else long save_ebp = r4300->recomp.save_ebp; long save_ebx = r4300->recomp.save_ebx; long save_esi = r4300->recomp.save_esi; long save_edi = r4300->recomp.save_edi; long save_esp = r4300->recomp.save_esp; long save_eip = r4300->recomp.save_eip; #endif #endif poweron_device(dev); pif_bootrom_hle_execute(r4300); r4300->cp0.last_addr = r4300->start_address; *r4300_cp0_next_interrupt(&r4300->cp0) = 624999; *r4300_cp0_cycle_count(&r4300->cp0) = 0; init_interrupt(&r4300->cp0); invalidate_r4300_cached_code(r4300, 0, 0); *r4300_pc_struct(r4300) = &r4300->interp_PC; if (r4300->emumode >= 2) { #ifdef NEW_DYNAREC new_dynarec_cleanup(); new_dynarec_init(); #else #if defined(__x86_64__) r4300->recomp.save_rsp = save_rsp; r4300->recomp.save_rip = save_rip; #else r4300->recomp.save_ebp = save_ebp; r4300->recomp.save_ebx = save_ebx; r4300->recomp.save_esi = save_esi; r4300->recomp.save_edi = save_edi; r4300->recomp.save_esp = save_esp; r4300->recomp.save_eip = save_eip; #endif #endif } generic_jump_to(r4300, r4300->cp0.last_addr); } static void call_interrupt_handler(const struct cp0* cp0, size_t index) { assert(index < CP0_INTERRUPT_HANDLERS_COUNT); const struct interrupt_handler* handler = &cp0->interrupt_handlers[index]; handler->callback(handler->opaque); } void gen_interrupt(struct r4300_core* r4300) { uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); unsigned int* cp0_next_interrupt = r4300_cp0_next_interrupt(&r4300->cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); if (*r4300_stop(r4300) == 1) { g_gs_vi_counter = 0; // debug #ifndef NO_ASM #ifndef NEW_DYNAREC dyna_stop(r4300); #endif #endif } if (!r4300->cp0.interrupt_unsafe_state) { if (savestates_get_job() == savestates_job_load) { savestates_load(); return; } if (r4300->reset_hard_job) { call_interrupt_handler(&r4300->cp0, 11); return; } } if (r4300->skip_jump) { uint32_t dest = r4300->skip_jump; r4300->skip_jump = 0; *cp0_next_interrupt = (r4300->cp0.q.first != NULL) ? r4300->cp0.q.first->data.count : 0; *cp0_cycle_count = (r4300->cp0.q.first != NULL) ? (cp0_regs[CP0_COUNT_REG] - r4300->cp0.q.first->data.count) : 0; r4300->cp0.last_addr = dest; generic_jump_to(r4300, dest); return; } switch (r4300->cp0.q.first->data.type) { case VI_INT: call_interrupt_handler(&r4300->cp0, 0); break; case COMPARE_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 1); break; case CHECK_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 2); break; case SI_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 3); break; case PI_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 4); break; case SPECIAL_INT: call_interrupt_handler(&r4300->cp0, 5); break; case AI_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 6); break; case SP_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 7); break; case DP_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 8); break; case HW2_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 9); break; case NMI_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 10); break; case RSP_DMA_EVT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 12); break; case DD_MC_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 13); break; case DD_BM_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 14); break; case DD_DV_INT: remove_interrupt_event(&r4300->cp0); call_interrupt_handler(&r4300->cp0, 15); break; default: DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", r4300->cp0.q.first->data.type); remove_interrupt_event(&r4300->cp0); exception_general(r4300); break; } if (!r4300->cp0.interrupt_unsafe_state) { if (savestates_get_job() == savestates_job_save) { savestates_save(); return; } } } mupen64plus-core-src-2.6.0/src/device/r4300/interrupt.h000066400000000000000000000062331464506436200224550ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - interrupt.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_INTERRUPT_H #define M64P_DEVICE_R4300_INTERRUPT_H #include struct r4300_core; struct cp0; struct interrupt_queue; void init_interrupt(struct cp0* cp0); void raise_maskable_interrupt(struct r4300_core* r4300, uint32_t cause_ip); void gen_interrupt(struct r4300_core* r4300); void r4300_check_interrupt(struct r4300_core* r4300, uint32_t cause_ip, int set_cause); void translate_event_queue(struct cp0* cp0, unsigned int base); void remove_event(struct interrupt_queue* q, int type); void add_interrupt_event_count(struct cp0* cp0, int type, unsigned int count); void add_interrupt_event(struct cp0* cp0, int type, unsigned int delay); unsigned int* get_event(const struct interrupt_queue* q, int type); int get_next_event_type(const struct interrupt_queue* q); unsigned int add_random_interrupt_time(struct r4300_core* r4300); void remove_interrupt_event(struct cp0* cp0); int save_eventqueue_infos(const struct cp0* cp0, char *buf); void load_eventqueue_infos(struct cp0* cp0, const char *buf); void reset_hard_handler(void* opaque); void compare_int_handler(void* opaque); void check_int_handler(void* opaque); void special_int_handler(void* opaque); void nmi_int_handler(void* opaque); #define VI_INT 0x0001 #define COMPARE_INT 0x0002 #define CHECK_INT 0x0004 #define SI_INT 0x0008 #define PI_INT 0x0010 #define SPECIAL_INT 0x0020 #define AI_INT 0x0040 #define SP_INT 0x0080 #define DP_INT 0x0100 #define HW2_INT 0x0200 #define NMI_INT 0x0400 #define RSP_DMA_EVT 0x0800 #define DD_MC_INT 0x1000 #define DD_BM_INT 0x2000 #define DD_DV_INT 0x4000 #endif /* M64P_DEVICE_R4300_INTERRUPT_H */ mupen64plus-core-src-2.6.0/src/device/r4300/mips_instructions.def000066400000000000000000001727551464506436200245410ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - mips_instructions.def * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Before #including this file the following macros must be defined: * * instruction operands accessor macros: * rrt, rrd, rfs, rrs, rsa, * rrt32, rrd32, rrs32, irs32, irt32, * irt, irs, ibase, ioffset, iimmediate, * jinst_index, * lfbase, lfft, lfoffset, * cfft, cffs, cffd * * DECLARE_R4300: An optionnal way of declaring teh r4300 pointer used * in instructions definitions * PCADDR: Program counter (memory address of the current instruction). * * ADD_TO_PC(x): Increment the program counter in 'x' instructions. * This is only used for small changes to PC, so the new program counter * is guaranteed to fall in the current cached interpreter or dynarec block. * * DECLARE_INSTRUCTION(name) * Declares an instruction function which is not a jump. * Followed by a block of code. * * DECLARE_JUMP(name, destination, condition, link, likely, cop1) * name is the name of the jump or branch instruction. * destination is the destination memory address of the jump. * If condition is nonzero, the jump is taken. * link is a pointer to a variable where (PC+8) is written unconditionally. * To avoid linking, pass ®[0] * If likely is nonzero, the delay slot is only executed if the jump is taken. * If cop1 is nonzero, a COP1 unusable check will be done. */ #include "fpu.h" #include "r4300_core.h" #include "device/memory/memory.h" #include "device/rcp/mi/mi_controller.h" #include "device/rdram/rdram.h" #include "osal/preproc.h" #define XXH_INLINE_ALL #include #include #include /* Assists unaligned memory accessors with making masks to preserve or apply * bits in registers and memory. * * BITS_BELOW_MASK32 and BITS_BELOW_MASK64 make masks where bits 0 to (x - 1) * are set. * * BITS_ABOVE_MASK32 makes masks where bits x to 31 are set. * BITS_ABOVE_MASK64 makes masks where bits x to 63 are set. * * e.g. x = 8 * 0000 0000 0000 0000 0000 0000 1111 1111 <- BITS_BELOW_MASK32(8) * 1111 1111 1111 1111 1111 1111 0000 0000 <- BITS_ABOVE_MASK32(8) * * Giving a negative value or one that is >= the bit count of the mask results * in undefined behavior. */ #define BITS_BELOW_MASK32(x) ((UINT32_C(1) << (x)) - 1) #define BITS_ABOVE_MASK32(x) (~(BITS_BELOW_MASK32((x)))) #define BITS_BELOW_MASK64(x) ((UINT64_C(1) << (x)) - 1) #define BITS_ABOVE_MASK64(x) (~(BITS_BELOW_MASK64((x)))) static unsigned int bshift(uint32_t address) { return ((address & 3) ^ 3) << 3; } static unsigned int hshift(uint32_t address) { return ((address & 2) ^ 2) << 3; } /* M64P Pseudo instructions */ DECLARE_INSTRUCTION(NI) { DECLARE_R4300 DebugMessage(M64MSG_ERROR, "NI() @ 0x%" PRIX32, PCADDR); DebugMessage(M64MSG_ERROR, "opcode not implemented: %" PRIX32 ":%" PRIX32, PCADDR, *fast_mem_access(r4300, PCADDR)); *r4300_stop(r4300) = 1; } /* Reserved */ DECLARE_INSTRUCTION(RESERVED) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); DebugMessage(M64MSG_ERROR, "reserved opcode: %" PRIX32 ":%" PRIX32, PCADDR, *fast_mem_access(r4300, PCADDR)); cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_RI; exception_general(r4300); } DECLARE_INSTRUCTION(RESERVED_COP2) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); if (check_cop2_unusable(r4300)) { return; } cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_RI | CP0_CAUSE_CE2; exception_general(r4300); } /* BREAK */ DECLARE_INSTRUCTION(BREAK) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_BP; exception_general(r4300); } /* Load instructions */ DECLARE_INSTRUCTION(LB) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); uint32_t value; unsigned int shift = bshift(lsaddr); if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = SE8((value >> shift) & 0xff); } } DECLARE_INSTRUCTION(LBU) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); uint32_t value; unsigned int shift = bshift(lsaddr); if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = (value >> shift) & 0xff; } } DECLARE_INSTRUCTION(LH) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); uint32_t value; unsigned int shift = hshift(lsaddr); if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = SE16((value >> shift) & 0xffff); } } DECLARE_INSTRUCTION(LHU) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); uint32_t value; unsigned int shift = hshift(lsaddr); if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = (value >> shift) & 0xffff; } } DECLARE_INSTRUCTION(LL) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); uint32_t value; if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = SE32(value); r4300->llbit = 1; } } DECLARE_INSTRUCTION(LW) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); uint32_t value; if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = SE32(value); } } DECLARE_INSTRUCTION(LWU) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); uint32_t value; if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = value; } } DECLARE_INSTRUCTION(LWL) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 3); unsigned int shift = 8 * n; uint32_t mask = BITS_BELOW_MASK32(8 * n); uint32_t value; if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = SE32(((uint32_t)*lsrtp & mask) | ((uint32_t)value << shift)); } } DECLARE_INSTRUCTION(LWR) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 3); unsigned int shift = 8 * (3 - n); uint32_t mask = (n == 3) ? UINT32_C(0) : BITS_ABOVE_MASK32(8 * (n + 1)); uint32_t value; if (r4300_read_aligned_word(r4300, lsaddr, &value)) { *lsrtp = SE32(((uint32_t)*lsrtp & mask) | ((uint32_t)value >> shift)); } } DECLARE_INSTRUCTION(LD) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); r4300_read_aligned_dword(r4300, lsaddr, (uint64_t*)lsrtp); } DECLARE_INSTRUCTION(LDL) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 7); unsigned int shift = 8 * n; uint64_t mask = BITS_BELOW_MASK64(8 * n); uint64_t value; if (r4300_read_aligned_dword(r4300, lsaddr & ~UINT32_C(7), &value)) { *lsrtp = ((uint64_t)*lsrtp & mask) | (value << shift); } } DECLARE_INSTRUCTION(LDR) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 7); unsigned int shift = 8 * (7 - n); uint64_t mask = (n == 7) ? UINT64_C(0) : BITS_ABOVE_MASK64(8 * (n + 1)); uint64_t value; if (r4300_read_aligned_dword(r4300, lsaddr & ~UINT32_C(7), &value)) { *lsrtp = ((uint64_t)*lsrtp & mask) | (value >> shift); } } /* Store instructions */ DECLARE_INSTRUCTION(SB) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int shift = bshift(lsaddr); r4300_write_aligned_word(r4300, lsaddr, (uint32_t)*lsrtp << shift, UINT32_C(0xff) << shift); } DECLARE_INSTRUCTION(SH) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int shift = hshift(lsaddr); r4300_write_aligned_word(r4300, lsaddr, (uint32_t)*lsrtp << shift, UINT32_C(0xffff) << shift); } DECLARE_INSTRUCTION(SC) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); if (r4300->llbit) { if (r4300_write_aligned_word(r4300, lsaddr, (uint32_t)*lsrtp, ~UINT32_C(0))) { r4300->llbit = 0; *lsrtp = 1; } } else { *lsrtp = 0; } } DECLARE_INSTRUCTION(SW) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); r4300_write_aligned_word(r4300, lsaddr, (uint32_t)*lsrtp, ~UINT32_C(0)); } DECLARE_INSTRUCTION(SWL) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 3); unsigned int shift = 8 * n; uint32_t mask = (n == 0) ? ~UINT32_C(0) : BITS_BELOW_MASK32(8 * (4 - n)); uint32_t value = (uint32_t)*lsrtp; r4300_write_aligned_word(r4300, lsaddr & ~UINT32_C(0x3), value >> shift, mask); } DECLARE_INSTRUCTION(SWR) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 3); unsigned int shift = 8 * (3 - n); uint32_t mask = BITS_ABOVE_MASK32(8 * (3 - n)); uint32_t value = (uint32_t)*lsrtp; r4300_write_aligned_word(r4300, lsaddr & ~UINT32_C(0x3), value << shift, mask); } DECLARE_INSTRUCTION(SD) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); r4300_write_aligned_dword(r4300, lsaddr, (uint64_t)*lsrtp, ~UINT64_C(0)); } DECLARE_INSTRUCTION(SDL) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 7); unsigned int shift = 8 * n; uint64_t mask = (n == 0) ? ~UINT64_C(0) : BITS_BELOW_MASK64(8 * (8 - n)); uint64_t value = (uint64_t)*lsrtp; r4300_write_aligned_dword(r4300, lsaddr & ~UINT32_C(0x7), value >> shift, mask); } DECLARE_INSTRUCTION(SDR) { DECLARE_R4300 const uint32_t lsaddr = (uint32_t) irs32 + (uint32_t) iimmediate; int64_t *lsrtp = &irt; ADD_TO_PC(1); unsigned int n = (lsaddr & 7); unsigned int shift = 8 * (7 - n); uint64_t mask = BITS_ABOVE_MASK64(8 * (7 - n)); uint64_t value = (uint64_t)*lsrtp; r4300_write_aligned_dword(r4300, lsaddr & ~UINT32_C(0x7), value << shift, mask); } /* Computational instructions */ DECLARE_INSTRUCTION(ADD) { DECLARE_R4300 rrd = SE32((uint32_t) rrs32 + (uint32_t) rrt32); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADDU) { DECLARE_R4300 rrd = SE32((uint32_t) rrs32 + (uint32_t) rrt32); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADDI) { DECLARE_R4300 irt = SE32((uint32_t) irs32 + (uint32_t) iimmediate); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADDIU) { DECLARE_R4300 irt = SE32((uint32_t) irs32 + (uint32_t) iimmediate); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DADD) { DECLARE_R4300 rrd = (uint64_t) rrs + (uint64_t) rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DADDU) { DECLARE_R4300 rrd = (uint64_t) rrs + (uint64_t) rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DADDI) { DECLARE_R4300 irt = (uint64_t) irs + (uint64_t) iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DADDIU) { DECLARE_R4300 irt = (uint64_t) irs + (uint64_t) iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(SUB) { DECLARE_R4300 rrd = SE32((uint32_t) rrs32 - (uint32_t) rrt32); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SUBU) { DECLARE_R4300 rrd = SE32((uint32_t) rrs32 - (uint32_t) rrt32); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSUB) { DECLARE_R4300 rrd = (uint64_t) rrs - (uint64_t) rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSUBU) { DECLARE_R4300 rrd = (uint64_t) rrs - (uint64_t) rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLT) { DECLARE_R4300 if (rrs < rrt) { rrd = 1; } else { rrd = 0; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLTU) { DECLARE_R4300 if ((uint64_t) rrs < (uint64_t) rrt) { rrd = 1; } else { rrd = 0; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLTI) { DECLARE_R4300 if (irs < iimmediate) { irt = 1; } else { irt = 0; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLTIU) { DECLARE_R4300 if ((uint64_t) irs < (uint64_t) ((int64_t) iimmediate)) { irt = 1; } else { irt = 0; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(AND) { DECLARE_R4300 rrd = rrs & rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(ANDI) { DECLARE_R4300 irt = irs & (uint16_t) iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(OR) { DECLARE_R4300 rrd = rrs | rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(ORI) { DECLARE_R4300 irt = irs | (uint16_t) iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(XOR) { DECLARE_R4300 rrd = rrs ^ rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(XORI) { DECLARE_R4300 irt = irs ^ (uint16_t) iimmediate; ADD_TO_PC(1); } DECLARE_INSTRUCTION(NOR) { DECLARE_R4300 rrd = ~(rrs | rrt); ADD_TO_PC(1); } DECLARE_INSTRUCTION(LUI) { DECLARE_R4300 irt = SE32((uint32_t) iimmediate << 16); ADD_TO_PC(1); } /* Shift instructions */ DECLARE_INSTRUCTION(NOP) { DECLARE_R4300 ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLL) { DECLARE_R4300 rrd = SE32((uint32_t) rrt32 << rsa); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SLLV) { DECLARE_R4300 rrd = SE32((uint32_t) rrt32 << (rrs32 & 0x1F)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSLL) { DECLARE_R4300 rrd = (uint64_t) rrt << rsa; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSLLV) { DECLARE_R4300 rrd = (uint64_t) rrt << (rrs32 & 0x3F); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSLL32) { DECLARE_R4300 rrd = (uint64_t) rrt << (32 + rsa); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRL) { DECLARE_R4300 rrd = SE32((uint32_t) rrt32 >> rsa); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRLV) { DECLARE_R4300 rrd = SE32((uint32_t) rrt32 >> (rrs32 & 0x1F)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRL) { DECLARE_R4300 rrd = (uint64_t) rrt >> rsa; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRLV) { DECLARE_R4300 rrd = (uint64_t) rrt >> (rrs32 & 0x3F); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRL32) { DECLARE_R4300 rrd = (uint64_t) rrt >> (32 + rsa); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRA) { DECLARE_R4300 rrd = SE32(rrt >> rsa); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SRAV) { DECLARE_R4300 rrd = SE32(rrt >> (rrs32 & 0x1F)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRA) { DECLARE_R4300 rrd = rrt >> rsa; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRAV) { DECLARE_R4300 rrd = (int64_t) rrt >> (rrs32 & 0x3F); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DSRA32) { DECLARE_R4300 rrd = (int64_t) rrt >> (32 + rsa); ADD_TO_PC(1); } /* Multiply / Divide instructions */ DECLARE_INSTRUCTION(MULT) { DECLARE_R4300 int64_t temp; temp = rrs32 * (int64_t)rrt32; *r4300_mult_hi(r4300) = temp >> 32; *r4300_mult_lo(r4300) = SE32(temp); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MULTU) { DECLARE_R4300 uint64_t temp; temp = (uint32_t) rrs * (uint64_t) ((uint32_t) rrt); *r4300_mult_hi(r4300) = (int64_t) temp >> 32; *r4300_mult_lo(r4300) = SE32(temp); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMULT) { DECLARE_R4300 uint64_t op1, op2, op3, op4; uint64_t result1, result2, result3, result4; uint64_t temp1, temp2, temp3, temp4; int sign = 0; if (rrs < 0) { op2 = -rrs; sign = 1 - sign; } else { op2 = rrs; } if (rrt < 0) { op4 = -rrt; sign = 1 - sign; } else { op4 = rrt; } op1 = op2 & UINT64_C(0xFFFFFFFF); op2 = (op2 >> 32) & UINT64_C(0xFFFFFFFF); op3 = op4 & UINT64_C(0xFFFFFFFF); op4 = (op4 >> 32) & UINT64_C(0xFFFFFFFF); temp1 = op1 * op3; temp2 = (temp1 >> 32) + op1 * op4; temp3 = op2 * op3; temp4 = (temp3 >> 32) + op2 * op4; result1 = temp1 & UINT64_C(0xFFFFFFFF); result2 = temp2 + (temp3 & UINT64_C(0xFFFFFFFF)); result3 = (result2 >> 32) + temp4; result4 = (result3 >> 32); *r4300_mult_lo(r4300) = result1 | (result2 << 32); *r4300_mult_hi(r4300) = (result3 & UINT64_C(0xFFFFFFFF)) | (result4 << 32); if (sign) { *r4300_mult_hi(r4300) = ~*r4300_mult_hi(r4300); if (!*r4300_mult_lo(r4300)) { (*r4300_mult_hi(r4300))++; } else { *r4300_mult_lo(r4300) = ~*r4300_mult_lo(r4300) + 1; } } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMULTU) { DECLARE_R4300 uint64_t op1, op2, op3, op4; uint64_t result1, result2, result3, result4; uint64_t temp1, temp2, temp3, temp4; op1 = rrs & UINT64_C(0xFFFFFFFF); op2 = (rrs >> 32) & UINT64_C(0xFFFFFFFF); op3 = rrt & UINT64_C(0xFFFFFFFF); op4 = (rrt >> 32) & UINT64_C(0xFFFFFFFF); temp1 = op1 * op3; temp2 = (temp1 >> 32) + op1 * op4; temp3 = op2 * op3; temp4 = (temp3 >> 32) + op2 * op4; result1 = temp1 & UINT64_C(0xFFFFFFFF); result2 = temp2 + (temp3 & UINT64_C(0xFFFFFFFF)); result3 = (result2 >> 32) + temp4; result4 = (result3 >> 32); *r4300_mult_lo(r4300) = result1 | (result2 << 32); *r4300_mult_hi(r4300) = (result3 & UINT64_C(0xFFFFFFFF)) | (result4 << 32); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DIV) { DECLARE_R4300 if (rrt32) { if (rrs32 == INT32_MIN && rrt32 == -1) { *r4300_mult_lo(r4300) = SE32(rrs32); *r4300_mult_hi(r4300) = 0; } else { *r4300_mult_lo(r4300) = SE32(rrs32 / rrt32); *r4300_mult_hi(r4300) = SE32(rrs32 % rrt32); } } else { *r4300_mult_lo(r4300) = rrs32 < 0 ? 1 : -1; *r4300_mult_hi(r4300) = SE32(rrs32); } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DIVU) { DECLARE_R4300 if (rrt32) { *r4300_mult_lo(r4300) = SE32((uint32_t) rrs32 / (uint32_t) rrt32); *r4300_mult_hi(r4300) = SE32((uint32_t) rrs32 % (uint32_t) rrt32); } else { *r4300_mult_lo(r4300) = -1; *r4300_mult_hi(r4300) = SE32(rrs32); } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DDIV) { DECLARE_R4300 if (rrt) { if (rrs == INT64_MIN && rrt == -1) { *r4300_mult_lo(r4300) = rrs; *r4300_mult_hi(r4300) = 0; } else { *r4300_mult_lo(r4300) = rrs / rrt; *r4300_mult_hi(r4300) = rrs % rrt; } } else { *r4300_mult_lo(r4300) = rrs < 0 ? 1 : -1; *r4300_mult_hi(r4300) = rrs; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DDIVU) { DECLARE_R4300 if (rrt) { *r4300_mult_lo(r4300) = (uint64_t) rrs / (uint64_t) rrt; *r4300_mult_hi(r4300) = (uint64_t) rrs % (uint64_t) rrt; } else { *r4300_mult_lo(r4300) = -1; *r4300_mult_hi(r4300) = rrs; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(MFHI) { DECLARE_R4300 rrd = *r4300_mult_hi(r4300); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MTHI) { DECLARE_R4300 *r4300_mult_hi(r4300) = rrs; ADD_TO_PC(1); } DECLARE_INSTRUCTION(MFLO) { DECLARE_R4300 rrd = *r4300_mult_lo(r4300); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MTLO) { DECLARE_R4300 *r4300_mult_lo(r4300) = rrs; ADD_TO_PC(1); } /* Jump & Branch instructions */ DECLARE_JUMP(J, (jinst_index<<2) | ((PCADDR+4) & UINT32_C(0xF0000000)), 1, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(JAL, (jinst_index<<2) | ((PCADDR+4) & UINT32_C(0xF0000000)), 1, &r4300_regs(r4300)[31], 0, 0) DECLARE_JUMP(JR, irs32, 1, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(JALR, irs32, 1, &rrd, 0, 0) DECLARE_JUMP(BEQ, PCADDR + (iimmediate+1)*4, irs == irt, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(BEQL, PCADDR + (iimmediate+1)*4, irs == irt, &r4300_regs(r4300)[0], 1, 0) DECLARE_JUMP(BNE, PCADDR + (iimmediate+1)*4, irs != irt, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(BNEL, PCADDR + (iimmediate+1)*4, irs != irt, &r4300_regs(r4300)[0], 1, 0) DECLARE_JUMP(BLEZ, PCADDR + (iimmediate+1)*4, irs <= 0, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(BLEZL, PCADDR + (iimmediate+1)*4, irs <= 0, &r4300_regs(r4300)[0], 1, 0) DECLARE_JUMP(BGTZ, PCADDR + (iimmediate+1)*4, irs > 0, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(BGTZL, PCADDR + (iimmediate+1)*4, irs > 0, &r4300_regs(r4300)[0], 1, 0) DECLARE_JUMP(BLTZ, PCADDR + (iimmediate+1)*4, irs < 0, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(BLTZAL, PCADDR + (iimmediate+1)*4, irs < 0, &r4300_regs(r4300)[31], 0, 0) DECLARE_JUMP(BLTZL, PCADDR + (iimmediate+1)*4, irs < 0, &r4300_regs(r4300)[0], 1, 0) DECLARE_JUMP(BLTZALL, PCADDR + (iimmediate+1)*4, irs < 0, &r4300_regs(r4300)[31], 1, 0) DECLARE_JUMP(BGEZ, PCADDR + (iimmediate+1)*4, irs >= 0, &r4300_regs(r4300)[0], 0, 0) DECLARE_JUMP(BGEZAL, PCADDR + (iimmediate+1)*4, irs >= 0, &r4300_regs(r4300)[31], 0, 0) DECLARE_JUMP(BGEZL, PCADDR + (iimmediate+1)*4, irs >= 0, &r4300_regs(r4300)[0], 1, 0) DECLARE_JUMP(BGEZALL, PCADDR + (iimmediate+1)*4, irs >= 0, &r4300_regs(r4300)[31], 1, 0) DECLARE_JUMP(BC1F, PCADDR + (iimmediate+1)*4, ((*r4300_cp1_fcr31(&r4300->cp1)) & FCR31_CMP_BIT)==0, &r4300_regs(r4300)[0], 0, 1) DECLARE_JUMP(BC1FL, PCADDR + (iimmediate+1)*4, ((*r4300_cp1_fcr31(&r4300->cp1)) & FCR31_CMP_BIT)==0, &r4300_regs(r4300)[0], 1, 1) DECLARE_JUMP(BC1T, PCADDR + (iimmediate+1)*4, ((*r4300_cp1_fcr31(&r4300->cp1)) & FCR31_CMP_BIT)!=0, &r4300_regs(r4300)[0], 0, 1) DECLARE_JUMP(BC1TL, PCADDR + (iimmediate+1)*4, ((*r4300_cp1_fcr31(&r4300->cp1)) & FCR31_CMP_BIT)!=0, &r4300_regs(r4300)[0], 1, 1) /* Special instructions */ DECLARE_INSTRUCTION(CACHE) { DECLARE_R4300 ADD_TO_PC(1); } DECLARE_INSTRUCTION(ERET) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); cp0_update_count(r4300); if (cp0_regs[CP0_STATUS_REG] & CP0_STATUS_ERL) { DebugMessage(M64MSG_ERROR, "error in ERET"); *r4300_stop(r4300)=1; } else { cp0_regs[CP0_STATUS_REG] &= ~CP0_STATUS_EXL; generic_jump_to(r4300, cp0_regs[CP0_EPC_REG]); } r4300->llbit = 0; r4300_check_interrupt(r4300, CP0_CAUSE_IP2, r4300->mi->regs[MI_INTR_REG] & r4300->mi->regs[MI_INTR_MASK_REG]); // ??? r4300->cp0.last_addr = PCADDR; if (*cp0_cycle_count >= 0) { gen_interrupt(r4300); } } DECLARE_INSTRUCTION(SYNC) { DECLARE_R4300 ADD_TO_PC(1); } DECLARE_INSTRUCTION(SYSCALL) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_SYS; exception_general(r4300); } /* Trap instructions */ #define DECLARE_TRAP(name, cond) \ DECLARE_INSTRUCTION(name) \ { \ DECLARE_R4300 \ uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \ if (cond) \ { \ cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_TR; \ exception_general(r4300); \ } \ else \ { \ ADD_TO_PC(1); \ } \ } DECLARE_TRAP(TGE, rrs >= rrt) DECLARE_TRAP(TGEU, (uint64_t) rrs >= (uint64_t) rrt) DECLARE_TRAP(TGEI, rrs >= (int64_t)iimmediate) DECLARE_TRAP(TGEIU, (uint64_t)rrs >= (uint64_t)(int64_t)iimmediate) DECLARE_TRAP(TLT, rrs < rrt) DECLARE_TRAP(TLTU, (uint64_t) rrs < (uint64_t) rrt) DECLARE_TRAP(TLTI, rrs < (int64_t)iimmediate) DECLARE_TRAP(TLTIU, (uint64_t)rrs < (uint64_t)(int64_t)iimmediate) DECLARE_TRAP(TEQ, rrs == rrt) DECLARE_TRAP(TEQI, rrs == (int64_t)iimmediate) DECLARE_TRAP(TNE, rrs != rrt) DECLARE_TRAP(TNEI, rrs != (int64_t)iimmediate) #undef DECLARE_TRAP /* TLB instructions */ DECLARE_INSTRUCTION(TLBP) { DECLARE_R4300 int i; uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); cp0_regs[CP0_INDEX_REG] |= UINT32_C(0x80000000); for (i = 0; i < 32; ++i) { if (((r4300->cp0.tlb.entries[i].vpn2 & (~r4300->cp0.tlb.entries[i].mask)) == (((cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFFFFE000)) >> 13) & (~r4300->cp0.tlb.entries[i].mask))) && ((r4300->cp0.tlb.entries[i].g) || (r4300->cp0.tlb.entries[i].asid == (cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFF))))) { cp0_regs[CP0_INDEX_REG] = i; break; } } ADD_TO_PC(1); } DECLARE_INSTRUCTION(TLBR) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); int index; index = cp0_regs[CP0_INDEX_REG] & UINT32_C(0x1F); cp0_regs[CP0_PAGEMASK_REG] = r4300->cp0.tlb.entries[index].mask << 13; cp0_regs[CP0_ENTRYHI_REG] = ((r4300->cp0.tlb.entries[index].vpn2 << 13) | r4300->cp0.tlb.entries[index].asid); cp0_regs[CP0_ENTRYLO0_REG] = (r4300->cp0.tlb.entries[index].pfn_even << 6) | (r4300->cp0.tlb.entries[index].c_even << 3) | (r4300->cp0.tlb.entries[index].d_even << 2) | (r4300->cp0.tlb.entries[index].v_even << 1) | r4300->cp0.tlb.entries[index].g; cp0_regs[CP0_ENTRYLO1_REG] = (r4300->cp0.tlb.entries[index].pfn_odd << 6) | (r4300->cp0.tlb.entries[index].c_odd << 3) | (r4300->cp0.tlb.entries[index].d_odd << 2) | (r4300->cp0.tlb.entries[index].v_odd << 1) | r4300->cp0.tlb.entries[index].g; ADD_TO_PC(1); } static void TLBWrite(struct r4300_core* r4300, unsigned int idx) { uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); uint32_t pc_addr = *r4300_pc(r4300); if (pc_addr >= r4300->cp0.tlb.entries[idx].start_even && pc_addr < r4300->cp0.tlb.entries[idx].end_even && r4300->cp0.tlb.entries[idx].v_even) return; if (pc_addr >= r4300->cp0.tlb.entries[idx].start_odd && pc_addr < r4300->cp0.tlb.entries[idx].end_odd && r4300->cp0.tlb.entries[idx].v_odd) return; if (r4300->emumode != EMUMODE_PURE_INTERPRETER) { unsigned int i; if (r4300->cp0.tlb.entries[idx].v_even) { for (i=r4300->cp0.tlb.entries[idx].start_even>>12; i<=r4300->cp0.tlb.entries[idx].end_even>>12; i++) { if(!r4300->cached_interp.invalid_code[i] &&(r4300->cached_interp.invalid_code[r4300->cp0.tlb.LUT_r[i]>>12] || r4300->cached_interp.invalid_code[(r4300->cp0.tlb.LUT_r[i]>>12)+0x20000])) { r4300->cached_interp.invalid_code[i] = 1; } if (!r4300->cached_interp.invalid_code[i]) { r4300->cached_interp.blocks[i]->xxhash = XXH3_64bits(&r4300->rdram->dram[(r4300->cp0.tlb.LUT_r[i]&0x7FF000)/4], 0x1000); r4300->cached_interp.invalid_code[i] = 1; } else if (r4300->cached_interp.blocks[i]) { r4300->cached_interp.blocks[i]->xxhash = 0; } } } if (r4300->cp0.tlb.entries[idx].v_odd) { for (i=r4300->cp0.tlb.entries[idx].start_odd>>12; i<=r4300->cp0.tlb.entries[idx].end_odd>>12; i++) { if(!r4300->cached_interp.invalid_code[i] &&(r4300->cached_interp.invalid_code[r4300->cp0.tlb.LUT_r[i]>>12] || r4300->cached_interp.invalid_code[(r4300->cp0.tlb.LUT_r[i]>>12)+0x20000])) { r4300->cached_interp.invalid_code[i] = 1; } if (!r4300->cached_interp.invalid_code[i]) { r4300->cached_interp.blocks[i]->xxhash = XXH3_64bits(&r4300->rdram->dram[(r4300->cp0.tlb.LUT_r[i]&0x7FF000)/4], 0x1000); r4300->cached_interp.invalid_code[i] = 1; } else if (r4300->cached_interp.blocks[i]) { r4300->cached_interp.blocks[i]->xxhash = 0; } } } } tlb_unmap(&r4300->cp0.tlb, idx); r4300->cp0.tlb.entries[idx].g = (cp0_regs[CP0_ENTRYLO0_REG] & cp0_regs[CP0_ENTRYLO1_REG] & 1); r4300->cp0.tlb.entries[idx].pfn_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x3FFFFFC0)) >> 6; r4300->cp0.tlb.entries[idx].pfn_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x3FFFFFC0)) >> 6; r4300->cp0.tlb.entries[idx].c_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x38)) >> 3; r4300->cp0.tlb.entries[idx].c_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x38)) >> 3; r4300->cp0.tlb.entries[idx].d_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x4)) >> 2; r4300->cp0.tlb.entries[idx].d_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x4)) >> 2; r4300->cp0.tlb.entries[idx].v_even = (cp0_regs[CP0_ENTRYLO0_REG] & UINT32_C(0x2)) >> 1; r4300->cp0.tlb.entries[idx].v_odd = (cp0_regs[CP0_ENTRYLO1_REG] & UINT32_C(0x2)) >> 1; r4300->cp0.tlb.entries[idx].asid = (cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFF)); r4300->cp0.tlb.entries[idx].vpn2 = (cp0_regs[CP0_ENTRYHI_REG] & UINT32_C(0xFFFFE000)) >> 13; //r4300->cp0.tlb.entries[idx].r = (cp0_regs[CP0_ENTRYHI_REG] & 0xC000000000000000LL) >> 62; r4300->cp0.tlb.entries[idx].mask = (cp0_regs[CP0_PAGEMASK_REG] & UINT32_C(0x1FFE000)) >> 13; r4300->cp0.tlb.entries[idx].start_even = r4300->cp0.tlb.entries[idx].vpn2 << 13; r4300->cp0.tlb.entries[idx].end_even = r4300->cp0.tlb.entries[idx].start_even+ (r4300->cp0.tlb.entries[idx].mask << 12) + UINT32_C(0xFFF); r4300->cp0.tlb.entries[idx].phys_even = r4300->cp0.tlb.entries[idx].pfn_even << 12; r4300->cp0.tlb.entries[idx].start_odd = r4300->cp0.tlb.entries[idx].end_even+1; r4300->cp0.tlb.entries[idx].end_odd = r4300->cp0.tlb.entries[idx].start_odd+ (r4300->cp0.tlb.entries[idx].mask << 12) + UINT32_C(0xFFF); r4300->cp0.tlb.entries[idx].phys_odd = r4300->cp0.tlb.entries[idx].pfn_odd << 12; tlb_map(&r4300->cp0.tlb, idx); if (r4300->emumode != EMUMODE_PURE_INTERPRETER) { unsigned int i; if (r4300->cp0.tlb.entries[idx].v_even) { for (i=r4300->cp0.tlb.entries[idx].start_even>>12; i<=r4300->cp0.tlb.entries[idx].end_even>>12; i++) { if(r4300->cached_interp.blocks[i] && r4300->cached_interp.blocks[i]->xxhash) { if(r4300->cached_interp.blocks[i]->xxhash == XXH3_64bits(&r4300->rdram->dram[(r4300->cp0.tlb.LUT_r[i]&0x7FF000)/4], 0x1000)) { r4300->cached_interp.invalid_code[i] = 0; } } } } if (r4300->cp0.tlb.entries[idx].v_odd) { for (i=r4300->cp0.tlb.entries[idx].start_odd>>12; i<=r4300->cp0.tlb.entries[idx].end_odd>>12; i++) { if(r4300->cached_interp.blocks[i] && r4300->cached_interp.blocks[i]->xxhash) { if(r4300->cached_interp.blocks[i]->xxhash == XXH3_64bits(&r4300->rdram->dram[(r4300->cp0.tlb.LUT_r[i]&0x7FF000)/4], 0x1000)) { r4300->cached_interp.invalid_code[i] = 0; } } } } } } DECLARE_INSTRUCTION(TLBWR) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); cp0_update_count(r4300); cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG])) + cp0_regs[CP0_WIRED_REG]; TLBWrite(r4300, cp0_regs[CP0_RANDOM_REG]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(TLBWI) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); TLBWrite(r4300, cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F)); ADD_TO_PC(1); } /* CP0 load/store instructions */ DECLARE_INSTRUCTION(MFC0) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); uint64_t* cp0_latch = r4300_cp0_latch(&r4300->cp0); switch(rfs) { case CP0_RANDOM_REG: cp0_update_count(r4300); cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG])) + cp0_regs[CP0_WIRED_REG]; rrt = SE32(cp0_regs[rfs]); break; case CP0_COUNT_REG: cp0_update_count(r4300); rrt = SE32(cp0_regs[rfs]); break; case CP0_UNUSED_7: case CP0_UNUSED_21: case CP0_UNUSED_22: case CP0_UNUSED_23: case CP0_UNUSED_24: case CP0_UNUSED_25: case CP0_UNUSED_31: rrt = (*cp0_latch); break; default: rrt = SE32(cp0_regs[rfs]); break; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMFC0) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); uint64_t* cp0_latch = r4300_cp0_latch(&r4300->cp0); switch(rfs) { case CP0_RANDOM_REG: cp0_update_count(r4300); cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG])) + cp0_regs[CP0_WIRED_REG]; rrt = cp0_regs[rfs]; break; case CP0_COUNT_REG: cp0_update_count(r4300); rrt = cp0_regs[rfs]; break; case CP0_EPC_REG: rrt = SE32(cp0_regs[rfs]); break; case CP0_UNUSED_7: case CP0_UNUSED_21: case CP0_UNUSED_22: case CP0_UNUSED_23: case CP0_UNUSED_24: case CP0_UNUSED_25: case CP0_UNUSED_31: rrt = (*cp0_latch); break; default: rrt = cp0_regs[rfs]; break; } ADD_TO_PC(1); } DECLARE_INSTRUCTION(MTC0) { DECLARE_R4300 uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); uint64_t* cp0_latch = r4300_cp0_latch(&r4300->cp0); int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); (*cp0_latch) = rrt32; switch(rfs) { case CP0_INDEX_REG: cp0_regs[CP0_INDEX_REG] = rrt32 & UINT32_C(0x8000003F); if ((cp0_regs[CP0_INDEX_REG] & UINT32_C(0x3F)) > UINT32_C(31)) { DebugMessage(M64MSG_ERROR, "MTC0 instruction writing Index register with TLB index > 31"); *r4300_stop(r4300)=1; } break; case CP0_RANDOM_REG: break; case CP0_ENTRYLO0_REG: cp0_regs[CP0_ENTRYLO0_REG] = rrt32 & UINT32_C(0x3FFFFFFF); break; case CP0_ENTRYLO1_REG: cp0_regs[CP0_ENTRYLO1_REG] = rrt32 & UINT32_C(0x3FFFFFFF); break; case CP0_CONTEXT_REG: cp0_regs[CP0_CONTEXT_REG] = (rrt32 & UINT32_C(0xFF800000)) | (cp0_regs[CP0_CONTEXT_REG] & UINT32_C(0x007FFFF0)); break; case CP0_PAGEMASK_REG: cp0_regs[CP0_PAGEMASK_REG] = rrt32 & UINT32_C(0x01FFE000); break; case CP0_WIRED_REG: cp0_regs[CP0_WIRED_REG] = rrt32 & UINT32_C(0x0000003F); cp0_regs[CP0_RANDOM_REG] = UINT32_C(31); break; case CP0_BADVADDR_REG: break; case CP0_COUNT_REG: cp0_update_count(r4300); r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_R4300; if (*cp0_cycle_count >= 0) { gen_interrupt(r4300); } r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_R4300; translate_event_queue(&r4300->cp0, rrt32); break; case CP0_ENTRYHI_REG: cp0_regs[CP0_ENTRYHI_REG] = rrt32 & UINT32_C(0xFFFFE0FF); break; case CP0_COMPARE_REG: cp0_update_count(r4300); remove_event(&r4300->cp0.q, COMPARE_INT); /* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */ cp0_regs[CP0_COUNT_REG] += r4300->cp0.count_per_op; *cp0_cycle_count += r4300->cp0.count_per_op; add_interrupt_event_count(&r4300->cp0, COMPARE_INT, rrt32); cp0_regs[CP0_COUNT_REG] -= r4300->cp0.count_per_op; /* Update next interrupt in case first event is COMPARE_INT */ *cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - r4300->cp0.q.first->data.count; cp0_regs[CP0_COMPARE_REG] = rrt32; cp0_regs[CP0_CAUSE_REG] &= ~CP0_CAUSE_IP7; break; case CP0_STATUS_REG: rrt32 &= ~UINT32_C(0x080000); /* 19th bit isn't writable */ if((rrt32 & CP0_STATUS_FR) != (cp0_regs[CP0_STATUS_REG] & CP0_STATUS_FR)) set_fpr_pointers(&r4300->cp1, rrt32); cp0_regs[CP0_STATUS_REG] = rrt32; ADD_TO_PC(1); cp0_update_count(r4300); r4300_check_interrupt(r4300, CP0_CAUSE_IP2, r4300->mi->regs[MI_INTR_REG] & r4300->mi->regs[MI_INTR_MASK_REG]); // ??? r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_R4300; if (*cp0_cycle_count >= 0) { gen_interrupt(r4300); } r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_R4300; return; case CP0_CAUSE_REG: cp0_regs[CP0_CAUSE_REG] &= ~(CP0_CAUSE_IP0 | CP0_CAUSE_IP1); cp0_regs[CP0_CAUSE_REG] |= rrt32 & (CP0_CAUSE_IP0 | CP0_CAUSE_IP1); break; case CP0_EPC_REG: cp0_regs[CP0_EPC_REG] = rrt32; break; case CP0_PREVID_REG: break; case CP0_CONFIG_REG: cp0_regs[CP0_CONFIG_REG] = (rrt32 & UINT32_C(0x0000000F)) | (cp0_regs[CP0_CONFIG_REG] & UINT32_C(0x00008000)) | (cp0_regs[CP0_CONFIG_REG] & UINT32_C(0x7FFFFFFF)); break; case CP0_LLADDR_REG: cp0_regs[CP0_LLADDR_REG] = rrt32; break; case CP0_WATCHLO_REG: cp0_regs[CP0_WATCHLO_REG] = rrt32; break; case CP0_WATCHHI_REG: cp0_regs[CP0_WATCHHI_REG] = rrt32; break; case CP0_XCONTEXT_REG: break; case CP0_CACHEERR_REG: break; case CP0_PARITYERR_REG: cp0_regs[CP0_PARITYERR_REG] = rrt32 & UINT32_C(0x000000FF); break; case CP0_TAGLO_REG: cp0_regs[CP0_TAGLO_REG] = rrt32 & UINT32_C(0x0FFFFFC0); break; case CP0_TAGHI_REG: cp0_regs[CP0_TAGHI_REG] = 0; break; case CP0_ERROREPC_REG: cp0_regs[CP0_ERROREPC_REG] = rrt32; break; default: break; } ADD_TO_PC(1); } /* CP1 load/store instructions */ DECLARE_INSTRUCTION(LWC1) { DECLARE_R4300 const unsigned char lslfft = lfft; const uint32_t lslfaddr = (uint32_t) r4300_regs(r4300)[lfbase] + lfoffset; if (check_cop1_unusable(r4300)) { return; } ADD_TO_PC(1); r4300_read_aligned_word(r4300, lslfaddr, (uint32_t*)r4300_cp1_regs_simple(&r4300->cp1)[lslfft]); } DECLARE_INSTRUCTION(LDC1) { DECLARE_R4300 const unsigned char lslfft = lfft; const uint32_t lslfaddr = (uint32_t) r4300_regs(r4300)[lfbase] + lfoffset; if (check_cop1_unusable(r4300)) { return; } ADD_TO_PC(1); r4300_read_aligned_dword(r4300, lslfaddr, (uint64_t*)r4300_cp1_regs_double(&r4300->cp1)[lslfft]); } DECLARE_INSTRUCTION(SWC1) { DECLARE_R4300 const unsigned char lslfft = lfft; const uint32_t lslfaddr = (uint32_t) r4300_regs(r4300)[lfbase] + lfoffset; if (check_cop1_unusable(r4300)) { return; } ADD_TO_PC(1); r4300_write_aligned_word(r4300, lslfaddr, *((uint32_t*)(r4300_cp1_regs_simple(&r4300->cp1))[lslfft]), ~UINT32_C(0)); } DECLARE_INSTRUCTION(SDC1) { DECLARE_R4300 const unsigned char lslfft = lfft; const uint32_t lslfaddr = (uint32_t) r4300_regs(r4300)[lfbase] + lfoffset; if (check_cop1_unusable(r4300)) { return; } ADD_TO_PC(1); r4300_write_aligned_dword(r4300, lslfaddr, *((uint64_t*)(r4300_cp1_regs_double(&r4300->cp1))[lslfft]), ~UINT64_C(0)); } DECLARE_INSTRUCTION(MFC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } rrt = SE32(*((int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[rfs])); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMFC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } rrt = *((int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[rfs]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CFC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } if (rfs==31) { rrt = SE32((*r4300_cp1_fcr31(&r4300->cp1))); } if (rfs==0) { rrt = SE32((*r4300_cp1_fcr0(&r4300->cp1))); } ADD_TO_PC(1); } DECLARE_INSTRUCTION(DCFC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); fpu_reset_cause(r4300_cp1_fcr31(&r4300->cp1)); /* Unimplemented Operation */ (*r4300_cp1_fcr31(&r4300->cp1)) |= FCR31_CAUSE_UNIMPLOP_BIT; cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_FPE; exception_general(r4300); } DECLARE_INSTRUCTION(MTC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } *((int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[rfs]) = rrt32; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMTC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } *((int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[rfs]) = rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(CTC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } if (rfs==31) { (*r4300_cp1_fcr31(&r4300->cp1)) = rrt32; update_x86_rounding_mode(&r4300->cp1); } //if (((*r4300_cp1_fcr31(&r4300->cp1)) >> 7) & 0x1F) printf("FPU Exception enabled : %x\n", // (int)(((*r4300_cp1_fcr31(&r4300->cp1)) >> 7) & 0x1F)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DCTC1) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); fpu_reset_cause(r4300_cp1_fcr31(&r4300->cp1)); /* Unimplemented Operation */ (*r4300_cp1_fcr31(&r4300->cp1)) |= FCR31_CAUSE_UNIMPLOP_BIT; cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_FPE; exception_general(r4300); } /* CP2 load/store instructions */ DECLARE_INSTRUCTION(MFC2) { DECLARE_R4300 if (check_cop2_unusable(r4300)) { return; } rrt = SE32(*r4300_cp2_latch(&r4300->cp2)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMFC2) { DECLARE_R4300 if (check_cop2_unusable(r4300)) { return; } rrt = (*r4300_cp2_latch(&r4300->cp2)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CFC2) { DECLARE_R4300 if (check_cop2_unusable(r4300)) { return; } rrt = SE32(*r4300_cp2_latch(&r4300->cp2)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MTC2) { DECLARE_R4300 if (check_cop2_unusable(r4300)) { return; } (*r4300_cp2_latch(&r4300->cp2)) = rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(DMTC2) { DECLARE_R4300 if (check_cop2_unusable(r4300)) { return; } (*r4300_cp2_latch(&r4300->cp2)) = rrt; ADD_TO_PC(1); } DECLARE_INSTRUCTION(CTC2) { DECLARE_R4300 if (check_cop2_unusable(r4300)) { return; } (*r4300_cp2_latch(&r4300->cp2)) = rrt; ADD_TO_PC(1); } /* CP1 computational instructions */ DECLARE_INSTRUCTION(ABS_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } abs_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ABS_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } abs_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADD_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } add_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ADD_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } add_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DIV_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } div_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(DIV_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } div_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MOV_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } mov_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MOV_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } mov_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MUL_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } mul_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(MUL_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } mul_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(NEG_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } neg_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(NEG_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } neg_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SQRT_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } sqrt_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SQRT_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } sqrt_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SUB_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } sub_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(SUB_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } sub_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(TRUNC_W_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } trunc_w_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(TRUNC_W_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } trunc_w_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(TRUNC_L_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } trunc_l_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(TRUNC_L_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } trunc_l_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ROUND_W_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } round_w_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ROUND_W_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } round_w_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ROUND_L_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } round_l_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(ROUND_L_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } round_l_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CEIL_W_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } ceil_w_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CEIL_W_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } ceil_w_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CEIL_L_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } ceil_l_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CEIL_L_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } ceil_l_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(FLOOR_W_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } floor_w_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(FLOOR_W_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } floor_w_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(FLOOR_L_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } floor_l_s((r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(FLOOR_L_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } floor_l_d((r4300_cp1_regs_double(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_S_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_s_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_S_W) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_s_w(r4300_cp1_fcr31(&r4300->cp1), (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_S_L) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_s_l(r4300_cp1_fcr31(&r4300->cp1), (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_D_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_d_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_D_W) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_d_w(r4300_cp1_fcr31(&r4300->cp1), (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_D_L) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_d_l(r4300_cp1_fcr31(&r4300->cp1), (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_W_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_w_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_W_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_w_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (int32_t*) (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_L_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_l_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(CVT_L_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } cvt_l_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (int64_t*) (r4300_cp1_regs_double(&r4300->cp1))[cffd]); ADD_TO_PC(1); } /* CP1 relational instructions */ DECLARE_INSTRUCTION(C_F_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_f_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cffd]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_F_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_f_d(r4300_cp1_fcr31(&r4300->cp1)); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_UN_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_un_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_UN_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_un_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_EQ_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_eq_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_EQ_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_eq_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_UEQ_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ueq_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_UEQ_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ueq_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_OLT_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_olt_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_OLT_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_olt_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_ULT_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ult_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_ULT_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ult_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_OLE_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ole_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_OLE_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ole_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_ULE_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ule_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_ULE_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ule_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_SF_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_sf_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_SF_D) { DECLARE_R4300 c_sf_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGLE_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ngle_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGLE_D) { DECLARE_R4300 c_ngle_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_SEQ_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_seq_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_SEQ_D) { DECLARE_R4300 c_seq_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGL_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ngl_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGL_D) { DECLARE_R4300 c_ngl_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_LT_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_lt_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_LT_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_lt_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGE_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_nge_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGE_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_nge_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_LE_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_le_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_LE_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_le_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGT_S) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ngt_s(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_simple(&r4300->cp1))[cffs], (r4300_cp1_regs_simple(&r4300->cp1))[cfft]); ADD_TO_PC(1); } DECLARE_INSTRUCTION(C_NGT_D) { DECLARE_R4300 if (check_cop1_unusable(r4300)) { return; } c_ngt_d(r4300_cp1_fcr31(&r4300->cp1), (r4300_cp1_regs_double(&r4300->cp1))[cffs], (r4300_cp1_regs_double(&r4300->cp1))[cfft]); ADD_TO_PC(1); } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/000077500000000000000000000000001464506436200225425ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm/000077500000000000000000000000001464506436200233215ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm/arm_cpu_features.c000066400000000000000000000121531464506436200270130ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - arm_cpu_features.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2015 Gilles Siberlin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "api/callbacks.h" #include "arm_cpu_features.h" arm_cpu_features_t arm_cpu_features; const char procfile[] = "/proc/cpuinfo"; static unsigned char check_arm_cpu_feature(const char* feature) { unsigned char status = 0; FILE *pFile = osal_file_open(procfile, "r"); if (pFile != NULL) { char line[1024]; while (fgets(line , sizeof(line) , pFile) != NULL) { if (strncmp(line, "Features\t: ", 11)) continue; if (strstr(line + 11, feature) != NULL) status = 1; break; } fclose(pFile); } return status; } static unsigned char get_arm_cpu_implementer(void) { unsigned char implementer = 0; FILE *pFile = osal_file_open(procfile, "r"); if (pFile != NULL) { char line[1024]; while (fgets(line , sizeof(line) , pFile) != NULL) { if (strncmp(line, "CPU implementer\t: ", 18)) continue; sscanf(line+18, "0x%02hhx", &implementer); break; } fclose(pFile); } return implementer; } static unsigned short get_arm_cpu_part(void) { unsigned short part = 0; FILE *pFile = osal_file_open(procfile, "r"); if (pFile != NULL) { char line[1024]; while (fgets(line , sizeof(line) , pFile) != NULL) { if (strncmp(line, "CPU part\t: ", 11)) continue; sscanf(line+11, "0x%03hx", &part); break; } fclose(pFile); } return part; } void detect_arm_cpu_features(void) { arm_cpu_features.SWP = check_arm_cpu_feature("swp"); arm_cpu_features.Half = check_arm_cpu_feature("half"); arm_cpu_features.Thumb = check_arm_cpu_feature("thumb"); arm_cpu_features.FastMult = check_arm_cpu_feature("fastmult"); arm_cpu_features.VFP = check_arm_cpu_feature("vfp"); arm_cpu_features.EDSP = check_arm_cpu_feature("edsp"); arm_cpu_features.ThumbEE = check_arm_cpu_feature("thumbee"); arm_cpu_features.NEON = check_arm_cpu_feature("neon"); arm_cpu_features.VFPv3 = check_arm_cpu_feature("vfpv3"); arm_cpu_features.TLS = check_arm_cpu_feature("tls"); arm_cpu_features.VFPv4 = check_arm_cpu_feature("vfpv4"); arm_cpu_features.IDIVa = check_arm_cpu_feature("idiva"); arm_cpu_features.IDIVt = check_arm_cpu_feature("idivt"); // Qualcomm Krait supports IDIVa but it doesn't report it. Check for krait. if (get_arm_cpu_implementer() == 0x51 && get_arm_cpu_part() == 0x6F) arm_cpu_features.IDIVa = arm_cpu_features.IDIVt = 1; } void print_arm_cpu_features(void) { char buffer[1024]; strcpy(buffer, "ARM CPU Features:"); if (arm_cpu_features.SWP) strcat(buffer, " SWP"); if (arm_cpu_features.Half) strcat(buffer, ", Half"); if (arm_cpu_features.Thumb) strcat(buffer, ", Thumb"); if (arm_cpu_features.FastMult) strcat(buffer, ", FastMult"); if (arm_cpu_features.VFP) strcat(buffer, ", VFP"); if (arm_cpu_features.EDSP) strcat(buffer, ", ESDP"); if (arm_cpu_features.ThumbEE) strcat(buffer, ", ThumbEE"); if (arm_cpu_features.NEON) strcat(buffer, ", NEON"); if (arm_cpu_features.VFPv3) strcat(buffer, ", VFPv3"); if (arm_cpu_features.TLS) strcat(buffer, ", TLS"); if (arm_cpu_features.VFPv4) strcat(buffer, ", VFPv4"); if (arm_cpu_features.IDIVa) strcat(buffer, ", IDIVa"); if (arm_cpu_features.IDIVt) strcat(buffer, ", IDIVt"); DebugMessage(M64MSG_INFO, "%s", buffer); } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm/arm_cpu_features.h000066400000000000000000000042371464506436200270240ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - arm_cpu_features.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2015 Gilles Siberlin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ARM_CPU_FEATURES_H #define M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ARM_CPU_FEATURES_H typedef struct { unsigned char SWP; unsigned char Half; unsigned char Thumb; unsigned char FastMult; unsigned char VFP; unsigned char EDSP; unsigned char ThumbEE; unsigned char NEON; unsigned char VFPv3; unsigned char TLS; unsigned char VFPv4; unsigned char IDIVa; unsigned char IDIVt; }arm_cpu_features_t; extern arm_cpu_features_t arm_cpu_features; void detect_arm_cpu_features(void); void print_arm_cpu_features(void); #endif /* M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ARM_CPU_FEATURES_H */ mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm/assem_arm.c000066400000000000000000003644261464506436200254530ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assem_arm.c * * Copyright (C) 2009-2011 Ari64 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* ease access to fp-addressed variables */ #define fp_cycle_count (offsetof(struct new_dynarec_hot_state, cycle_count)) #define fp_invc_ptr (offsetof(struct new_dynarec_hot_state, invc_ptr)) #define fp_fcr31 (offsetof(struct new_dynarec_hot_state, cp1_fcr31)) #define fp_regs (offsetof(struct new_dynarec_hot_state, regs)) #define fp_hi (offsetof(struct new_dynarec_hot_state, hi)) #define fp_lo (offsetof(struct new_dynarec_hot_state, lo)) #define fp_cp0_regs(x) ((offsetof(struct new_dynarec_hot_state, cp0_regs)) + (x)*sizeof(uint32_t)) #define fp_rounding_modes (offsetof(struct new_dynarec_hot_state, rounding_modes)) #define fp_fake_pc (offsetof(struct new_dynarec_hot_state, fake_pc)) #define fp_ram_offset (offsetof(struct new_dynarec_hot_state, ram_offset)) #define fp_mini_ht(x,y) ((offsetof(struct new_dynarec_hot_state, mini_ht)) + 4*((y)*32+(x))) #define fp_memory_map (offsetof(struct new_dynarec_hot_state, memory_map)) void jump_vaddr_r0(void); void jump_vaddr_r1(void); void jump_vaddr_r2(void); void jump_vaddr_r3(void); void jump_vaddr_r4(void); void jump_vaddr_r5(void); void jump_vaddr_r6(void); void jump_vaddr_r7(void); void jump_vaddr_r8(void); void jump_vaddr_r9(void); void jump_vaddr_r10(void); void jump_vaddr_r12(void); void invalidate_addr_r0(void); void invalidate_addr_r1(void); void invalidate_addr_r2(void); void invalidate_addr_r3(void); void invalidate_addr_r4(void); void invalidate_addr_r5(void); void invalidate_addr_r6(void); void invalidate_addr_r7(void); void invalidate_addr_r8(void); void invalidate_addr_r9(void); void invalidate_addr_r10(void); void invalidate_addr_r12(void); void breakpoint(void); static void invalidate_addr(u_int addr); static u_int literals[1024][2]; static unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)]; static const u_int jump_vaddr_reg[16] = { (int)jump_vaddr_r0, (int)jump_vaddr_r1, (int)jump_vaddr_r2, (int)jump_vaddr_r3, (int)jump_vaddr_r4, (int)jump_vaddr_r5, (int)jump_vaddr_r6, (int)jump_vaddr_r7, (int)jump_vaddr_r8, (int)jump_vaddr_r9, (int)jump_vaddr_r10, (int)breakpoint, (int)jump_vaddr_r12, (int)breakpoint, (int)breakpoint, (int)breakpoint}; static const u_int invalidate_addr_reg[16] = { (int)invalidate_addr_r0, (int)invalidate_addr_r1, (int)invalidate_addr_r2, (int)invalidate_addr_r3, (int)invalidate_addr_r4, (int)invalidate_addr_r5, (int)invalidate_addr_r6, (int)invalidate_addr_r7, (int)invalidate_addr_r8, (int)invalidate_addr_r9, (int)invalidate_addr_r10, (int)breakpoint, (int)invalidate_addr_r12, (int)breakpoint, (int)breakpoint, (int)breakpoint}; static u_int jump_table_symbols[] = { (int)NULL /*TLBR*/, (int)NULL /*TLBP*/, (int)NULL /*MULT*/, (int)NULL /*MULTU*/, (int)NULL /*DIV*/, (int)NULL /*DIVU*/, (int)NULL /*DMULT*/, (int)NULL /*DMULTU*/, (int)NULL /*DDIV*/, (int)NULL /*DDIVU*/, (int)invalidate_addr, (int)dyna_linker, (int)dyna_linker_ds, (int)verify_code, (int)cc_interrupt, (int)fp_exception, (int)jump_syscall, (int)jump_eret, (int)do_interrupt, (int)TLBWI_new, (int)TLBWR_new, (int)MFC0_new, (int)MTC0_new, (int)jump_vaddr_r0, (int)jump_vaddr_r1, (int)jump_vaddr_r2, (int)jump_vaddr_r3, (int)jump_vaddr_r4, (int)jump_vaddr_r5, (int)jump_vaddr_r6, (int)jump_vaddr_r7, (int)jump_vaddr_r8, (int)jump_vaddr_r9, (int)jump_vaddr_r10, (int)jump_vaddr_r12, (int)invalidate_addr_r0, (int)invalidate_addr_r1, (int)invalidate_addr_r2, (int)invalidate_addr_r3, (int)invalidate_addr_r4, (int)invalidate_addr_r5, (int)invalidate_addr_r6, (int)invalidate_addr_r7, (int)invalidate_addr_r8, (int)invalidate_addr_r9, (int)invalidate_addr_r10, (int)invalidate_addr_r12, (int)cvt_s_w, (int)cvt_d_w, (int)cvt_s_l, (int)cvt_d_l, (int)cvt_w_s, (int)cvt_w_d, (int)cvt_l_s, (int)cvt_l_d, (int)cvt_d_s, (int)cvt_s_d, (int)round_l_s, (int)round_w_s, (int)trunc_l_s, (int)trunc_w_s, (int)ceil_l_s, (int)ceil_w_s, (int)floor_l_s, (int)floor_w_s, (int)round_l_d, (int)round_w_d, (int)trunc_l_d, (int)trunc_w_d, (int)ceil_l_d, (int)ceil_w_d, (int)floor_l_d, (int)floor_w_d, (int)c_f_s, (int)c_un_s, (int)c_eq_s, (int)c_ueq_s, (int)c_olt_s, (int)c_ult_s, (int)c_ole_s, (int)c_ule_s, (int)c_sf_s, (int)c_ngle_s, (int)c_seq_s, (int)c_ngl_s, (int)c_lt_s, (int)c_nge_s, (int)c_le_s, (int)c_ngt_s, (int)c_f_d, (int)c_un_d, (int)c_eq_d, (int)c_ueq_d, (int)c_olt_d, (int)c_ult_d, (int)c_ole_d, (int)c_ule_d, (int)c_sf_d, (int)c_ngle_d, (int)c_seq_d, (int)c_ngl_d, (int)c_lt_d, (int)c_nge_d, (int)c_le_d, (int)c_ngt_d, (int)add_s, (int)sub_s, (int)mul_s, (int)div_s, (int)sqrt_s, (int)abs_s, (int)mov_s, (int)neg_s, (int)add_d, (int)sub_d, (int)mul_d, (int)div_d, (int)sqrt_d, (int)abs_d, (int)mov_d, (int)neg_d, (int)read_byte_new, (int)read_hword_new, (int)read_word_new, (int)read_dword_new, (int)write_byte_new, (int)write_hword_new, (int)write_word_new, (int)write_dword_new, (int)LWL_new, (int)LWR_new, (int)LDL_new, (int)LDR_new, (int)SWL_new, (int)SWR_new, (int)SDL_new, (int)SDR_new, (int)breakpoint }; static void cache_flush(char* start, char* end) { __clear_cache(start, end); } /* Linker */ static void set_jump_target(int addr,u_int target) { u_char *ptr=(u_char *)addr; u_int *ptr2=(u_int *)ptr; if(ptr[3]==0xe2) { assert((target-(u_int)ptr2-8)<1024); assert((addr&3)==0); assert((target&3)==0); *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00; //DebugMessage(M64MSG_VERBOSE, "target=%x addr=%x insn=%x",target,addr,*ptr2); } else if(ptr[3]==0x72) { // generated by emit_jno_unlikely if((target-(u_int)ptr2-8)<1024) { assert((addr&3)==0); assert((target&3)==0); *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>2)|0xF00; } else if((target-(u_int)ptr2-8)<4096&&!((target-(u_int)ptr2-8)&15)) { assert((addr&3)==0); assert((target&3)==0); *ptr2=(*ptr2&0xFFFFF000)|((target-(u_int)ptr2-8)>>4)|0xE00; } else *ptr2=(0x7A000000)|(((target-(u_int)ptr2-8)<<6)>>8); } else { assert((ptr[3]&0x0e)==0xa); *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8); } } // This optionally copies the instruction from the target of the branch into // the space before the branch. Works, but the difference in speed is // usually insignificant. /* static void set_jump_target_fillslot(int addr,u_int target,int copy) { u_char *ptr=(u_char *)addr; u_int *ptr2=(u_int *)ptr; assert(!copy||ptr2[-1]==0xe28dd000); if(ptr[3]==0xe2) { assert(!copy); assert((target-(u_int)ptr2-8)<4096); *ptr2=(*ptr2&0xFFFFF000)|(target-(u_int)ptr2-8); } else { assert((ptr[3]&0x0e)==0xa); u_int target_insn=*(u_int *)target; if((target_insn&0x0e100000)==0) { // ALU, no immediate, no flags copy=0; } if((target_insn&0x0c100000)==0x04100000) { // Load copy=0; } if(target_insn&0x08000000) { copy=0; } if(copy) { ptr2[-1]=target_insn; target+=4; } *ptr2=(*ptr2&0xFF000000)|(((target-(u_int)ptr2-8)<<6)>>8); } } */ /* Literal pool */ static void add_literal(int addr,int val) { literals[literalcount][0]=addr; literals[literalcount][1]=val; literalcount++; } static void *add_pointer(void *src, void* addr) { int *ptr=(int*)src; assert((*ptr&0x0f000000)==0x0a000000); //jmp int offset=(int)(((u_int)*ptr+2)<<8)>>6; void *ptr2=(void*)((u_int)ptr+(u_int)offset); #ifdef ARMv5_ONLY assert((*(int*)((u_int)ptr2)&0x0ff00000)==0x05900000); //ldr assert((*(int*)((u_int)ptr2+4)&0x0ff00000)==0x05900000); //ldr #else assert((*(int*)((u_int)ptr2)&0x0ff00000)==0x03000000); //movw assert((*(int*)((u_int)ptr2+4)&0x0ff00000)==0x03400000); //movt assert((*(int*)((u_int)ptr2+8)&0x0ff00000)==0x03000000); //movw assert((*(int*)((u_int)ptr2+12)&0x0ff00000)==0x03400000); //movt #endif *ptr=(*ptr&0xFF000000)|((((u_int)addr-(u_int)ptr-8)<<6)>>8); cache_flush((void*)ptr, (void*)((u_int)ptr+4)); return ptr2; } static void *kill_pointer(void *stub) { #ifdef ARMv5_ONLY int *ptr=(int *)(stub+4); assert((*ptr&0x0ff00000)==0x05900000); //ldr u_int offset=*ptr&0xfff; int **l_ptr=(void *)ptr+offset+8; int *i_ptr=*l_ptr; #else int *ptr=(int *)((int)stub+8); int *ptr2=(int *)((int)stub+12); assert((*ptr&0x0ff00000)==0x03000000); //movw assert((*ptr2&0x0ff00000)==0x03400000); //movt int *i_ptr=(int*)((*ptr&0xfff)|((*ptr>>4)&0xf000)|((*ptr2&0xfff)<<16)|((*ptr2&0xf0000)<<12)); #endif assert((*i_ptr&0x0f000000)==0x0a000000); //jmp set_jump_target((int)i_ptr,(int)stub); return i_ptr; } static int get_pointer(void *stub) { #ifdef ARMv5_ONLY int *ptr=(int *)(stub+4); assert((*ptr&0x0ff00000)==0x05900000); //ldr u_int offset=*ptr&0xfff; int **l_ptr=(void *)ptr+offset+8; int *i_ptr=*l_ptr; #else int *ptr=(int *)((int)stub+8); int *ptr2=(int *)((int)stub+12); assert((*ptr&0x0ff00000)==0x03000000); //movw assert((*ptr2&0x0ff00000)==0x03400000); //movt int *i_ptr=(int*)((*ptr&0xfff)|((*ptr>>4)&0xf000)|((*ptr2&0xfff)<<16)|((*ptr2&0xf0000)<<12)); #endif assert((*i_ptr&0x0f000000)==0x0a000000); //jmp return (int)i_ptr+((*i_ptr<<8)>>6)+8; } /* Register allocation */ // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). static void alloc_reg(struct regstat *cur,int i,signed char reg) { int r,hr; int preferred_reg = (reg&7); if(reg==CCREG) preferred_reg=HOST_CCREG; if(reg==PTEMP||reg==FTEMP) preferred_reg=12; // Don't allocate unused registers if((cur->u>>reg)&1) return; // see if it's already allocated for(hr=0;hrregmap[hr]==reg) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<uu>>reg)&1) return; // see if the upper half is already allocated for(hr=0;hrregmap[hr]==reg+64) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg|64; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==reg) return; } // Try to allocate any available register for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<uu>>(r&63))&1) { if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hr2) { if(cur->regmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<2) { if(cur->regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[n]==reg) { dirty=(cur->dirty>>n)&1; cur->regmap[n]=-1; } } cur->regmap[hr]=reg; cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<0) { if(imm<256) { *encoded=((i&30)<<7)|imm; return 1; } imm=(imm>>2)|(imm<<30);i-=2; } return 0; } static u_int genjmp(u_int addr) { if(addr<4) return 0; int offset=addr-(int)out-8; if(offset<-33554432||offset>=33554432) { int n; for (n=0;n=-33554432&&offset<33554432); return ((u_int)offset>>2)&0xffffff; } static void emit_mov(int rs,int rt) { assem_debug("mov %s,%s",regname[rt],regname[rs]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)); } static void emit_movs(int rs,int rt) { assem_debug("movs %s,%s",regname[rt],regname[rs]); output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)); } static void emit_add(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0800000|rd_rn_rm(rt,rs1,rs2)); } static void emit_addne(int rs1,int rs2,int rt) { assem_debug("addne %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x12800000|rd_rn_rm(rt,rs1,rs2)); } static void emit_adcsarimm(int rs1,int rs2,int rt,int imm) { assert(imm>0); assert(imm<32); assem_debug("adc %s,%s,%s,ASR#%d",regname[rt],regname[rs1],regname[rs2],imm); output_w32(0xe0a00000|rd_rn_rm(rt,rs1,rs2)|0x40|(imm<<7)); } static void emit_adds(int rs1,int rs2,int rt) { assem_debug("adds %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0900000|rd_rn_rm(rt,rs1,rs2)); } static void emit_adc(int rs1,int rs2,int rt) { assem_debug("adc %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0a00000|rd_rn_rm(rt,rs1,rs2)); } static void emit_adcs(int rs1,int rs2,int rt) { assem_debug("adcs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0b00000|rd_rn_rm(rt,rs1,rs2)); } static void emit_sbc(int rs1,int rs2,int rt) { assem_debug("sbc %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0c00000|rd_rn_rm(rt,rs1,rs2)); } static void emit_sbcs(int rs1,int rs2,int rt) { assem_debug("sbcs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0d00000|rd_rn_rm(rt,rs1,rs2)); } static void emit_neg(int rs, int rt) { assem_debug("rsb %s,%s,#0",regname[rt],regname[rs]); output_w32(0xe2600000|rd_rn_rm(rt,rs,0)); } static void emit_negs(int rs, int rt) { assem_debug("rsbs %s,%s,#0",regname[rt],regname[rs]); output_w32(0xe2700000|rd_rn_rm(rt,rs,0)); } static void emit_sub(int rs1,int rs2,int rt) { assem_debug("sub %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2)); } static void emit_subs(int rs1,int rs2,int rt) { assem_debug("subs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0500000|rd_rn_rm(rt,rs1,rs2)); } static void emit_zeroreg(int rt) { assem_debug("mov %s,#0",regname[rt]); output_w32(0xe3a00000|rd_rn_rm(rt,0,0)); } static void emit_loadlp(u_int imm,u_int rt) { add_literal((int)out,imm); assem_debug("ldr %s,pc+? [=%x]",regname[rt],imm); output_w32(0xe5900000|rd_rn_rm(rt,15,0)); } static void emit_movw(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movw %s,#%d (0x%x)",regname[rt],imm,imm); output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000)); } static void emit_movt(u_int imm,u_int rt) { assem_debug("movt %s,#%d (0x%x)",regname[rt],imm&0xffff0000,imm&0xffff0000); output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000)); } static void emit_movimm(u_int imm,u_int rt) { u_int armval; if(genimm(imm,&armval)) { assem_debug("mov %s,#%d",regname[rt],imm); output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval); }else if(genimm(~imm,&armval)) { assem_debug("mvn %s,#%d",regname[rt],imm); output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval); }else if(imm<65536) { #ifdef ARMv5_ONLY assem_debug("mov %s,#%d",regname[rt],imm&0xFF00); output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8)); assem_debug("add %s,%s,#%d",regname[rt],regname[rt],imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); #else emit_movw(imm,rt); #endif }else{ #ifdef ARMv5_ONLY emit_loadlp(imm,rt); #else emit_movw(imm&0x0000FFFF,rt); emit_movt(imm&0xFFFF0000,rt); #endif } } static void emit_pcreladdr(u_int rt) { assem_debug("add %s,pc,#?",regname[rt]); output_w32(0xe2800000|rd_rn_rm(rt,15,0)); } static void emit_loadreg(int r, int hr) { if((r&63)==0) emit_zeroreg(hr); else if(r==MMREG) emit_movimm(fp_memory_map>>2,hr); else { u_int offset = fp_regs+((r&63)<<3)+((r&64)>>4); if((r&63)==HIREG) offset=fp_hi+((r&64)>>4); if((r&63)==LOREG) offset=fp_lo+((r&64)>>4); if(r==CCREG) offset=fp_cycle_count; if(r==CSREG) offset=fp_cp0_regs(CP0_STATUS_REG); if(r==FSREG) offset=fp_fcr31; if(r==INVCP) offset=fp_invc_ptr; if(r==ROREG) offset=fp_ram_offset; assert(offset<4096); assem_debug("ldr %s,fp+%d",regname[hr],offset); output_w32(0xe5900000|rd_rn_rm(hr,FP,0)|offset); } } static void emit_storereg(int r, int hr) { u_int offset = fp_regs+((r&63)<<3)+((r&64)>>4); if((r&63)==HIREG) offset=fp_hi+((r&64)>>4); if((r&63)==LOREG) offset=fp_lo+((r&64)>>4); if(r==CCREG) offset=fp_cycle_count; if(r==FSREG) offset=fp_fcr31; assert((r&63)!=CSREG); assert((r&63)!=0); assert((r&63)<=CCREG); assert(offset<4096); assem_debug("str %s,fp+%d",regname[hr],offset); output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset); } static void emit_test(int rs, int rt) { assem_debug("tst %s,%s",regname[rs],regname[rt]); output_w32(0xe1100000|rd_rn_rm(0,rs,rt)); } static void emit_testimm(int rs,int imm) { u_int armval, ret; assem_debug("tst %s,#%d",regname[rs],imm); ret = genimm(imm,&armval); assert(ret); output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval); } static void emit_not(int rs,int rt) { assem_debug("mvn %s,%s",regname[rt],regname[rs]); output_w32(0xe1e00000|rd_rn_rm(rt,0,rs)); } static void emit_and(u_int rs1,u_int rs2,u_int rt) { assem_debug("and %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0000000|rd_rn_rm(rt,rs1,rs2)); } static void emit_or(u_int rs1,u_int rs2,u_int rt) { assem_debug("orr %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe1800000|rd_rn_rm(rt,rs1,rs2)); } static void emit_or_and_set_flags(int rs1,int rs2,int rt) { assem_debug("orrs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe1900000|rd_rn_rm(rt,rs1,rs2)); } static void emit_xor(u_int rs1,u_int rs2,u_int rt) { assem_debug("eor %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2)); } static void emit_addimm(u_int rs,int imm,u_int rt) { assert(rs<16); assert(rt<16); if(imm!=0) { assert(imm>-65536&&imm<65536); u_int armval; if(genimm(imm,&armval)) { assem_debug("add %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval); }else if(genimm(-imm,&armval)) { assem_debug("sub %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval); }else if(imm<0) { assem_debug("sub %s,%s,#%d",regname[rt],regname[rs],(-imm)&0xFF00); assem_debug("sub %s,%s,#%d",regname[rt],regname[rt],(-imm)&0xFF); output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8)); output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); }else{ assem_debug("add %s,%s,#%d",regname[rt],regname[rs],imm&0xFF00); assem_debug("add %s,%s,#%d",regname[rt],regname[rt],imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } else if(rs!=rt) emit_mov(rs,rt); } static void emit_addimm_and_set_flags(int imm,int rt) { assert(imm>-65536&&imm<65536); u_int armval; if(genimm(imm,&armval)) { assem_debug("adds %s,%s,#%d",regname[rt],regname[rt],imm); output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval); }else if(genimm(-imm,&armval)) { assem_debug("subs %s,%s,#%d",regname[rt],regname[rt],imm); output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval); }else if(imm<0) { assem_debug("sub %s,%s,#%d",regname[rt],regname[rt],(-imm)&0xFF00); assem_debug("subs %s,%s,#%d",regname[rt],regname[rt],(-imm)&0xFF); output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8)); output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); }else{ assem_debug("add %s,%s,#%d",regname[rt],regname[rt],imm&0xFF00); assem_debug("adds %s,%s,#%d",regname[rt],regname[rt],imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8)); output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } #ifndef RAM_OFFSET static void emit_addimm_no_flags(u_int imm,u_int rt) { emit_addimm(rt,imm,rt); } #endif static void emit_addnop(u_int r) { assert(r<16); assem_debug("add %s,%s,#0 (nop)",regname[r],regname[r]); output_w32(0xe2800000|rd_rn_rm(r,r,0)); } static void emit_adcimm(u_int rs,int imm,u_int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("adc %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2a00000|rd_rn_rm(rt,rs,0)|armval); } static void emit_sbcimm(u_int rs,int imm,u_int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("sbc %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2c00000|rd_rn_rm(rt,rs,0)|armval); } static void emit_rscimm(int rs,int imm,u_int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("rsc %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2e00000|rd_rn_rm(rt,rs,0)|armval); } static void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) { u_int armval; if(imm>0&&genimm(imm,&armval)) { assem_debug("adds %s,%s,#%d",regname[rtl],regname[rsl],imm); output_w32(0xe2900000|rd_rn_rm(rtl,rsl,0)|armval); emit_adcimm(rsh,0,rth); }else if(imm<0&&genimm(-imm,&armval)) { assem_debug("subs %s,%s,#%d",regname[rtl],regname[rsl],imm); output_w32(0xe2500000|rd_rn_rm(rtl,rsl,0)|armval); emit_sbcimm(rsh,0,rth); }else if(imm<0) { assert(rsl!=HOST_TEMPREG); emit_movimm(-imm,HOST_TEMPREG); emit_subs(rsl,HOST_TEMPREG,rtl); emit_sbcimm(rsh,0,rth); }else if(imm>0) { assert(rsl!=HOST_TEMPREG); emit_movimm(imm,HOST_TEMPREG); emit_adds(rsl,HOST_TEMPREG,rtl); emit_adcimm(rsh,0,rth); } else { assert(imm==0); if(rsl!=rtl) { assert(rsh!=rth); emit_mov(rsl,rtl); emit_mov(rsh,rth); } } } #ifdef INVERTED_CARRY static void emit_sbb(int rs1,int rs2) { assem_debug("sbb %%%s,%%%s",regname[rs2],regname[rs1]); output_byte(0x19); output_modrm(3,rs1,rs2); } #endif static void emit_andimm(int rs,int imm,int rt) { u_int armval; if(imm==0) { emit_zeroreg(rt); }else if(genimm(imm,&armval)) { assem_debug("and %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval); }else if(genimm(~imm,&armval)) { assem_debug("bic %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval); }else if(imm==65535) { #ifdef ARMv5_ONLY assem_debug("bic %s,%s,#FF000000",regname[rt],regname[rs]); output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF); assem_debug("bic %s,%s,#00FF0000",regname[rt],regname[rt]); output_w32(0xe3c00000|rd_rn_rm(rt,rt,0)|0x8FF); #else assem_debug("uxth %s,%s",regname[rt],regname[rs]); output_w32(0xe6ff0070|rd_rn_rm(rt,0,rs)); #endif }else{ assert(rs!=HOST_TEMPREG); assert(imm>0&&imm<65535); #ifdef ARMv5_ONLY assem_debug("mov r14,#%d",imm&0xFF00); output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8)); assem_debug("add r14,r14,#%d",imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(HOST_TEMPREG,HOST_TEMPREG,imm&0xff,0)); #else emit_movw(imm,HOST_TEMPREG); #endif assem_debug("and %s,%s,r14",regname[rt],regname[rs]); output_w32(0xe0000000|rd_rn_rm(rt,rs,HOST_TEMPREG)); } } static void emit_orimm(int rs,int imm,int rt) { u_int armval; if(imm==0) { if(rs!=rt) emit_mov(rs,rt); }else if(genimm(imm,&armval)) { assem_debug("orr %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(imm>0&&imm<65536); assem_debug("orr %s,%s,#%d",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } static void emit_xorimm(int rs,int imm,int rt) { u_int armval; if(imm==0) { if(rs!=rt) emit_mov(rs,rt); }else if(genimm(imm,&armval)) { assem_debug("eor %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(imm>0&&imm<65536); assem_debug("eor %s,%s,#%d",regname[rt],regname[rs],imm&0xFF00); assem_debug("eor %s,%s,#%d",regname[rt],regname[rs],imm&0xFF); output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe2200000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } static void emit_shlimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); //if(imm==1) ... assem_debug("lsl %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7)); } static void emit_shrimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("lsr %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); } static void emit_sarimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("asr %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7)); } static void emit_rorimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("ror %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7)); } static void emit_shldimm(int rs,int rs2,u_int imm,int rt) { assem_debug("shld %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); assert(imm<32); //if(imm==1) ... assem_debug("lsl %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7)); assem_debug("orr %s,%s,%s,lsr #%d",regname[rt],regname[rt],regname[rs2],32-imm); output_w32(0xe1800020|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7)); } static void emit_shrdimm(int rs,int rs2,u_int imm,int rt) { assem_debug("shrd %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); assert(imm<32); //if(imm==1) ... assem_debug("lsr %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe1a00020|rd_rn_rm(rt,0,rs)|(imm<<7)); assem_debug("orr %s,%s,%s,lsl #%d",regname[rt],regname[rt],regname[rs2],32-imm); output_w32(0xe1800000|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7)); } static void emit_shl(u_int rs,u_int shift,u_int rt) { assert(rs<16); assert(rt<16); assert(shift<16); //if(imm==1) ... assem_debug("lsl %s,%s,%s",regname[rt],regname[rs],regname[shift]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x10|(shift<<8)); } static void emit_shr(u_int rs,u_int shift,u_int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("lsr %s,%s,%s",regname[rt],regname[rs],regname[shift]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x30|(shift<<8)); } static void emit_sar(u_int rs,u_int shift,u_int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("asr %s,%s,%s",regname[rt],regname[rs],regname[shift]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8)); } static void emit_orrshl(u_int rs,u_int shift,u_int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("orr %s,%s,%s,lsl %s",regname[rt],regname[rt],regname[rs],regname[shift]); output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8)); } static void emit_orrshr(u_int rs,u_int shift,u_int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("orr %s,%s,%s,lsr %s",regname[rt],regname[rt],regname[rs],regname[shift]); output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x30|(shift<<8)); } static void emit_cmpimm(int rs,int imm) { u_int armval; if(genimm(imm,&armval)) { assem_debug("cmp %s,#%d",regname[rs],imm); output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval); }else if(genimm(-imm,&armval)) { assem_debug("cmn %s,#%d",regname[rs],imm); output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval); }else if(imm>0) { assert(rs!=HOST_TEMPREG); assert(imm<65536); #ifdef ARMv5_ONLY emit_movimm(imm,HOST_TEMPREG); #else emit_movw(imm,HOST_TEMPREG); #endif assem_debug("cmp %s,r14",regname[rs]); output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG)); }else{ assert(rs!=HOST_TEMPREG); assert(imm>-65536); #ifdef ARMv5_ONLY emit_movimm(-imm,HOST_TEMPREG); #else emit_movw(-imm,HOST_TEMPREG); #endif assem_debug("cmn %s,r14",regname[rs]); output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG)); } } static void emit_cmovne_imm(int imm,int rt) { assem_debug("movne %s,#%d",regname[rt],imm); u_int armval, ret; ret = genimm(imm,&armval); assert(ret); output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval); } static void emit_cmovl_imm(int imm,int rt) { assem_debug("movlt %s,#%d",regname[rt],imm); u_int armval, ret; ret = genimm(imm,&armval); assert(ret); output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval); } static void emit_cmovb_imm(int imm,int rt) { assem_debug("movcc %s,#%d",regname[rt],imm); u_int armval, ret; ret = genimm(imm,&armval); assert(ret); output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval); } static void emit_cmovs_imm(int imm,int rt) { assem_debug("movmi %s,#%d",regname[rt],imm); u_int armval, ret; ret = genimm(imm,&armval); assert(ret); output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval); } static void emit_cmove_reg(int rs,int rt) { assem_debug("moveq %s,%s",regname[rt],regname[rs]); output_w32(0x01a00000|rd_rn_rm(rt,0,rs)); } static void emit_cmovne_reg(int rs,int rt) { assem_debug("movne %s,%s",regname[rt],regname[rs]); output_w32(0x11a00000|rd_rn_rm(rt,0,rs)); } static void emit_cmovl_reg(int rs,int rt) { assem_debug("movlt %s,%s",regname[rt],regname[rs]); output_w32(0xb1a00000|rd_rn_rm(rt,0,rs)); } static void emit_cmovs_reg(int rs,int rt) { assem_debug("movmi %s,%s",regname[rt],regname[rs]); output_w32(0x41a00000|rd_rn_rm(rt,0,rs)); } static void emit_slti32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_cmovl_imm(1,rt); } static void emit_sltiu32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_cmovb_imm(1,rt); } static void emit_slti64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_slti32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne_imm(0,rt); emit_cmovs_imm(1,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne_imm(0,rt); emit_cmovl_imm(1,rt); } } static void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_sltiu32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne_imm(0,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne_imm(1,rt); } } static void emit_cmp(int rs,int rt) { assem_debug("cmp %s,%s",regname[rs],regname[rt]); output_w32(0xe1500000|rd_rn_rm(0,rs,rt)); } static void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_cmovl_imm(0,rt); } static void emit_set_nz32(int rs, int rt) { //assem_debug("set_nz32"); if(rs!=rt) emit_movs(rs,rt); else emit_test(rs,rs); emit_cmovne_imm(1,rt); } static void emit_set_gz64_32(int rsh, int rsl, int rt) { //assem_debug("set_gz64"); emit_set_gz32(rsl,rt); emit_test(rsh,rsh); emit_cmovne_imm(1,rt); emit_cmovs_imm(0,rt); } static void emit_set_nz64_32(int rsh, int rsl, int rt) { //assem_debug("set_nz64"); emit_or_and_set_flags(rsh,rsl,rt); emit_cmovne_imm(1,rt); } static void emit_set_if_less32(int rs1, int rs2, int rt) { //assem_debug("set if less (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovl_imm(1,rt); } static void emit_set_if_carry32(int rs1, int rs2, int rt) { //assem_debug("set if carry (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovb_imm(1,rt); } static void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_movimm(0,rt); emit_sbcs(u1,u2,HOST_TEMPREG); emit_cmovl_imm(1,rt); } static void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_movimm(0,rt); emit_sbcs(u1,u2,HOST_TEMPREG); emit_cmovb_imm(1,rt); } static void emit_call(int a) { assem_debug("bl %x (%x+%x)",a,(int)out,a-(int)out-8); u_int offset=genjmp(a); output_w32(0xeb000000|offset); } static void emit_jmp(int a) { assem_debug("b %x (%x+%x)",a,(int)out,a-(int)out-8); u_int offset=genjmp(a); output_w32(0xea000000|offset); } static void emit_jne(int a) { assem_debug("bne %x",a); u_int offset=genjmp(a); output_w32(0x1a000000|offset); } static void emit_jeq(int a) { assem_debug("beq %x",a); u_int offset=genjmp(a); output_w32(0x0a000000|offset); } static void emit_js(int a) { assem_debug("bmi %x",a); u_int offset=genjmp(a); output_w32(0x4a000000|offset); } static void emit_jns(int a) { assem_debug("bpl %x",a); u_int offset=genjmp(a); output_w32(0x5a000000|offset); } static void emit_jl(int a) { assem_debug("blt %x",a); u_int offset=genjmp(a); output_w32(0xba000000|offset); } static void emit_jge(int a) { assem_debug("bge %x",a); u_int offset=genjmp(a); output_w32(0xaa000000|offset); } static void emit_jno(int a) { assem_debug("bvc %x",a); u_int offset=genjmp(a); output_w32(0x7a000000|offset); } static void emit_jcc(int a) { assem_debug("bcc %x",a); u_int offset=genjmp(a); output_w32(0x3a000000|offset); } static void emit_jae(int a) { assem_debug("bcs %x",a); u_int offset=genjmp(a); output_w32(0x2a000000|offset); } static void emit_jb(int a) { assem_debug("bcc %x",a); u_int offset=genjmp(a); output_w32(0x3a000000|offset); } static void emit_pushreg(u_int r) { assem_debug("push %%%s",regname[r]); assert(0); } static void emit_popreg(u_int r) { assem_debug("pop %%%s",regname[r]); assert(0); } /* static void emit_callreg(u_int r) { assem_debug("call *%%%s",regname[r]); assert(0); }*/ static void emit_jmpreg(u_int r) { assem_debug("mov pc,%s",regname[r]); output_w32(0xe1a00000|rd_rn_rm(15,0,r)); } static void emit_readword_indexed(int offset, int rs, int rt) { assert(offset>-4096&&offset<4096); assem_debug("ldr %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5900000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5100000|rd_rn_rm(rt,rs,0)|(-offset)); } } static void emit_readword_dualindexedx4(int rs1, int rs2, int rt) { assem_debug("ldr %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100); } static void emit_readword_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_readword_indexed(addr, rs, rt); else { assert(addr==0); emit_readword_dualindexedx4(rs, map, rt); } } static void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl) { if(map<0) { if(rh>=0) emit_readword_indexed(addr, rs, rh); emit_readword_indexed(addr+4, rs, rl); }else{ assert(rh!=rs); if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh); emit_addimm(map,1,HOST_TEMPREG); emit_readword_indexed_tlb(addr, rs, HOST_TEMPREG, rl); } } static void emit_movsbl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldrsb %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1d000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe15000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } static void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movsbl_indexed(addr, rs, rt); else { if(addr==0) { emit_shlimm(map,2,HOST_TEMPREG); assem_debug("ldrsb %s,%s+%s",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0xe19000d0|rd_rn_rm(rt,rs,HOST_TEMPREG)); }else{ assert(addr>-256&&addr<256); assem_debug("add %s,%s,%s,lsl #2",regname[rt],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7)); emit_movsbl_indexed(addr, rt, rt); } } } static void emit_movswl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldrsh %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1d000f0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe15000f0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } static void emit_movswl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movswl_indexed(addr,rs,rt); else { if(addr==0) { emit_shlimm(map,2,HOST_TEMPREG); assem_debug("ldrsh %s,%s+%s",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0xe19000f0|rd_rn_rm(rt,rs,HOST_TEMPREG)); }else{ assert(addr>-256&&addr<256); assem_debug("add %s,%s,%s,lsl #2",regname[rt],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7)); emit_movswl_indexed(addr, rt, rt); } } } static void emit_movzbl_indexed(int offset, int rs, int rt) { assert(offset>-4096&&offset<4096); assem_debug("ldrb %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5d00000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5500000|rd_rn_rm(rt,rs,0)|(-offset)); } } static void emit_movzbl_dualindexedx4(int rs1, int rs2, int rt) { assem_debug("ldrb %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7d00000|rd_rn_rm(rt,rs1,rs2)|0x100); } static void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movzbl_indexed(addr, rs, rt); else { if(addr==0) { emit_movzbl_dualindexedx4(rs, map, rt); }else{ emit_addimm(rs,addr,rt); emit_movzbl_dualindexedx4(rt, map, rt); } } } static void emit_movzwl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldrh %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1d000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } static void emit_movzwl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movzwl_indexed(addr,rs,rt); else { if(addr==0) { emit_shlimm(map,2,HOST_TEMPREG); assem_debug("ldrh %s,%s+%s",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0xe19000b0|rd_rn_rm(rt,rs,HOST_TEMPREG)); }else{ assert(addr>-256&&addr<256); assem_debug("add %s,%s,%s,lsl #2",regname[rt],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7)); emit_movzwl_indexed(addr, rt, rt); } } } static void emit_readword(int addr, int rt) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<4096); assem_debug("ldr %s,fp+%d",regname[rt],offset); output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset); } static void emit_readptr(int addr, int rt) { emit_readword(addr,rt); } static void emit_movsbl(int addr, int rt) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<256); assem_debug("ldrsb %s,fp+%d",regname[rt],offset); output_w32(0xe1d000d0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } static void emit_movswl(int addr, int rt) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<256); assem_debug("ldrsh %s,fp+%d",regname[rt],offset); output_w32(0xe1d000f0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } static void emit_movzbl(int addr, int rt) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<4096); assem_debug("ldrb %s,fp+%d",regname[rt],offset); output_w32(0xe5d00000|rd_rn_rm(rt,FP,0)|offset); } static void emit_movzwl(int addr, int rt) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<256); assem_debug("ldrh %s,fp+%d",regname[rt],offset); output_w32(0xe1d000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } /* static void emit_movzwl_reg(int rs, int rt) { assem_debug("movzwl %%%s,%%%s",regname[rs]+1,regname[rt]); assert(0); } */ static void emit_writeword_indexed(int rt, int offset, int rs) { assert(offset>-4096&&offset<4096); assem_debug("str %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5800000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5000000|rd_rn_rm(rt,rs,0)|(-offset)); } } static void emit_writeword_dualindexedx4(int rt, int rs1, int rs2) { assem_debug("str %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7800000|rd_rn_rm(rt,rs1,rs2)|0x100); } static void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writeword_indexed(rt, addr, rs); else { if(addr==0) { emit_writeword_dualindexedx4(rt, rs, map); }else{ assem_debug("add %s,%s,%s,lsl #2",regname[HOST_TEMPREG],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(HOST_TEMPREG,rs,map)|(2<<7)); emit_writeword_indexed(rt,addr,HOST_TEMPREG); } } } static void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map) { //emit_writeword_indexed_tlb modifies HOST_TEMPREG when addr!=0 if(map==HOST_TEMPREG) assert(addr==0); assert(rh>=0); emit_writeword_indexed_tlb(rh, addr, rs, map); emit_writeword_indexed_tlb(rl, addr+4, rs, map); } static void emit_writehword_indexed(int rt, int offset, int rs) { assert(offset>-256&&offset<256); assem_debug("strh %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1c000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe14000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } static void emit_writehword_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writehword_indexed(rt, addr, rs); else { assem_debug("add %s,%s,%s,lsl #2",regname[HOST_TEMPREG],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(HOST_TEMPREG,rs,map)|(2<<7)); emit_writehword_indexed(rt,addr,HOST_TEMPREG); } } static void emit_writebyte_indexed(int rt, int offset, int rs) { assert(offset>-4096&&offset<4096); assem_debug("strb %s,%s+%d",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5c00000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5400000|rd_rn_rm(rt,rs,0)|(-offset)); } } static void emit_writebyte_dualindexedx4(int rt, int rs1, int rs2) { assem_debug("strb %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7c00000|rd_rn_rm(rt,rs1,rs2)|0x100); } static void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writebyte_indexed(rt, addr, rs); else { if(addr==0) { emit_writebyte_dualindexedx4(rt, rs, map); }else{ assem_debug("add %s,%s,%s,lsl #2",regname[HOST_TEMPREG],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(HOST_TEMPREG,rs,map)|(2<<7)); emit_writebyte_indexed(rt,addr,HOST_TEMPREG); } } } static void emit_writeword(int rt, int addr) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<4096); assem_debug("str %s,fp+%d",regname[rt],offset); output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset); } static void emit_writehword(int rt, int addr) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<256); assem_debug("strh %s,fp+%d",regname[rt],offset); output_w32(0xe1c000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } static void emit_writebyte(int rt, int addr) { u_int offset = addr-(u_int)&g_dev.r4300.new_dynarec_hot_state; assert(offset<4096); assem_debug("strb %s,fp+%d",regname[rt],offset); output_w32(0xe5c00000|rd_rn_rm(rt,FP,0)|offset); } static void emit_mul(u_int rs1,u_int rs2,u_int rt) { assem_debug("mul %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0000090|(rt<<16)|(rs2<<8)|rs1); } static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo) { assem_debug("umull %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); assert(rs1<16); assert(rs2<16); assert(hi<16); assert(lo<16); output_w32(0xe0800090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); } static void emit_umlal(u_int rs1, u_int rs2, u_int hi, u_int lo) { assem_debug("umlal %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); assert(rs1<16); assert(rs2<16); assert(hi<16); assert(lo<16); output_w32(0xe0a00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); } static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo) { assem_debug("smull %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); assert(rs1<16); assert(rs2<16); assert(hi<16); assert(lo<16); output_w32(0xe0c00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); } static void emit_smlal(u_int rs1, u_int rs2, u_int hi, u_int lo) { assem_debug("smlal %s, %s, %s, %s",regname[lo],regname[hi],regname[rs1],regname[rs2]); assert(rs1<16); assert(rs2<16); assert(hi<16); assert(lo<16); output_w32(0xe0e00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); } static void emit_sdiv(u_int rs1,u_int rs2,u_int rt) { assert(arm_cpu_features.IDIVa); assem_debug("sdiv %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe710f010|(rt<<16)|(rs2<<8)|rs1); } static void emit_udiv(u_int rs1,u_int rs2,u_int rt) { assert(arm_cpu_features.IDIVa); assem_debug("udiv %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe730f010|(rt<<16)|(rs2<<8)|rs1); } static void emit_clz(int rs,int rt) { assem_debug("clz %s,%s",regname[rt],regname[rs]); output_w32(0xe16f0f10|rd_rn_rm(rt,0,rs)); } static void emit_subcs(int rs1,int rs2,int rt) { assem_debug("subcs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x20400000|rd_rn_rm(rt,rs1,rs2)); } static void emit_shrcc_imm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("lsrcc %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); } static void emit_negmi(int rs, int rt) { assem_debug("rsbmi %s,%s,#0",regname[rt],regname[rs]); output_w32(0x42600000|rd_rn_rm(rt,rs,0)); } static void emit_orreq(u_int rs1,u_int rs2,u_int rt) { assem_debug("orreq %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x01800000|rd_rn_rm(rt,rs1,rs2)); } static void emit_orrne(u_int rs1,u_int rs2,u_int rt) { assem_debug("orrne %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x11800000|rd_rn_rm(rt,rs1,rs2)); } static void emit_bic_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt) { assem_debug("bic %s,%s,%s lsl %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); } static void emit_biceq_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt) { assem_debug("biceq %s,%s,%s lsl %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); } static void emit_bicne_lsl(u_int rs1,u_int rs2,u_int shift,u_int rt) { assem_debug("bicne %s,%s,%s lsl %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); } static void emit_bic_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt) { assem_debug("bic %s,%s,%s lsr %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); } static void emit_biceq_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt) { assem_debug("biceq %s,%s,%s lsr %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); } static void emit_bicne_lsr(u_int rs1,u_int rs2,u_int shift,u_int rt) { assem_debug("bicne %s,%s,%s lsr %s",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); } static void emit_teq(int rs, int rt) { assem_debug("teq %s,%s",regname[rs],regname[rt]); output_w32(0xe1300000|rd_rn_rm(0,rs,rt)); } static void emit_rsbimm(int rs, int imm, int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("rsb %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval); } // Load 2 immediates optimizing for small code size static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2) { emit_movimm(imm1,rt1); u_int armval; if(genimm(imm2-imm1,&armval)) { assem_debug("add %s,%s,#%d",regname[rt2],regname[rt1],imm2-imm1); output_w32(0xe2800000|rd_rn_rm(rt2,rt1,0)|armval); }else if(genimm(imm1-imm2,&armval)) { assem_debug("sub %s,%s,#%d",regname[rt2],regname[rt1],imm1-imm2); output_w32(0xe2400000|rd_rn_rm(rt2,rt1,0)|armval); } else emit_movimm(imm2,rt2); } // Conditionally select one of two immediates, optimizing for small code size // This will only be called if HAVE_CMOV_IMM is defined static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt) { u_int armval; if(genimm(imm2-imm1,&armval)) { emit_movimm(imm1,rt); assem_debug("addne %s,%s,#%d",regname[rt],regname[rt],imm2-imm1); output_w32(0x12800000|rd_rn_rm(rt,rt,0)|armval); }else if(genimm(imm1-imm2,&armval)) { emit_movimm(imm1,rt); assem_debug("subne %s,%s,#%d",regname[rt],regname[rt],imm1-imm2); output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval); } else { #ifdef ARMv5_ONLY emit_movimm(imm1,rt); add_literal((int)out,imm2); assem_debug("ldrne %s,pc+? [=%x]",regname[rt],imm2); output_w32(0x15900000|rd_rn_rm(rt,15,0)); #else emit_movw(imm1&0x0000FFFF,rt); if((imm1&0xFFFF)!=(imm2&0xFFFF)) { assem_debug("movwne %s,#%d (0x%x)",regname[rt],imm2&0xFFFF,imm2&0xFFFF); output_w32(0x13000000|rd_rn_rm(rt,0,0)|(imm2&0xfff)|((imm2<<4)&0xf0000)); } emit_movt(imm1&0xFFFF0000,rt); if((imm1&0xFFFF0000)!=(imm2&0xFFFF0000)) { assem_debug("movtne %s,#%d (0x%x)",regname[rt],imm2&0xffff0000,imm2&0xffff0000); output_w32(0x13400000|rd_rn_rm(rt,0,0)|((imm2>>16)&0xfff)|((imm2>>12)&0xf0000)); } #endif } } // special case for checking pending_exception static void emit_cmpmem_imm(int addr, int imm) { assert(imm==0); emit_readword(addr,HOST_TEMPREG); emit_test(HOST_TEMPREG,HOST_TEMPREG); } #if !defined(HOST_IMM8) // special case for checking invalid_code static void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) { assert(0); } #endif // special case for checking invalid_code static void emit_cmpmem_indexedsr12_reg(int base,int r,int imm) { assert(imm<128&&imm>=0); assert(r>=0&&r<16); assem_debug("ldrb lr,%s,%s lsr #12",regname[base],regname[r]); output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620); emit_cmpimm(HOST_TEMPREG,imm); } // special case for tlb mapping static void emit_addsr12(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s lsr #12",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0800620|rd_rn_rm(rt,rs1,rs2)); } static void emit_addsl2(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s lsl #2",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0800100|rd_rn_rm(rt,rs1,rs2)); } static void emit_callne(int a) { assem_debug("blne %x",a); u_int offset=genjmp(a); output_w32(0x1b000000|offset); } #ifdef IMM_PREFETCH // Used to preload hash table entries static void emit_prefetch(void *addr) { assem_debug("prefetch %x",(int)addr); output_byte(0x0F); output_byte(0x18); output_modrm(0,5,1); output_w32((int)addr); } #endif #ifdef REG_PREFETCH static void emit_prefetchreg(int r) { assem_debug("pld %s",regname[r]); output_w32(0xf5d0f000|rd_rn_rm(0,r,0)); } #endif // Special case for mini_ht static void emit_ldreq_indexed(int rs, u_int offset, int rt) { assert(offset<4096); assem_debug("ldreq %s,[%s, #%d]",regname[rt],regname[rs],offset); output_w32(0x05900000|rd_rn_rm(rt,rs,0)|offset); } static void emit_flds(int r,int sr) { assem_debug("flds s%d,[%s]",sr,regname[r]); output_w32(0xed900a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16)); } static void emit_vldr(int r,int vr) { assem_debug("vldr d%d,[%s]",vr,regname[r]); output_w32(0xed900b00|(vr<<12)|(r<<16)); } static void emit_fsts(int sr,int r) { assem_debug("fsts s%d,[%s]",sr,regname[r]); output_w32(0xed800a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16)); } static void emit_vstr(int vr,int r) { assem_debug("vstr d%d,[%s]",vr,regname[r]); output_w32(0xed800b00|(vr<<12)|(r<<16)); } static void emit_ftosizs(int s,int d) { assem_debug("ftosizs s%d,s%d",d,s); output_w32(0xeebd0ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } static void emit_ftosizd(int s,int d) { assem_debug("ftosizd s%d,d%d",d,s); output_w32(0xeebd0bc0|((d&14)<<11)|((d&1)<<22)|(s&7)); } static void emit_fsitos(int s,int d) { assem_debug("fsitos s%d,s%d",d,s); output_w32(0xeeb80ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } static void emit_fsitod(int s,int d) { assem_debug("fsitod d%d,s%d",d,s); output_w32(0xeeb80bc0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5)); } static void emit_fcvtds(int s,int d) { assem_debug("fcvtds d%d,s%d",d,s); output_w32(0xeeb70ac0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5)); } static void emit_fcvtsd(int s,int d) { assem_debug("fcvtsd s%d,d%d",d,s); output_w32(0xeeb70bc0|((d&14)<<11)|((d&1)<<22)|(s&7)); } static void emit_fsqrts(int s,int d) { assem_debug("fsqrts d%d,s%d",d,s); output_w32(0xeeb10ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } static void emit_fsqrtd(int s,int d) { assem_debug("fsqrtd s%d,d%d",d,s); output_w32(0xeeb10bc0|((d&7)<<12)|(s&7)); } static void emit_fabss(int s,int d) { assem_debug("fabss d%d,s%d",d,s); output_w32(0xeeb00ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } static void emit_fabsd(int s,int d) { assem_debug("fabsd s%d,d%d",d,s); output_w32(0xeeb00bc0|((d&7)<<12)|(s&7)); } static void emit_fnegs(int s,int d) { assem_debug("fnegs d%d,s%d",d,s); output_w32(0xeeb10a40|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } static void emit_fnegd(int s,int d) { assem_debug("fnegd s%d,d%d",d,s); output_w32(0xeeb10b40|((d&7)<<12)|(s&7)); } static void emit_fadds(int s1,int s2,int d) { assem_debug("fadds s%d,s%d,s%d",d,s1,s2); output_w32(0xee300a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } static void emit_faddd(int s1,int s2,int d) { assem_debug("faddd d%d,d%d,d%d",d,s1,s2); output_w32(0xee300b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } static void emit_fsubs(int s1,int s2,int d) { assem_debug("fsubs s%d,s%d,s%d",d,s1,s2); output_w32(0xee300a40|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } static void emit_fsubd(int s1,int s2,int d) { assem_debug("fsubd d%d,d%d,d%d",d,s1,s2); output_w32(0xee300b40|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } static void emit_fmuls(int s1,int s2,int d) { assem_debug("fmuls s%d,s%d,s%d",d,s1,s2); output_w32(0xee200a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } static void emit_fmuld(int s1,int s2,int d) { assem_debug("fmuld d%d,d%d,d%d",d,s1,s2); output_w32(0xee200b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } static void emit_fdivs(int s1,int s2,int d) { assem_debug("fdivs s%d,s%d,s%d",d,s1,s2); output_w32(0xee800a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } static void emit_fdivd(int s1,int s2,int d) { assem_debug("fdivd d%d,d%d,d%d",d,s1,s2); output_w32(0xee800b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } static void emit_fcmps(int x,int y) { assem_debug("fcmps s14, s15"); output_w32(0xeeb47a67); } static void emit_fcmpd(int x,int y) { assem_debug("fcmpd d6, d7"); output_w32(0xeeb46b47); } static void emit_fmstat(void) { assem_debug("fmstat"); output_w32(0xeef1fa10); } static void emit_bicne_imm(int rs,int imm,int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("bicne %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x13c00000|rd_rn_rm(rt,rs,0)|armval); } static void emit_biccs_imm(int rs,int imm,int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("biccs %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x23c00000|rd_rn_rm(rt,rs,0)|armval); } static void emit_bicvc_imm(int rs,int imm,int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("bicvc %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x73c00000|rd_rn_rm(rt,rs,0)|armval); } static void emit_bichi_imm(int rs,int imm,int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("bichi %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x83c00000|rd_rn_rm(rt,rs,0)|armval); } static void emit_orrvs_imm(int rs,int imm,int rt) { u_int armval, ret; ret = genimm(imm,&armval); assert(ret); assem_debug("orrvs %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x63800000|rd_rn_rm(rt,rs,0)|armval); } static void emit_jno_unlikely(int a) { //emit_jno(a); assem_debug("addvc pc,pc,#? (%x)",/*a-(int)out-8,*/a); output_w32(0x72800000|rd_rn_rm(15,15,0)); } // Save registers before function call static void save_regs(u_int reglist) { reglist&=CALLER_SAVED_REGS; // only save the caller-save registers, r0-r3, r12 if(!reglist) return; assem_debug("stmia fp,{"); if(reglist&1) assem_debug("r0, "); if(reglist&2) assem_debug("r1, "); if(reglist&4) assem_debug("r2, "); if(reglist&8) assem_debug("r3, "); if(reglist&0x1000) assem_debug("r12"); assem_debug("}"); output_w32(0xe88b0000|reglist); } // Restore registers after function call static void restore_regs(u_int reglist) { reglist&=CALLER_SAVED_REGS; // only restore the caller-save registers, r0-r3, r12 if(!reglist) return; assem_debug("ldmia fp,{"); if(reglist&1) assem_debug("r0, "); if(reglist&2) assem_debug("r1, "); if(reglist&4) assem_debug("r2, "); if(reglist&8) assem_debug("r3, "); if(reglist&0x1000) assem_debug("r12"); assem_debug("}"); output_w32(0xe89b0000|reglist); } /* Stubs/epilogue */ static void literal_pool(int n) { if(!literalcount) return; if(n) { if((int)out-literals[0][0]<4096-n) return; } u_int *ptr; int i; for(i=0;ivaddr); #ifdef ARMv5_ONLY emit_loadlp((int)head,ARG1_REG); #else emit_movw(((u_int)head)&0x0000FFFF,ARG1_REG); emit_movt(((u_int)head)&0xFFFF0000,ARG1_REG); #endif emit_call((int)&verify_code); int entry=(int)out; load_regs_entry(i); if(entry==(int)out) entry=instr_addr[i]; emit_jmp(instr_addr[i]); return entry; } static void do_dirty_stub_ds(struct ll_entry * head) { assem_debug("do_dirty_stub_ds %x",head->vaddr); #ifdef ARMv5_ONLY emit_loadlp((int)head,ARG1_REG); #else emit_movw(((u_int)head)&0x0000FFFF,ARG1_REG); emit_movt(((u_int)head)&0xFFFF0000,ARG1_REG); #endif emit_call((int)&verify_code); } /* TLB */ static int do_tlb_r(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { if((signed int)addr>=(signed int)0xC0000000) { // address_generation already loaded the const emit_readword_dualindexedx4(FP,map,map); } else return -1; // No mapping } else { assert(s!=map); if(cache>=0) { // Use cached offset to memory map emit_addsr12(cache,s,map); }else{ emit_movimm(fp_memory_map>>2,map); emit_addsr12(map,s,map); } // Schedule this while we wait on the load //if(x) emit_xorimm(s,x,ar); emit_readword_dualindexedx4(FP,map,map); } return map; } static int do_tlb_r_branch(int map, int c, u_int addr, int *jaddr) { if(!c||(signed int)addr>=(signed int)0xC0000000) { emit_test(map,map); *jaddr=(int)out; emit_js(0); } return map; } static int do_tlb_w(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { if(addr<0x80800000||addr>=0xC0000000) { // address_generation already loaded the const emit_readword_dualindexedx4(FP,map,map); } else return -1; // No mapping } else { assert(s!=map); if(cache>=0) { // Use cached offset to memory map emit_addsr12(cache,s,map); }else{ emit_movimm(fp_memory_map>>2,map); emit_addsr12(map,s,map); } // Schedule this while we wait on the load //if(x) emit_xorimm(s,x,ar); emit_readword_dualindexedx4(FP,map,map); } return map; } static void do_tlb_w_branch(int map, int c, u_int addr, int *jaddr) { if(!c||addr<0x80800000||addr>=0xC0000000) { emit_testimm(map,0x40000000); *jaddr=(int)out; emit_jne(0); } } // Generate the address of the memory_map entry, relative to dynarec_local static void generate_map_const(u_int addr,int reg) { //DebugMessage(M64MSG_VERBOSE, "generate_map_const(%x,%s)",addr,regname[reg]); emit_movimm((addr>>12)+(fp_memory_map>>2),reg); } static void set_rounding_mode(int s,int temp) { assert(temp>=0); emit_andimm(s,3,temp); emit_addimm(FP,fp_rounding_modes,HOST_TEMPREG); emit_readword_dualindexedx4(HOST_TEMPREG,temp,temp); output_w32(0xeef10a10|rd_rn_rm(HOST_TEMPREG,0,0)); /*Read FPSCR*/ emit_andimm(HOST_TEMPREG,~0xc00000,HOST_TEMPREG); /*Clear RMode*/ emit_or(temp,HOST_TEMPREG,HOST_TEMPREG); /*Set RMode*/ output_w32(0xeee10a10|rd_rn_rm(HOST_TEMPREG,0,0)); /*Write FPSCR*/ } /* Special assem */ static void shift_assemble_arm(int i,struct regstat *i_regs) { if(rt1[i]) { if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV { signed char s,t,shift; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(t>=0){ if(rs1[i]==0) { emit_zeroreg(t); } else if(rs2[i]==0) { assert(s>=0); if(s!=t) emit_mov(s,t); } else { emit_andimm(shift,31,HOST_TEMPREG); if(opcode2[i]==4) // SLLV { emit_shl(s,HOST_TEMPREG,t); } if(opcode2[i]==6) // SRLV { emit_shr(s,HOST_TEMPREG,t); } if(opcode2[i]==7) // SRAV { emit_sar(s,HOST_TEMPREG,t); } } } } else { // DSLLV/DSRLV/DSRAV signed char sh,sl,th,tl,shift; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(tl>=0){ if(rs1[i]==0) { emit_zeroreg(tl); if(th>=0) emit_zeroreg(th); } else if(rs2[i]==0) { assert(sl>=0); if(sl!=tl) emit_mov(sl,tl); if(th>=0&&sh!=th) emit_mov(sh,th); } else { int temp=get_reg(i_regs->regmap,-1); int real_th=th; if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register assert(sl>=0); assert(sh>=0); emit_testimm(shift,32); emit_andimm(shift,31,HOST_TEMPREG); if(opcode2[i]==0x14) // DSLLV { if(th>=0) emit_shl(sh,HOST_TEMPREG,th); emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); emit_orrshr(sl,HOST_TEMPREG,th); emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); emit_shl(sl,HOST_TEMPREG,tl); if(th>=0) emit_cmovne_reg(tl,th); emit_cmovne_imm(0,tl); } if(opcode2[i]==0x16) // DSRLV { assert(th>=0); emit_shr(sl,HOST_TEMPREG,tl); emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); emit_orrshl(sh,HOST_TEMPREG,tl); emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); emit_shr(sh,HOST_TEMPREG,th); emit_cmovne_reg(th,tl); if(real_th>=0) emit_cmovne_imm(0,th); } if(opcode2[i]==0x17) // DSRAV { assert(th>=0); emit_shr(sl,HOST_TEMPREG,tl); emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); if(real_th>=0) { assert(temp>=0); emit_sarimm(th,31,temp); } emit_orrshl(sh,HOST_TEMPREG,tl); emit_rsbimm(HOST_TEMPREG,32,HOST_TEMPREG); emit_sar(sh,HOST_TEMPREG,th); emit_cmovne_reg(th,tl); if(real_th>=0) emit_cmovne_reg(temp,th); } } } } } } #define shift_assemble shift_assemble_arm static void loadlr_assemble_arm(int i,struct regstat *i_regs) { signed char s,th,tl,temp,temp2,temp2h,addr,map=-1,cache=-1; int offset,type=0,memtarget=0,c=0; intptr_t jaddr=0; u_int hr,reglist=0; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); temp=get_reg(i_regs->regmap,-1); temp2=get_reg(i_regs->regmap,FTEMP); temp2h=get_reg(i_regs->regmap,FTEMP|64); addr=get_reg(i_regs->regmap,AGEN1+(i&1)); assert(addr<0); assert(temp>=0); assert(temp2>=0); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { c=(i_regs->wasconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } if(offset||s<0||c) addr=temp2; else addr=s; int dummy=(rt1[i]==0)||(tl!=get_reg(i_regs->regmap,rt1[i])); // ignore loads to r0 and unneeded reg switch(opcode[i]) { case 0x22: type=LOADWL_STUB; break; case 0x26: type=LOADWR_STUB; break; case 0x1A: type=LOADDL_STUB; break; case 0x1B: type=LOADDR_STUB; break; } #ifndef INTERPRET_LOADLR if(!using_tlb) { if(!c) { emit_cmpimm(addr,0x800000); jaddr=(intptr_t)out; emit_jno(0); } #ifdef RAM_OFFSET if(!c&&!dummy) { map=get_reg(i_regs->regmap,ROREG); if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); } #endif }else{ // using tlb map=get_reg(i_regs->regmap,TLREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<=0); if(!c) { emit_shlimm(addr,3,temp); emit_andimm(addr,~3,temp2); emit_readword_indexed_tlb(0,temp2,map,temp2); emit_andimm(temp,24,temp); if (opcode[i]==0x26) emit_xorimm(temp,24,temp); // LWR emit_movimm(-1,HOST_TEMPREG); if (opcode[i]==0x26) { emit_shr(temp2,temp,temp2); emit_bic_lsr(tl,HOST_TEMPREG,temp,tl); }else{ emit_shl(temp2,temp,temp2); emit_bic_lsl(tl,HOST_TEMPREG,temp,tl); } emit_or(temp2,tl,tl); } else { int shift=((constmap[i][s]+offset)&3)<<3; uint32_t mask=~UINT32_C(0); if (opcode[i]==0x26) { //LWR shift^=24; mask>>=shift; } else { //LWL mask<<=shift; } if((constmap[i][s]+offset)&3) emit_andimm(addr,~3,temp2); if(shift) { emit_readword_indexed_tlb(0,temp2,map,temp2); if (opcode[i]==0x26) emit_shrimm(temp2,shift,temp2); else emit_shlimm(temp2,shift,temp2); emit_andimm(tl,~mask,tl); emit_or(temp2,tl,tl); } else emit_readword_indexed_tlb(0,temp2,map,tl); } } if(opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR assert(tl>=0); assert(th>=0); assert(temp2h>=0); if(!c) { emit_shlimm(addr,3,temp); emit_andimm(addr,~7,temp2); emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2); emit_testimm(temp,32); emit_andimm(temp,24,temp); if (opcode[i]==0x1A) { // LDL emit_rsbimm(temp,32,HOST_TEMPREG); emit_shl(temp2h,temp,temp2h); emit_orrshr(temp2,HOST_TEMPREG,temp2h); emit_movimm(-1,HOST_TEMPREG); emit_shl(temp2,temp,temp2); emit_cmove_reg(temp2h,th); emit_biceq_lsl(tl,HOST_TEMPREG,temp,tl); emit_bicne_lsl(th,HOST_TEMPREG,temp,th); emit_orreq(temp2,tl,tl); emit_orrne(temp2,th,th); } if (opcode[i]==0x1B) { // LDR emit_xorimm(temp,24,temp); emit_rsbimm(temp,32,HOST_TEMPREG); emit_shr(temp2,temp,temp2); emit_orrshl(temp2h,HOST_TEMPREG,temp2); emit_movimm(-1,HOST_TEMPREG); emit_shr(temp2h,temp,temp2h); emit_cmovne_reg(temp2,tl); emit_bicne_lsr(th,HOST_TEMPREG,temp,th); emit_biceq_lsr(tl,HOST_TEMPREG,temp,tl); emit_orrne(temp2h,th,th); emit_orreq(temp2h,tl,tl); } } else { int shift=((constmap[i][s]+offset)&7)<<3; uint64_t mask=~UINT64_C(0); if (opcode[i]==0x1B) { //LDR shift^=56; mask>>=shift; } else { //LDL mask<<=shift; } if((constmap[i][s]+offset)&7) emit_andimm(addr,~7,temp2); if(shift) { emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2); if (opcode[i]==0x1B) { emit_shrdimm(temp2h,temp2,shift,temp2h); emit_shrimm(temp2,shift,temp2); } else { emit_shldimm(temp2h,temp2,shift,temp2h); emit_shlimm(temp2,shift,temp2); } emit_andimm(tl,~mask,tl); emit_andimm(th,~mask>>32,th); emit_or(temp2,tl,tl); emit_or(temp2h,th,th); } else emit_readdword_indexed_tlb(0,temp2,map,th,tl); } } } if(jaddr) { add_stub(type,jaddr,(intptr_t)out,i,addr,(intptr_t)i_regs,ccadj[i],reglist); } else if(c&&!memtarget) { inline_readstub(type,i,(constmap[i][s]+offset),addr,i_regs,rt1[i],ccadj[i],reglist); } #else inline_readstub(type,i,c?(constmap[i][s]+offset):0,addr,i_regs,rt1[i],ccadj[i],reglist); #endif } #define loadlr_assemble loadlr_assemble_arm static void fconv_assemble_arm(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char rs=get_reg(i_regs->regmap,CSREG); assert(rs>=0); emit_testimm(rs,CP0_STATUS_CU1); int jaddr=(int)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCONV #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { // trunc_w_s emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,15); emit_ftosizs(15,15); // float->int, truncate if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fsts(15,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { // trunc_w_d emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_vldr(temp,7); emit_ftosizd(7,13); // double->int, truncate emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fsts(13,temp); return; } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { // cvt_s_w emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,13); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fsitos(13,15); emit_fsts(15,temp); return; } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { // cvt_d_w emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,13); emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fsitod(13,7); emit_vstr(7,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { // cvt_d_s emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,13); emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fcvtds(13,7); emit_vstr(7,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { // cvt_s_d emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_vldr(temp,7); emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fcvtsd(7,13); emit_fsts(13,temp); return; } #endif #endif // C emulation code u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,FSREG); save_regs(reglist); if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_s_w); } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)cvt_d_w); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_s_l); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_d_l); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)cvt_d_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_l_s); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_s_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((int)cvt_l_d); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)round_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)trunc_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)ceil_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)floor_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)round_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)trunc_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)ceil_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)floor_w_s); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)round_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)trunc_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)ceil_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)floor_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)round_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)trunc_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)ceil_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) { emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((int)floor_w_d); } restore_regs(reglist); } #define fconv_assemble fconv_assemble_arm static void fcomp_assemble(int i,struct regstat *i_regs) { signed char fs=get_reg(i_regs->regmap,FSREG); signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); int jaddr=(int)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCOMP if((source[i]&0x3f)==0x30) { emit_andimm(fs,~0x800000,fs); return; } if((source[i]&0x3e)==0x38) { // sf/ngle - these should throw exceptions for NaNs emit_andimm(fs,~0x800000,fs); return; } #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) if(opcode2[i]==0x10) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_orimm(fs,0x800000,fs); emit_flds(temp,14); emit_flds(HOST_TEMPREG,15); emit_fcmps(14,15); emit_fmstat(); if((source[i]&0x3f)==0x31) emit_bicvc_imm(fs,0x800000,fs); // c_un_s if((source[i]&0x3f)==0x32) emit_bicne_imm(fs,0x800000,fs); // c_eq_s if((source[i]&0x3f)==0x33) {emit_bicne_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ueq_s if((source[i]&0x3f)==0x34) emit_biccs_imm(fs,0x800000,fs); // c_olt_s if((source[i]&0x3f)==0x35) {emit_biccs_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ult_s if((source[i]&0x3f)==0x36) emit_bichi_imm(fs,0x800000,fs); // c_ole_s if((source[i]&0x3f)==0x37) {emit_bichi_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ule_s if((source[i]&0x3f)==0x3a) emit_bicne_imm(fs,0x800000,fs); // c_seq_s if((source[i]&0x3f)==0x3b) emit_bicne_imm(fs,0x800000,fs); // c_ngl_s if((source[i]&0x3f)==0x3c) emit_biccs_imm(fs,0x800000,fs); // c_lt_s if((source[i]&0x3f)==0x3d) emit_biccs_imm(fs,0x800000,fs); // c_nge_s if((source[i]&0x3f)==0x3e) emit_bichi_imm(fs,0x800000,fs); // c_le_s if((source[i]&0x3f)==0x3f) emit_bichi_imm(fs,0x800000,fs); // c_ngt_s return; } if(opcode2[i]==0x11) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_orimm(fs,0x800000,fs); emit_vldr(temp,6); emit_vldr(HOST_TEMPREG,7); emit_fcmpd(6,7); emit_fmstat(); if((source[i]&0x3f)==0x31) emit_bicvc_imm(fs,0x800000,fs); // c_un_d if((source[i]&0x3f)==0x32) emit_bicne_imm(fs,0x800000,fs); // c_eq_d if((source[i]&0x3f)==0x33) {emit_bicne_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ueq_d if((source[i]&0x3f)==0x34) emit_biccs_imm(fs,0x800000,fs); // c_olt_d if((source[i]&0x3f)==0x35) {emit_biccs_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ult_d if((source[i]&0x3f)==0x36) emit_bichi_imm(fs,0x800000,fs); // c_ole_d if((source[i]&0x3f)==0x37) {emit_bichi_imm(fs,0x800000,fs);emit_orrvs_imm(fs,0x800000,fs);} // c_ule_d if((source[i]&0x3f)==0x3a) emit_bicne_imm(fs,0x800000,fs); // c_seq_d if((source[i]&0x3f)==0x3b) emit_bicne_imm(fs,0x800000,fs); // c_ngl_d if((source[i]&0x3f)==0x3c) emit_biccs_imm(fs,0x800000,fs); // c_lt_d if((source[i]&0x3f)==0x3d) emit_biccs_imm(fs,0x800000,fs); // c_nge_d if((source[i]&0x3f)==0x3e) emit_bichi_imm(fs,0x800000,fs); // c_le_d if((source[i]&0x3f)==0x3f) emit_bichi_imm(fs,0x800000,fs); // c_ngt_d return; } #endif #endif // C only u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],ARG3_REG); if((source[i]&0x3f)==0x30) emit_call((int)c_f_s); if((source[i]&0x3f)==0x31) emit_call((int)c_un_s); if((source[i]&0x3f)==0x32) emit_call((int)c_eq_s); if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_s); if((source[i]&0x3f)==0x34) emit_call((int)c_olt_s); if((source[i]&0x3f)==0x35) emit_call((int)c_ult_s); if((source[i]&0x3f)==0x36) emit_call((int)c_ole_s); if((source[i]&0x3f)==0x37) emit_call((int)c_ule_s); if((source[i]&0x3f)==0x38) emit_call((int)c_sf_s); if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_s); if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_s); if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_s); if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_s); if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_s); if((source[i]&0x3f)==0x3e) emit_call((int)c_le_s); if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_s); } if(opcode2[i]==0x11) { emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],ARG3_REG); if((source[i]&0x3f)==0x30) emit_call((int)c_f_d); if((source[i]&0x3f)==0x31) emit_call((int)c_un_d); if((source[i]&0x3f)==0x32) emit_call((int)c_eq_d); if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_d); if((source[i]&0x3f)==0x34) emit_call((int)c_olt_d); if((source[i]&0x3f)==0x35) emit_call((int)c_ult_d); if((source[i]&0x3f)==0x36) emit_call((int)c_ole_d); if((source[i]&0x3f)==0x37) emit_call((int)c_ule_d); if((source[i]&0x3f)==0x38) emit_call((int)c_sf_d); if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_d); if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_d); if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_d); if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_d); if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_d); if((source[i]&0x3f)==0x3e) emit_call((int)c_le_d); if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_d); } restore_regs(reglist); emit_loadreg(FSREG,fs); } static void float_assemble(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); int jaddr=(int)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FLOAT #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) if((source[i]&0x3f)==6) // mov { if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(opcode2[i]==0x10) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],HOST_TEMPREG); emit_readword_indexed(0,temp,temp); emit_writeword_indexed(temp,0,HOST_TEMPREG); } if(opcode2[i]==0x11) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],HOST_TEMPREG); emit_vldr(temp,7); emit_vstr(7,HOST_TEMPREG); } } return; } if((source[i]&0x3f)>3) { if(opcode2[i]==0x10) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,15); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==4) // sqrt emit_fsqrts(15,15); if((source[i]&0x3f)==5) // abs emit_fabss(15,15); if((source[i]&0x3f)==7) // neg emit_fnegs(15,15); emit_fsts(15,temp); } if(opcode2[i]==0x11) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_vldr(temp,7); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==4) // sqrt emit_fsqrtd(7,7); if((source[i]&0x3f)==5) // abs emit_fabsd(7,7); if((source[i]&0x3f)==7) // neg emit_fnegd(7,7); emit_vstr(7,temp); } return; } if((source[i]&0x3f)<4) { if(opcode2[i]==0x10) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); } if(opcode2[i]==0x11) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); } if(((source[i]>>11)&0x1f)!=((source[i]>>16)&0x1f)) { if(opcode2[i]==0x10) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_flds(temp,15); emit_flds(HOST_TEMPREG,13); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } } if((source[i]&0x3f)==0) emit_fadds(15,13,15); if((source[i]&0x3f)==1) emit_fsubs(15,13,15); if((source[i]&0x3f)==2) emit_fmuls(15,13,15); if((source[i]&0x3f)==3) emit_fdivs(15,13,15); if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) { emit_fsts(15,HOST_TEMPREG); }else{ emit_fsts(15,temp); } } else if(opcode2[i]==0x11) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_vldr(temp,7); emit_vldr(HOST_TEMPREG,6); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } } if((source[i]&0x3f)==0) emit_faddd(7,6,7); if((source[i]&0x3f)==1) emit_fsubd(7,6,7); if((source[i]&0x3f)==2) emit_fmuld(7,6,7); if((source[i]&0x3f)==3) emit_fdivd(7,6,7); if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) { emit_vstr(7,HOST_TEMPREG); }else{ emit_vstr(7,temp); } } } else { if(opcode2[i]==0x10) { emit_flds(temp,15); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==0) emit_fadds(15,15,15); if((source[i]&0x3f)==1) emit_fsubs(15,15,15); if((source[i]&0x3f)==2) emit_fmuls(15,15,15); if((source[i]&0x3f)==3) emit_fdivs(15,15,15); emit_fsts(15,temp); } else if(opcode2[i]==0x11) { emit_vldr(temp,7); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readword((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==0) emit_faddd(7,7,7); if((source[i]&0x3f)==1) emit_fsubd(7,7,7); if((source[i]&0x3f)==2) emit_fmuld(7,7,7); if((source[i]&0x3f)==3) emit_fdivd(7,7,7); emit_vstr(7,temp); } } return; } #endif #endif u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,FSREG); if(opcode2[i]==0x10) { // Single precision save_regs(reglist); switch(source[i]&0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],ARG3_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG4_REG); break; case 0x04: emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); break; case 0x05: case 0x06: case 0x07: emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); break; } switch(source[i]&0x3f) { case 0x00: emit_call((int)add_s);break; case 0x01: emit_call((int)sub_s);break; case 0x02: emit_call((int)mul_s);break; case 0x03: emit_call((int)div_s);break; case 0x04: emit_call((int)sqrt_s);break; case 0x05: emit_call((int)abs_s);break; case 0x06: emit_call((int)mov_s);break; case 0x07: emit_call((int)neg_s);break; } restore_regs(reglist); } if(opcode2[i]==0x11) { // Double precision save_regs(reglist); switch(source[i]&0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],ARG3_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG4_REG); break; case 0x04: emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); break; case 0x05: case 0x06: case 0x07: emit_addimm(FP,fp_fcr31,ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((u_int)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); break; } switch(source[i]&0x3f) { case 0x00: emit_call((int)add_d);break; case 0x01: emit_call((int)sub_d);break; case 0x02: emit_call((int)mul_d);break; case 0x03: emit_call((int)div_d);break; case 0x04: emit_call((int)sqrt_d);break; case 0x05: emit_call((int)abs_d);break; case 0x06: emit_call((int)mov_d);break; case 0x07: emit_call((int)neg_d);break; } restore_regs(reglist); } } static void multdiv_assemble_arm(int i,struct regstat *i_regs) { // case 0x18: MULT // case 0x19: MULTU // case 0x1A: DIV // case 0x1B: DIVU // case 0x1C: DMULT // case 0x1D: DMULTU // case 0x1E: DDIV // case 0x1F: DDIVU if(rs1[i]&&rs2[i]) { if((opcode2[i]&4)==0) // 32-bit { #ifndef INTERPRET_MULT if((opcode2[i]==0x18) || (opcode2[i]==0x19)) { signed char m1=get_reg(i_regs->regmap,rs1[i]); signed char m2=get_reg(i_regs->regmap,rs2[i]); signed char hi=get_reg(i_regs->regmap,HIREG); signed char lo=get_reg(i_regs->regmap,LOREG); assert(m1>=0); assert(m2>=0); assert(hi>=0); assert(lo>=0); if(opcode2[i]==0x18) //MULT emit_smull(m1,m2,hi,lo); else if(opcode2[i]==0x19) //MULTU emit_umull(m1,m2,hi,lo); } else #endif #ifndef INTERPRET_DIV if((opcode2[i]==0x1A) || (opcode2[i]==0x1B)) { signed char d1=get_reg(i_regs->regmap,rs1[i]); // dividend signed char d2=get_reg(i_regs->regmap,rs2[i]); // divisor assert(d1>=0); assert(d2>=0); signed char quotient=get_reg(i_regs->regmap,LOREG); signed char remainder=get_reg(i_regs->regmap,HIREG); assert(quotient>=0); assert(remainder>=0); if(opcode2[i]==0x1A) //DIV { if(arm_cpu_features.IDIVa) { emit_test(d2,d2); emit_jeq((int)out+16); // Division by zero emit_sdiv(d1,d2,quotient); emit_mul(quotient,d2,remainder); emit_sub(d1,remainder,remainder); } else { emit_movs(d1,remainder); emit_negmi(remainder,remainder); emit_movs(d2,HOST_TEMPREG); emit_jeq((int)out+52); // Division by zero emit_negmi(HOST_TEMPREG,HOST_TEMPREG); emit_clz(HOST_TEMPREG,quotient); emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG); emit_orimm(quotient,1<<31,quotient); emit_shr(quotient,quotient,quotient); emit_cmp(remainder,HOST_TEMPREG); emit_subcs(remainder,HOST_TEMPREG,remainder); emit_adcs(quotient,quotient,quotient); emit_shrimm(HOST_TEMPREG,1,HOST_TEMPREG); emit_jcc((int)out-16); // -4 emit_teq(d1,d2); emit_negmi(quotient,quotient); emit_test(d1,d1); emit_negmi(remainder,remainder); } } else if(opcode2[i]==0x1B) //DIVU { emit_test(d2,d2); if(arm_cpu_features.IDIVa) { emit_jeq((int)out+16); // Division by zero emit_udiv(d1,d2,quotient); emit_mul(quotient,d2,remainder); emit_sub(d1,remainder,remainder); } else { emit_jeq((int)out+44); // Division by zero emit_clz(d2,HOST_TEMPREG); emit_movimm(1<<31,quotient); emit_shl(d2,HOST_TEMPREG,d2); emit_mov(d1,remainder); emit_shr(quotient,HOST_TEMPREG,quotient); emit_cmp(remainder,d2); emit_subcs(remainder,d2,remainder); emit_adcs(quotient,quotient,quotient); emit_shrcc_imm(d2,1,d2); emit_jcc((int)out-16); // -4 } } } else #endif { u_int reglist=0; signed char r1=get_reg(i_regs->regmap,rs1[i]); signed char r2=get_reg(i_regs->regmap,rs2[i]); signed char hi=get_reg(i_regs->regmap,HIREG); signed char lo=get_reg(i_regs->regmap,LOREG); assert(r1>=0); assert(r2>=0); for(int hr=0;hrregmap[hr]>=0) reglist|=1<=0) reglist&=~(1<=0) reglist&=~(1<=0) emit_loadreg(HIREG,hi); if(lo>=0) emit_loadreg(LOREG,lo); } } else // 64-bit { #ifndef INTERPRET_MULT64 if(opcode2[i]==0x1C||opcode2[i]==0x1D) { signed char b_1=get_reg(i_regs->regmap,rs1[i]|64); signed char b_0=get_reg(i_regs->regmap,rs1[i]); signed char c_1=get_reg(i_regs->regmap,rs2[i]|64); signed char c_0=get_reg(i_regs->regmap,rs2[i]); assert(b_1>=0); assert(b_0>=0); assert(c_1>=0); assert(c_0>=0); signed char a_3=get_reg(i_regs->regmap,HIREG|64); signed char a_2=get_reg(i_regs->regmap,HIREG); signed char a_1=get_reg(i_regs->regmap,LOREG|64); signed char a_0=get_reg(i_regs->regmap,LOREG); assert(a_3>=0); assert(a_2>=0); assert(a_1>=0); assert(a_0>=0); if(opcode2[i]==0x1C) // DMULT { emit_umull(b_0,c_0,a_1,a_0); emit_zeroreg(a_2); emit_smlal(b_0,c_1,a_2,a_1); emit_testimm(b_0,0x80000000); emit_addne(a_2,c_1,a_2); emit_zeroreg(a_3); emit_smlal(b_1,c_0,a_3,a_1); emit_testimm(c_0,0x80000000); emit_addne(a_3,b_1,a_3); emit_sarimm(a_2,31,HOST_TEMPREG); emit_adds(a_2,a_3,a_2); emit_adcsarimm(HOST_TEMPREG,a_3,a_3,31); emit_smlal(b_1,c_1,a_3,a_2); } else if(opcode2[i]==0x1D) // DMULTU { emit_umull(b_0,c_0,a_1,a_0); emit_zeroreg(a_2); emit_umlal(b_0,c_1,a_2,a_1); emit_zeroreg(a_3); emit_umlal(b_1,c_0,a_3,a_1); emit_zeroreg(HOST_TEMPREG); emit_adds(a_2,a_3,a_2); emit_adcimm(HOST_TEMPREG,0,a_3); emit_umlal(b_1,c_1,a_3,a_2); } } else #endif { u_int reglist=0; signed char r1h=get_reg(i_regs->regmap,rs1[i]|64); signed char r1l=get_reg(i_regs->regmap,rs1[i]); signed char r2h=get_reg(i_regs->regmap,rs2[i]|64); signed char r2l=get_reg(i_regs->regmap,rs2[i]); signed char hih=get_reg(i_regs->regmap,HIREG|64); signed char hil=get_reg(i_regs->regmap,HIREG); signed char loh=get_reg(i_regs->regmap,LOREG|64); signed char lol=get_reg(i_regs->regmap,LOREG); assert(r1h>=0); assert(r2h>=0); assert(r1l>=0); assert(r2l>=0); for(int hr=0;hrregmap[hr]>=0) reglist|=1<=0) reglist&=~(1<=0) reglist&=~(1<=0) reglist&=~(1<=0) reglist&=~(1<=0) emit_loadreg(HIREG|64,hih); if(hil>=0) emit_loadreg(HIREG,hil); if(loh>=0) emit_loadreg(LOREG|64,loh); if(lol>=0) emit_loadreg(LOREG,lol); } } } else { // Multiply by zero is zero. // MIPS does not have a divide by zero exception. // The result is undefined, we return zero. signed char hr=get_reg(i_regs->regmap,HIREG); signed char lr=get_reg(i_regs->regmap,LOREG); if(hr>=0) emit_zeroreg(hr); if(lr>=0) emit_zeroreg(lr); } } #define multdiv_assemble multdiv_assemble_arm static void do_preload_rhash(int r) { // Don't need this for ARM. On x86, this puts the value 0xf8 into the // register. On ARM the hash can be done with a single instruction (below) } static void do_preload_rhtbl(int ht) { emit_addimm(FP,fp_mini_ht(0,0),ht); } static void do_rhash(int rs,int rh) { emit_andimm(rs,0xf8,rh); } static void do_miniht_load(int ht,int rh) { assem_debug("ldr %s,[%s,%s]!",regname[rh],regname[ht],regname[rh]); output_w32(0xe7b00000|rd_rn_rm(rh,ht,rh)); } static void do_miniht_jump(int rs,int rh,int ht) { emit_cmp(rh,rs); emit_ldreq_indexed(ht,4,15); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK emit_mov(rs,7); emit_jmp(jump_vaddr_reg[7]); #else emit_jmp(jump_vaddr_reg[rs]); #endif } static void do_miniht_insert(u_int return_address,int rt,int temp) { #ifdef ARMv5_ONLY emit_movimm(return_address,rt); // PC into link register add_to_linker((int)out,return_address,1); emit_pcreladdr(temp); emit_writeword(rt,(u_int)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0xFF)>>3][0]); emit_writeword(temp,(u_int)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0xFF)>>3][1]); #else emit_movw(return_address&0x0000FFFF,rt); add_to_linker((int)out,return_address,1); emit_pcreladdr(temp); emit_writeword(temp,(u_int)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0xFF)>>3][1]); emit_movt(return_address&0xFFFF0000,rt); emit_writeword(rt,(u_int)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0xFF)>>3][0]); #endif } // Clearing the cache is rather slow on ARM Linux, so mark the areas // that need to be cleared, and then only clear these areas once. static void do_clear_cache(void) { int i,j; for (i=0;i<(1<<(TARGET_SIZE_2-17));i++) { u_int bitmap=needs_clear_cache[i]; if(bitmap) { u_int start,end; for(j=0;j<32;j++) { if(bitmap&(1<>12); } // CPU-architecture-specific initialization static void arch_init(void) { detect_arm_cpu_features(); print_arm_cpu_features(); g_dev.r4300.new_dynarec_hot_state.rounding_modes[0]=0x0<<22; // round g_dev.r4300.new_dynarec_hot_state.rounding_modes[1]=0x3<<22; // trunc g_dev.r4300.new_dynarec_hot_state.rounding_modes[2]=0x1<<22; // ceil g_dev.r4300.new_dynarec_hot_state.rounding_modes[3]=0x2<<22; // floor jump_table_symbols[0] = (int) cached_interp_TLBR; jump_table_symbols[1] = (int) cached_interp_TLBP; jump_table_symbols[2] = (int) cached_interp_MULT; jump_table_symbols[3] = (int) cached_interp_MULTU; jump_table_symbols[4] = (int) cached_interp_DIV; jump_table_symbols[5] = (int) cached_interp_DIVU; jump_table_symbols[6] = (int) cached_interp_DMULT; jump_table_symbols[7] = (int) cached_interp_DMULTU; jump_table_symbols[8] = (int) cached_interp_DDIV; jump_table_symbols[9] = (int) cached_interp_DDIVU; #ifdef RAM_OFFSET g_dev.r4300.new_dynarec_hot_state.ram_offset=((int)g_dev.rdram.dram-(int)0x80000000)>>2; #endif // Trampolines for jumps >32M int *ptr,*ptr2; ptr=(int *)jump_table_symbols; ptr2=(int *)((char *)base_addr+(1<=-33554432&&offset<33554432) { *ptr2=0xea000000|((offset>>2)&0xffffff); // direct branch }else{ *ptr2=0xe51ff004; // ldr pc,[pc,#-4] } ptr2++; *ptr2=*ptr; ptr++; ptr2++; } // Jumping thru the trampolines created above slows things down by about 1%. // If part of the cache is beyond the 32M limit, avoid using this area // initially. It will be used later if the cache gets full. /*if((u_int)dyna_linker-33554432>(u_int)base_addr) { if((u_int)dyna_linker-33554432<(u_int)base_addr+(1<<(TARGET_SIZE_2-1))) { out=(u_char *)(((u_int)dyna_linker-33554432)&~4095); expirep=((((int)out-(int)base_addr)>>(TARGET_SIZE_2-16))+16384)&65535; } }*/ } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm/assem_arm.h000066400000000000000000000021451464506436200254430ustar00rootroot00000000000000#ifndef M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ASSEM_ARM_H #define M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ASSEM_ARM_H #define HOST_REGS 13 #define HOST_CCREG 10 #define HOST_BTREG 8 #define EXCLUDE_REG 11 #define HOST_IMM8 1 #define HAVE_CMOV_IMM 1 #define CORTEX_A8_BRANCH_PREDICTION_HACK 1 #define USE_MINI_HT 1 //#define REG_PREFETCH 1 #define HAVE_CONDITIONAL_CALL 1 #define RAM_OFFSET 1 /* ARM calling convention: r0-r3, r12: caller-save r4-r11: callee-save */ #define ARG1_REG 0 #define ARG2_REG 1 #define ARG3_REG 2 #define ARG4_REG 3 /* GCC register naming convention: r10 = sl (base) r11 = fp (frame pointer) r12 = ip (scratch) r13 = sp (stack pointer) r14 = lr (link register) r15 = pc (program counter) */ #define FP 11 #define LR 14 #define CALLER_SAVED_REGS 0x100f #define HOST_TEMPREG 14 // Note: FP is set to &dynarec_local when executing generated code. // Thus the local variables are actually global and not on the stack. #define TARGET_SIZE_2 25 // 2^25 = 32 megabytes #define JUMP_TABLE_SIZE (sizeof(jump_table_symbols)*2) #endif /* M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ASSEM_ARM_H */ mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm/linkage_arm.S000066400000000000000000000176271464506436200257330ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - linkage_arm.S * * Copyright (C) 2009-2011 Ari64 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define GLOBAL_FUNCTION(name) \ .align 2; \ .globl name; \ .hidden name; \ .type name, %function; \ name #define LOCAL_FUNCTION(name) \ .align 2; \ .hidden name; \ .type name, %function; \ name #define GLOBAL_VARIABLE(name, size_) \ .global name; \ .hidden name; \ .type name, %object; \ .size name, size_ #define TEXT_SECTION .text #define END_SECTION #ifndef __ARM_NEON__ #if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP)) .fpu vfp #else .fpu softvfp #endif #else .fpu neon #endif .eabi_attribute 20, 1 .eabi_attribute 21, 1 #ifndef __ARM_NEON__ .eabi_attribute 23, 3 #endif .eabi_attribute 24, 1 .eabi_attribute 25, 1 .eabi_attribute 26, 2 #ifndef __ARM_NEON__ #if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP)) .eabi_attribute 28, 1 #endif #endif .eabi_attribute 30, 6 .eabi_attribute 18, 4 .file "linkage_arm.S" #include "asm_defines_gas.h" device_r4300_new_dynarec_hot_state_dynarec_local = (offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_dynarec_local) /* Defines offsets for fp addressed variables */ fp_saved_context = offsetof_struct_new_dynarec_hot_state_dynarec_local + 28 fp_cycle_count = offsetof_struct_new_dynarec_hot_state_cycle_count fp_pending_exception = offsetof_struct_new_dynarec_hot_state_pending_exception fp_pcaddr = offsetof_struct_new_dynarec_hot_state_pcaddr fp_stop = offsetof_struct_new_dynarec_hot_state_stop TEXT_SECTION .align 2 .outptr_offset : .word out-(.outptr_pic+8) .savedcontextptr_offset : .word g_dev + device_r4300_new_dynarec_hot_state_dynarec_local + fp_saved_context -(.savedcontextptr_pic+8) GLOBAL_FUNCTION(jump_vaddr_r0): b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r1): mov r0, r1 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r2): mov r0, r2 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r3): mov r0, r3 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r4): mov r0, r4 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r5): mov r0, r5 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r6): mov r0, r6 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r8): mov r0, r8 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r9): mov r0, r9 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r10): mov r0, r10 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r12): mov r0, r12 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_r7): add r0, r7, #0 GLOBAL_FUNCTION(jump_vaddr): bl get_addr_ht mov pc, r0 GLOBAL_FUNCTION(verify_code): /* r0 = head */ mov r9, lr bl verify_dirty tst r0, r0 moveq pc, r9 bl get_addr mov pc, r0 GLOBAL_FUNCTION(cc_interrupt): str r10, [fp, #fp_cycle_count] mov r1, #0 str r1, [fp, #fp_pending_exception] mov r10, lr bl dynarec_gen_interrupt mov lr, r10 ldr r10, [fp, #fp_cycle_count] ldr r1, [fp, #fp_pending_exception] ldr r2, [fp, #fp_stop] tst r2, r2 bne new_dyna_stop tst r1, r1 moveq pc, lr .E1: ldr r0, [fp, #fp_pcaddr] bl get_addr_ht mov pc, r0 LOCAL_FUNCTION(new_dyna_stop): add r12, fp, #fp_saved_context ldmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, pc} GLOBAL_FUNCTION(do_interrupt): ldr r2, [fp, #fp_stop] tst r2, r2 bne new_dyna_stop ldr r0, [fp, #fp_pcaddr] bl get_addr_ht ldr r10, [fp, #fp_cycle_count] mov pc, r0 GLOBAL_FUNCTION(fp_exception): str r0, [fp, #fp_pcaddr] bl cop1_unusable mov pc, r0 GLOBAL_FUNCTION(jump_syscall): str r0, [fp, #fp_pcaddr] bl SYSCALL_new mov pc, r0 GLOBAL_FUNCTION(jump_eret): str r10, [fp, #fp_cycle_count] bl ERET_new ldr r10, [fp, #fp_cycle_count] tst r0, r0 beq new_dyna_stop mov pc, r0 GLOBAL_FUNCTION(dyna_linker): bl dynamic_linker mov pc, r0 GLOBAL_FUNCTION(dyna_linker_ds): bl dynamic_linker_ds mov pc, r0 GLOBAL_FUNCTION(new_dyna_start): ldr r12, .savedcontextptr_offset .savedcontextptr_pic: add r12, pc, r12 ldr r1, .outptr_offset .outptr_pic: add r1, pc, r1 mov r0, #0xa4000000 stmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, lr} sub fp, r12, #fp_saved_context ldr r4, [r1] add r0, r0, #0x40 bl new_recompile_block ldr r10, [fp, #fp_cycle_count] mov pc, r4 GLOBAL_FUNCTION(invalidate_addr_r0): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r0, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r1): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r1, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r2): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r2, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r3): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r3, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r4): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r4, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r5): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r5, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r6): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r6, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r7): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r7, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r8): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r8, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r9): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r9, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r10): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r10, #12 b invalidate_addr_call GLOBAL_FUNCTION(invalidate_addr_r12): stmia fp, {r0, r1, r2, r3, r12, lr} lsr r0, r12, #12 LOCAL_FUNCTION(invalidate_addr_call): bl invalidate_block ldmia fp, {r0, r1, r2, r3, r12, pc} GLOBAL_FUNCTION(breakpoint): .inst 0xe7f001f0 mov pc, lr END_SECTION mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm64/000077500000000000000000000000001464506436200234735ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm64/assem_arm64.c000066400000000000000000004256671464506436200260040ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assem_arm64.c * * Copyright (C) 2009-2018 Gillou68310 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define fp_cycle_count (offsetof(struct new_dynarec_hot_state, cycle_count)) #define fp_invc_ptr (offsetof(struct new_dynarec_hot_state, invc_ptr)) #define fp_fcr31 (offsetof(struct new_dynarec_hot_state, cp1_fcr31)) #define fp_regs (offsetof(struct new_dynarec_hot_state, regs)) #define fp_hi (offsetof(struct new_dynarec_hot_state, hi)) #define fp_lo (offsetof(struct new_dynarec_hot_state, lo)) #define fp_cp0_regs(x) ((offsetof(struct new_dynarec_hot_state, cp0_regs)) + (x)*sizeof(uint32_t)) #define fp_rounding_modes (offsetof(struct new_dynarec_hot_state, rounding_modes)) #define fp_fake_pc (offsetof(struct new_dynarec_hot_state, fake_pc)) #define fp_ram_offset (offsetof(struct new_dynarec_hot_state, ram_offset)) #define fp_mini_ht (offsetof(struct new_dynarec_hot_state, mini_ht)) #define fp_memory_map (offsetof(struct new_dynarec_hot_state, memory_map)) typedef enum { COND_EQ, COND_NE, COND_CS, COND_CC, COND_MI, COND_PL, COND_VS, COND_VC, COND_HI, COND_LS, COND_GE, COND_LT, COND_GT, COND_LE, COND_AW, COND_NV } eCond; void jump_vaddr_x0(void); void jump_vaddr_x1(void); void jump_vaddr_x2(void); void jump_vaddr_x3(void); void jump_vaddr_x4(void); void jump_vaddr_x5(void); void jump_vaddr_x6(void); void jump_vaddr_x7(void); void jump_vaddr_x8(void); void jump_vaddr_x9(void); void jump_vaddr_x10(void); void jump_vaddr_x11(void); void jump_vaddr_x12(void); void jump_vaddr_x13(void); void jump_vaddr_x14(void); void jump_vaddr_x15(void); void jump_vaddr_x16(void); void jump_vaddr_x17(void); void jump_vaddr_x19(void); void jump_vaddr_x21(void); void jump_vaddr_x22(void); void jump_vaddr_x23(void); void jump_vaddr_x24(void); void jump_vaddr_x25(void); void jump_vaddr_x26(void); void jump_vaddr_x27(void); void jump_vaddr_x28(void); void breakpoint(void); static void invalidate_addr(u_int addr); static uintptr_t literals[1024][2]; static unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)]; static const uintptr_t jump_vaddr_reg[32] = { (intptr_t)jump_vaddr_x0, (intptr_t)jump_vaddr_x1, (intptr_t)jump_vaddr_x2, (intptr_t)jump_vaddr_x3, (intptr_t)jump_vaddr_x4, (intptr_t)jump_vaddr_x5, (intptr_t)jump_vaddr_x6, (intptr_t)jump_vaddr_x7, (intptr_t)jump_vaddr_x8, (intptr_t)jump_vaddr_x9, (intptr_t)jump_vaddr_x10, (intptr_t)jump_vaddr_x11, (intptr_t)jump_vaddr_x12, (intptr_t)jump_vaddr_x13, (intptr_t)jump_vaddr_x14, (intptr_t)jump_vaddr_x15, (intptr_t)jump_vaddr_x16, (intptr_t)jump_vaddr_x17, (intptr_t)breakpoint, /*trampoline jumps uses x18*/ (intptr_t)jump_vaddr_x19, (intptr_t)breakpoint, /*cycle count*/ (intptr_t)jump_vaddr_x21, (intptr_t)jump_vaddr_x22, (intptr_t)jump_vaddr_x23, (intptr_t)jump_vaddr_x24, (intptr_t)jump_vaddr_x25, (intptr_t)jump_vaddr_x26, (intptr_t)jump_vaddr_x27, (intptr_t)jump_vaddr_x28, (intptr_t)breakpoint, (intptr_t)breakpoint, (intptr_t)breakpoint}; static uintptr_t jump_table_symbols[] = { (intptr_t)NULL /*TLBR*/, (intptr_t)NULL /*TLBP*/, (intptr_t)NULL /*MULT*/, (intptr_t)NULL /*MULTU*/, (intptr_t)NULL /*DIV*/, (intptr_t)NULL /*DIVU*/, (intptr_t)NULL /*DMULT*/, (intptr_t)NULL /*DMULTU*/, (intptr_t)NULL /*DDIV*/, (intptr_t)NULL /*DDIVU*/, (intptr_t)invalidate_addr, (intptr_t)dyna_linker, (intptr_t)dyna_linker_ds, (intptr_t)verify_code, (intptr_t)cc_interrupt, (intptr_t)fp_exception, (intptr_t)jump_syscall, (intptr_t)jump_eret, (intptr_t)do_interrupt, (intptr_t)TLBWI_new, (intptr_t)TLBWR_new, (intptr_t)MFC0_new, (intptr_t)MTC0_new, (intptr_t)jump_vaddr_x0, (intptr_t)jump_vaddr_x1, (intptr_t)jump_vaddr_x2, (intptr_t)jump_vaddr_x3, (intptr_t)jump_vaddr_x4, (intptr_t)jump_vaddr_x5, (intptr_t)jump_vaddr_x6, (intptr_t)jump_vaddr_x7, (intptr_t)jump_vaddr_x8, (intptr_t)jump_vaddr_x9, (intptr_t)jump_vaddr_x10, (intptr_t)jump_vaddr_x11, (intptr_t)jump_vaddr_x12, (intptr_t)jump_vaddr_x13, (intptr_t)jump_vaddr_x14, (intptr_t)jump_vaddr_x15, (intptr_t)jump_vaddr_x16, (intptr_t)jump_vaddr_x17, (intptr_t)jump_vaddr_x19, (intptr_t)jump_vaddr_x21, (intptr_t)jump_vaddr_x22, (intptr_t)jump_vaddr_x23, (intptr_t)jump_vaddr_x24, (intptr_t)jump_vaddr_x25, (intptr_t)jump_vaddr_x26, (intptr_t)jump_vaddr_x27, (intptr_t)jump_vaddr_x28, (intptr_t)cvt_s_w, (intptr_t)cvt_d_w, (intptr_t)cvt_s_l, (intptr_t)cvt_d_l, (intptr_t)cvt_w_s, (intptr_t)cvt_w_d, (intptr_t)cvt_l_s, (intptr_t)cvt_l_d, (intptr_t)cvt_d_s, (intptr_t)cvt_s_d, (intptr_t)round_l_s, (intptr_t)round_w_s, (intptr_t)trunc_l_s, (intptr_t)trunc_w_s, (intptr_t)ceil_l_s, (intptr_t)ceil_w_s, (intptr_t)floor_l_s, (intptr_t)floor_w_s, (intptr_t)round_l_d, (intptr_t)round_w_d, (intptr_t)trunc_l_d, (intptr_t)trunc_w_d, (intptr_t)ceil_l_d, (intptr_t)ceil_w_d, (intptr_t)floor_l_d, (intptr_t)floor_w_d, (intptr_t)c_f_s, (intptr_t)c_un_s, (intptr_t)c_eq_s, (intptr_t)c_ueq_s, (intptr_t)c_olt_s, (intptr_t)c_ult_s, (intptr_t)c_ole_s, (intptr_t)c_ule_s, (intptr_t)c_sf_s, (intptr_t)c_ngle_s, (intptr_t)c_seq_s, (intptr_t)c_ngl_s, (intptr_t)c_lt_s, (intptr_t)c_nge_s, (intptr_t)c_le_s, (intptr_t)c_ngt_s, (intptr_t)c_f_d, (intptr_t)c_un_d, (intptr_t)c_eq_d, (intptr_t)c_ueq_d, (intptr_t)c_olt_d, (intptr_t)c_ult_d, (intptr_t)c_ole_d, (intptr_t)c_ule_d, (intptr_t)c_sf_d, (intptr_t)c_ngle_d, (intptr_t)c_seq_d, (intptr_t)c_ngl_d, (intptr_t)c_lt_d, (intptr_t)c_nge_d, (intptr_t)c_le_d, (intptr_t)c_ngt_d, (intptr_t)add_s, (intptr_t)sub_s, (intptr_t)mul_s, (intptr_t)div_s, (intptr_t)sqrt_s, (intptr_t)abs_s, (intptr_t)mov_s, (intptr_t)neg_s, (intptr_t)add_d, (intptr_t)sub_d, (intptr_t)mul_d, (intptr_t)div_d, (intptr_t)sqrt_d, (intptr_t)abs_d, (intptr_t)mov_d, (intptr_t)neg_d, (intptr_t)read_byte_new, (intptr_t)read_hword_new, (intptr_t)read_word_new, (intptr_t)read_dword_new, (intptr_t)write_byte_new, (intptr_t)write_hword_new, (intptr_t)write_word_new, (intptr_t)write_dword_new, (intptr_t)LWL_new, (intptr_t)LWR_new, (intptr_t)LDL_new, (intptr_t)LDR_new, (intptr_t)SWL_new, (intptr_t)SWR_new, (intptr_t)SDL_new, (intptr_t)SDR_new, (intptr_t)breakpoint }; static void cache_flush(char* start, char* end) { #ifndef WIN32 // Don't rely on GCC's __clear_cache implementation, as it caches // icache/dcache cache line sizes, that can vary between cores on // big.LITTLE architectures. uint64_t addr, ctr_el0; static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff; size_t isize, dsize; __asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0)); isize = 4 << ((ctr_el0 >> 0) & 0xf); dsize = 4 << ((ctr_el0 >> 16) & 0xf); // use the global minimum cache line size icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize; dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize; addr = (uint64_t)start & ~(uint64_t)(dsize - 1); for (; addr < (uint64_t)end; addr += dsize) // use "civac" instead of "cvau", as this is the suggested workaround for // Cortex-A53 errata 819472, 826319, 827319 and 824069. __asm__ volatile("dc civac, %0" : : "r"(addr) : "memory"); __asm__ volatile("dsb ish" : : : "memory"); addr = (uint64_t)start & ~(uint64_t)(isize - 1); for (; addr < (uint64_t)end; addr += isize) __asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory"); __asm__ volatile("dsb ish" : : : "memory"); __asm__ volatile("isb" : : : "memory"); #endif } /* Linker */ static void set_jump_target(intptr_t addr,uintptr_t target) { u_int *ptr=(u_int *)addr; intptr_t offset=target-(intptr_t)addr; if((*ptr&0xFC000000)==0x14000000) { assert(offset>=-134217728LL&&offset<134217728LL); *ptr=(*ptr&0xFC000000)|((offset>>2)&0x3ffffff); } else if((*ptr&0xff000000)==0x54000000) { //Conditional branch are limited to +/- 1MB //block max size is 256k so branching beyond the +/- 1MB limit //should only happen when jumping to an already compiled block (see add_link) //a workaround would be to do a trampoline jump via a stub at the end of the block assert(offset>=-1048576LL&&offset<1048576LL); *ptr=(*ptr&0xFF00000F)|(((offset>>2)&0x7ffff)<<5); } else if((*ptr&0x9f000000)==0x10000000) { //adr //generated by do_miniht_insert assert(offset>=-1048576LL&&offset<1048576LL); *ptr=(*ptr&0x9F00001F)|(offset&0x3)<<29|((offset>>2)&0x7ffff)<<5; } else assert(0); /*Should not happen*/ } /* Literal pool */ static void add_literal(uintptr_t addr,uintptr_t val) { literals[literalcount][0]=addr; literals[literalcount][1]=val; literalcount++; } static void *add_pointer(void *src, void* addr) { int *ptr=(int*)src; assert((*ptr&0xFC000000)==0x14000000); //b int offset=((signed int)(*ptr<<6)>>6)<<2; int *ptr2=(int*)((intptr_t)ptr+offset); assert((ptr2[0]&0xFFE00000)==0x52A00000); //movz assert((ptr2[1]&0xFFE00000)==0x72800000); //movk assert((ptr2[2]&0x9f000000)==0x10000000); //adr set_jump_target((intptr_t)src,(intptr_t)addr); intptr_t ptr_rx=((intptr_t)ptr-(intptr_t)base_addr)+(intptr_t)base_addr_rx; cache_flush((void*)ptr_rx, (void*)(ptr_rx+4)); return ptr2; } static void *kill_pointer(void *stub) { int *ptr=(int *)((intptr_t)stub+8); assert((*ptr&0x9f000000)==0x10000000); //adr int offset=(((signed int)(*ptr<<8)>>13)<<2)|((*ptr>>29)&0x3); int *i_ptr=(int*)((intptr_t)ptr+offset); assert((*i_ptr&0xfc000000)==0x14000000); //b set_jump_target((intptr_t)i_ptr,(intptr_t)stub); return i_ptr; } static intptr_t get_pointer(void *stub) { int *ptr=(int *)((intptr_t)stub+8); assert((*ptr&0x9f000000)==0x10000000); //adr int offset=(((signed int)(*ptr<<8)>>13)<<2)|((*ptr>>29)&0x3); int *i_ptr=(int*)((intptr_t)ptr+offset); assert((*i_ptr&0xfc000000)==0x14000000); //b return (intptr_t)i_ptr+(((signed int)(*i_ptr<<6)>>6)<<2); } /* Register allocation */ // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). static void alloc_reg(struct regstat *cur,int i,signed char tr) { int r,hr; int preferred_reg = (tr&7); if(tr==CCREG) preferred_reg=HOST_CCREG; if(tr==PTEMP||tr==FTEMP) preferred_reg=12; // Don't allocate unused registers if((cur->u>>tr)&1) return; // see if it's already allocated for(hr=0;hrregmap[hr]==tr) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,tr,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=tr; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=tr; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=tr; cur->dirty&=~(1<isconst&=~(1<regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=tr; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<uu>>tr)&1) return; // see if the upper half is already allocated for(hr=0;hrregmap[hr]==tr+64) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,tr,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=tr|64; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=tr|64; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=tr|64; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=tr|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=tr|64; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=tr|64; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=tr|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=tr|64; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=tr|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=tr|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==tr) return; } // Try to allocate any available register for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<uu>>(r&63))&1) { if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hr2) { if(cur->regmap[hr]==r+64) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<2) { if(cur->regmap[hr]==r) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=tr; cur->dirty&=~(1<isconst&=~(1<regmap[n]==tr) { dirty=(cur->dirty>>n)&1; cur->regmap[n]=-1; } } cur->regmap[hr]=tr; cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<=(intptr_t)base_addr+(1<=134217728LL) { int n; for(n=0;n=-134217728LL&&offset<134217728LL); return (offset>>2)&0x3ffffff; } static u_int gencondjmp(intptr_t addr) { if(addr<4) return 0; intptr_t out_rx=(intptr_t)out; if(addr<(intptr_t)base_addr||addr>=(intptr_t)base_addr+(1<=-1048576LL&&offset<1048576LL); return (offset>>2)&0x7ffff; } uint32_t count_trailing_zeros(uint64_t value) { #ifdef _MSC_VER uint32_t trailing_zero_low = 0; uint32_t trailing_zero_high = 0; if(!_BitScanForward(&trailing_zero_low, (uint32_t)value)) trailing_zero_low = 32; if(!_BitScanForward(&trailing_zero_high, (uint32_t)(value>>32))) trailing_zero_high = 32; if(trailing_zero_low == 32) return trailing_zero_low + trailing_zero_high; else return trailing_zero_low; #else /* ARM64 */ return __builtin_ctzll(value); #endif } uint32_t count_leading_zeros(uint64_t value) { #ifdef _MSC_VER uint32_t leading_zero_low = 0; uint32_t leading_zero_high = 0; if(!_BitScanReverse(&leading_zero_low, (uint32_t)value)) leading_zero_low = 32; else leading_zero_low = 31 - leading_zero_low; if(!_BitScanReverse(&leading_zero_high, (uint32_t)(value>>32))) leading_zero_high = 32; else leading_zero_high = 31 - leading_zero_high; if(leading_zero_high == 32) return leading_zero_low + leading_zero_high; else return leading_zero_high; #else /* ARM64 */ return __builtin_clzll(value); #endif } // This function returns true if the argument is a non-empty // sequence of ones starting at the least significant bit with the remainder // zero. static uint32_t is_mask(uint64_t value) { return value && ((value + 1) & value) == 0; } // This function returns true if the argument contains a // non-empty sequence of ones with the remainder zero. static uint32_t is_shifted_mask(uint64_t Value) { return Value && is_mask((Value - 1) | Value); } // Determine if an immediate value can be encoded // as the immediate operand of a logical instruction for the given register // size. If so, return 1 with "encoding" set to the encoded value in // the form N:immr:imms. static uint32_t genimm(uint64_t imm, uint32_t regsize, uint32_t * encoded) { // First, determine the element size. uint32_t size = regsize; do { size /= 2; uint64_t mask = (1ULL << size) - 1; if ((imm & mask) != ((imm >> size) & mask)) { size *= 2; break; } } while (size > 2); // Second, determine the rotation to make the element be: 0^m 1^n. uint32_t trailing_one, trailing_zero; uint64_t mask = ((uint64_t)-1LL) >> (64 - size); imm &= mask; if (is_shifted_mask(imm)) { trailing_zero = count_trailing_zeros(imm); assert(trailing_zero < 64); trailing_one = count_trailing_zeros(~(imm >> trailing_zero)); } else { imm |= ~mask; if (!is_shifted_mask(~imm)) return 0; uint32_t leading_one = count_leading_zeros(~imm); trailing_zero = 64 - leading_one; trailing_one = leading_one + count_trailing_zeros(~imm) - (64 - size); } // Encode in immr the number of RORs it would take to get *from* 0^m 1^n // to our target value, where trailing_zero is the number of RORs to go the opposite // direction. assert(size > trailing_zero); uint32_t immr = (size - trailing_zero) & (size - 1); // If size has a 1 in the n'th bit, create a value that has zeroes in // bits [0, n] and ones above that. uint64_t Nimms = ~(size-1) << 1; // Or the trailing_one value into the low bits, which must be below the Nth bit // bit mentioned above. Nimms |= (trailing_one-1); // Extract the seventh bit and toggle it to create the N field. uint32_t N = ((Nimms >> 6) & 1) ^ 1; *encoded = (N << 12) | (immr << 6) | (Nimms & 0x3f); return 1; } static void emit_loadlp(uintptr_t addr,u_int rt) { add_literal((uintptr_t)out,addr); output_w32(0x58000000|rt); } static void emit_mov(int rs,int rt) { assem_debug("mov %s,%s",regname[rt],regname[rs]); output_w32(0x2a000000|rs<<16|WZR<<5|rt); } static void emit_mov64(int rs,int rt) { assem_debug("mov %s,%s",regname64[rt],regname64[rs]); output_w32(0xaa000000|rs<<16|WZR<<5|rt); } static void emit_add(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x0b000000|rs2<<16|rs1<<5|rt); } static void emit_adds(int rs1,int rs2,int rt) { assem_debug("adds %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x2b000000|rs2<<16|rs1<<5|rt); } static void emit_adc(int rs1,int rs2,int rt) { assem_debug("adc %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x1a000000|rs2<<16|rs1<<5|rt); } static void emit_sub(int rs1,int rs2,int rt) { assem_debug("sub %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x4b000000|rs2<<16|rs1<<5|rt); } static void emit_subs(int rs1,int rs2,int rt) { assem_debug("subs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x6b000000|rs2<<16|rs1<<5|rt); } static void emit_sbc(int rs1,int rs2,int rt) { assem_debug("sbc %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x5a000000|rs2<<16|rs1<<5|rt); } static void emit_sbcs(int rs1,int rs2,int rt) { assem_debug("sbcs %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x7a000000|rs2<<16|rs1<<5|rt); } static void emit_neg(int rs, int rt) { assem_debug("neg %s,%s",regname[rt],regname[rs]); output_w32(0x4b000000|rs<<16|WZR<<5|rt); } static void emit_negs(int rs, int rt) { assem_debug("negs %s,%s",regname[rt],regname[rs]); output_w32(0x6b000000|rs<<16|WZR<<5|rt); } static void emit_rscimm(int rs,int imm,u_int rt) { assert(imm==0); assem_debug("ngc %s,%s",regname[rt],regname[rs]); output_w32(0x5a000000|rs<<16|WZR<<5|rt); } static void emit_zeroreg(int rt) { assem_debug("movz %s,#0",regname[rt]); output_w32(0x52800000|rt); } static void emit_zeroreg64(int rt) { assem_debug("movz %s,#0",regname64[rt]); output_w32(0xd2800000|rt); } static void emit_movz(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movz %s,#%d",regname[rt],imm); output_w32(0x52800000|imm<<5|rt); } static void emit_movz_lsl16(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movz %s, #%d, lsl #%d",regname[rt],imm,16); output_w32(0x52a00000|imm<<5|rt); } static void emit_movn(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movn %s,#%d",regname[rt],imm); output_w32(0x12800000|imm<<5|rt); } static void emit_movn_lsl16(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movn %s, #%d, lsl #%d",regname[rt],imm,16); output_w32(0x12a00000|imm<<5|rt); } static void emit_movk(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movk %s,#%d",regname[rt],imm); output_w32(0x72800000|imm<<5|rt); } static void emit_movk_lsl16(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movk %s, #%d, lsl #%d",regname[rt],imm,16); output_w32(0x72a00000|imm<<5|rt); } static void emit_movz64(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movz %s,#%d",regname64[rt],imm); output_w32(0xd2800000|imm<<5|rt); } static void emit_movz64_lsl16(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movz %s, #%d, lsl #%d",regname64[rt],imm,16); output_w32(0xd2a00000|imm<<5|rt); } static void emit_movz64_lsl32(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movz %s, #%d, lsl #%d",regname64[rt],imm,32); output_w32(0xd2c00000|imm<<5|rt); } static void emit_movz64_lsl48(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movz %s, #%d, lsl #%d",regname64[rt],imm,48); output_w32(0xd2e00000|imm<<5|rt); } static void emit_movn64(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movn %s,#%d",regname64[rt],imm); output_w32(0x92800000|imm<<5|rt); } static void emit_movn64_lsl16(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movn %s, #%d, lsl #%d",regname64[rt],imm,16); output_w32(0x92a00000|imm<<5|rt); } static void emit_movn64_lsl32(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movn %s, #%d, lsl #%d",regname64[rt],imm,32); output_w32(0x92c00000|imm<<5|rt); } static void emit_movn64_lsl48(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movn %s, #%d, lsl #%d",regname64[rt],imm,48); output_w32(0x92e00000|imm<<5|rt); } static void emit_movk64(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movk %s,#%d",regname64[rt],imm); output_w32(0xf2800000|imm<<5|rt); } static void emit_movk64_lsl16(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movk %s, #%d, lsl #%d",regname64[rt],imm,16); output_w32(0xf2a00000|imm<<5|rt); } static void emit_movk64_lsl32(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movk %s, #%d, lsl #%d",regname64[rt],imm,32); output_w32(0xf2c00000|imm<<5|rt); } static void emit_movk64_lsl48(u_int imm,u_int rt) { assert(imm<65536); assem_debug("movk %s, #%d, lsl #%d",regname64[rt],imm,48); output_w32(0xf2e00000|imm<<5|rt); } static void emit_movimm(u_int imm,u_int rt) { uint32_t armval=0; if(imm<65536) { emit_movz(imm,rt); }else if((~imm)<65536) { emit_movn(~imm,rt); }else if((imm&0xffff)==0) { emit_movz_lsl16((imm>>16)&0xffff,rt); }else if(((~imm)&0xffff)==0) { emit_movn_lsl16((~imm>>16)&0xffff,rt); }else if(genimm((uint64_t)imm,32,&armval)) { assem_debug("orr %s, wzr, #%d (0x%x)",regname[rt],imm,imm); output_w32(0x32000000|armval<<10|WZR<<5|rt); }else{ emit_movz_lsl16((imm>>16)&0xffff,rt); emit_movk(imm&0xffff,rt); } } static void emit_loadreg(int r, int hr) { if((r&63)==0) emit_zeroreg(hr); else if(r==MMREG) emit_movimm(fp_memory_map>>3,hr); else if(r==INVCP||r==ROREG){ u_int offset=0; if(r==INVCP) offset=fp_invc_ptr; if(r==ROREG) offset=fp_ram_offset; assert(offset<4096); assert(offset%8 == 0); /* 8 bytes aligned */ assem_debug("ldr %s,fp+%d",regname[hr],offset); output_w32(0xf9400000|((offset>>3)<<10)|(FP<<5)|hr); } else { u_int offset = fp_regs+((r&63)<<3)+((r&64)>>4); if((r&63)==HIREG) offset=fp_hi+((r&64)>>4); if((r&63)==LOREG) offset=fp_lo+((r&64)>>4); if(r==CCREG) offset=fp_cycle_count; if(r==CSREG) offset=fp_cp0_regs(CP0_STATUS_REG); if(r==FSREG) offset=fp_fcr31; assert(offset<4096); assert(offset%4 == 0); /* 4 bytes aligned */ assem_debug("ldr %s,fp+%d",regname[hr],offset); output_w32(0xb9400000|((offset>>2)<<10)|(FP<<5)|hr); } } static void emit_storereg(int r, int hr) { u_int offset = fp_regs+((r&63)<<3)+((r&64)>>4); if((r&63)==HIREG) offset=fp_hi+((r&64)>>4); if((r&63)==LOREG) offset=fp_lo+((r&64)>>4); if(r==CCREG) offset=fp_cycle_count; if(r==FSREG) offset=fp_fcr31; assert((r&63)!=CSREG); assert((r&63)!=0); assert((r&63)<=CCREG); assert(offset<4096); assert(offset%4 == 0); /* 4 bytes aligned */ assem_debug("str %s,fp+%d",regname[hr],offset); output_w32(0xb9000000|((offset>>2)<<10)|(FP<<5)|hr); } static void emit_test(int rs, int rt) { assem_debug("tst %s,%s",regname[rs],regname[rt]); output_w32(0x6a000000|rt<<16|rs<<5|WZR); } static void emit_test64(int rs, int rt) { assem_debug("tst %s,%s",regname64[rs],regname64[rt]); output_w32(0xea000000|rt<<16|rs<<5|WZR); } static void emit_testimm(int rs,int imm) { u_int armval, ret; assem_debug("tst %s,#%d",regname[rs],imm); ret=genimm(imm,32,&armval); assert(ret); output_w32(0x72000000|armval<<10|rs<<5|WZR); } static void emit_testimm64(int rs,int64_t imm) { u_int armval, ret; assem_debug("tst %s,#%d",regname64[rs],imm); ret=genimm(imm,64,&armval); assert(ret); output_w32(0xf2000000|armval<<10|rs<<5|WZR); } static void emit_not(int rs,int rt) { assem_debug("mvn %s,%s",regname[rt],regname[rs]); output_w32(0x2a200000|rs<<16|WZR<<5|rt); } static void emit_and(u_int rs1,u_int rs2,u_int rt) { assem_debug("and %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x0a000000|rs2<<16|rs1<<5|rt); } static void emit_or(u_int rs1,u_int rs2,u_int rt) { assem_debug("orr %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x2a000000|rs2<<16|rs1<<5|rt); } static void emit_orr64(u_int rs1,u_int rs2,u_int rt) { assem_debug("orr %s,%s,%s",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0xaa000000|rs2<<16|rs1<<5|rt); } static void emit_xor(u_int rs1,u_int rs2,u_int rt) { assem_debug("eor %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x4a000000|rs2<<16|rs1<<5|rt); } static void emit_addimm64(u_int rs,int imm,u_int rt) { assert(imm>=0&&imm<4096); assem_debug("add %s, %s, #%d",regname64[rt],regname64[rs],imm); output_w32(0x91000000|imm<<10|rs<<5|rt); } static void emit_addimm(u_int rs,int imm,u_int rt) { if(imm!=0) { assert(imm>-65536&&imm<65536); //assert(imm>-16777216&&imm<16777216); if(imm<0&&imm>-4096) { assem_debug("sub %s, %s, #%d",regname[rt],regname[rs],-imm&0xfff); output_w32(0x51000000|((-imm)&0xfff)<<10|rs<<5|rt); }else if(imm>0&&imm<4096) { assem_debug("add %s, %s, #%d",regname[rt],regname[rs],imm&0xfff); output_w32(0x11000000|(imm&0xfff)<<10|rs<<5|rt); }else if(imm<0) { assem_debug("sub %s, %s, #%d lsl #%d",regname[rt],regname[rt],((-imm)>>12)&0xfff,12); output_w32(0x51400000|(((-imm)>>12)&0xfff)<<10|rs<<5|rt); if((-imm&0xfff)!=0) { assem_debug("sub %s, %s, #%d",regname[rt],regname[rs],(-imm&0xfff)); output_w32(0x51000000|((-imm)&0xfff)<<10|rt<<5|rt); } }else { assem_debug("add %s, %s, #%d lsl #%d",regname[rt],regname[rt],(imm>>12)&0xfff,12); output_w32(0x11400000|((imm>>12)&0xfff)<<10|rs<<5|rt); if((imm&0xfff)!=0) { assem_debug("add %s, %s, #%d",regname[rt],regname[rs],imm&0xfff); output_w32(0x11000000|(imm&0xfff)<<10|rt<<5|rt); } } } else if(rs!=rt) emit_mov(rs,rt); } static void emit_addimm_and_set_flags(int imm,int rt) { assert(imm>-65536&&imm<65536); //assert(imm>-16777216&&imm<16777216); if(imm<0&&imm>-4096) { assem_debug("subs %s, %s, #%d",regname[rt],regname[rt],-imm&0xfff); output_w32(0x71000000|((-imm)&0xfff)<<10|rt<<5|rt); }else if(imm>0&&imm<4096) { assem_debug("adds %s, %s, #%d",regname[rt],regname[rt],imm&0xfff); output_w32(0x31000000|(imm&0xfff)<<10|rt<<5|rt); }else if(imm<0) { if((-imm&0xfff)!=0) { assem_debug("sub %s, %s, #%d lsl #%d",regname[rt],regname[rt],((-imm)>>12)&0xfff,12); output_w32(0x51400000|(((-imm)>>12)&0xfff)<<10|rt<<5|rt); assem_debug("subs %s, %s, #%d",regname[rt],regname[rt],(-imm&0xfff)); output_w32(0x71000000|((-imm)&0xfff)<<10|rt<<5|rt); }else{ assem_debug("subs %s, %s, #%d lsl #%d",regname[rt],regname[rt],((-imm)>>12)&0xfff,12); output_w32(0x71400000|(((-imm)>>12)&0xfff)<<10|rt<<5|rt); } }else { if((imm&0xfff)!=0) { assem_debug("add %s, %s, #%d lsl #%d",regname[rt],regname[rt],(imm>>12)&0xfff,12); output_w32(0x11400000|((imm>>12)&0xfff)<<10|rt<<5|rt); assem_debug("adds %s, %s, #%d",regname[rt],regname[rt],imm&0xfff); output_w32(0x31000000|(imm&0xfff)<<10|rt<<5|rt); }else{ assem_debug("adds %s, %s, #%d lsl #%d",regname[rt],regname[rt],(imm>>12)&0xfff,12); output_w32(0x31400000|((imm>>12)&0xfff)<<10|rt<<5|rt); } } } #ifndef RAM_OFFSET static void emit_addimm_no_flags(u_int imm,u_int rt) { assert(0); } #endif static void emit_addnop(u_int r) { assem_debug("nop"); output_w32(0xd503201f); /*assem_debug("add %s,%s,#0 (nop)",regname[r],regname[r]); output_w32(0x11000000|r<<5|r);*/ } static void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) { if(imm<0&&imm>-4096) { assem_debug("subs %s, %s, #%d",regname[rtl],regname[rsl],-imm&0xfff); output_w32(0x71000000|((-imm)&0xfff)<<10|rsl<<5|rtl); emit_sbc(rsh,WZR,rth); }else if(imm>0&&imm<4096) { assem_debug("adds %s, %s, #%d",regname[rtl],regname[rsl],imm&0xfff); output_w32(0x31000000|(imm&0xfff)<<10|rsl<<5|rtl); emit_adc(rsh,WZR,rth); }else if(imm<0) { assert(rsl!=HOST_TEMPREG); emit_movimm(-imm,HOST_TEMPREG); emit_subs(rsl,HOST_TEMPREG,rtl); emit_sbc(rsh,WZR,rth); }else if(imm>0) { assert(rsl!=HOST_TEMPREG); emit_movimm(imm,HOST_TEMPREG); emit_adds(rsl,HOST_TEMPREG,rtl); emit_adc(rsh,WZR,rth); } else { assert(imm==0); if(rsl!=rtl) { assert(rsh!=rth); emit_mov(rsl,rtl); emit_mov(rsh,rth); } } } #ifdef INVERTED_CARRY static void emit_sbb(int rs1,int rs2) { assert(0); } static void emit_adcimm(u_int rs,int imm,u_int rt) { assert(0); } #endif static void emit_andimm(int rs,int imm,int rt) { u_int armval; if(imm==0) { emit_zeroreg(rt); }else if(genimm((uint64_t)imm,32,&armval)) { assem_debug("and %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x12000000|armval<<10|rs<<5|rt); }else{ assert(rs!=HOST_TEMPREG); assert(imm>0&&imm<65535); emit_movz(imm,HOST_TEMPREG); assem_debug("and %s,%s,%s",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0x0a000000|HOST_TEMPREG<<16|rs<<5|rt); } } static void emit_andimm64(int rs,int64_t imm,int rt) { u_int armval; uint32_t ret=genimm((uint64_t)imm,64,&armval); assert(ret); assem_debug("and %s,%s,#%d",regname64[rt],regname64[rs],imm); output_w32(0x92000000|armval<<10|rs<<5|rt); } static void emit_orimm(int rs,int imm,int rt) { u_int armval; if(imm==0) { if(rs!=rt) emit_mov(rs,rt); }else if(genimm(imm,32,&armval)) { assem_debug("orr %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x32000000|armval<<10|rs<<5|rt); }else{ assert(rs!=HOST_TEMPREG); assert(imm>0&&imm<65536); emit_movz(imm,HOST_TEMPREG); assem_debug("orr %s,%s,%s",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0x2a000000|HOST_TEMPREG<<16|rs<<5|rt); } } static void emit_xorimm(int rs,int imm,int rt) { u_int armval; if(imm==0) { if(rs!=rt) emit_mov(rs,rt); }else if(genimm((uint64_t)imm,32,&armval)) { assem_debug("eor %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x52000000|armval<<10|rs<<5|rt); }else{ assert(rs!=HOST_TEMPREG); assert(imm>0&&imm<65536); emit_movz(imm,HOST_TEMPREG); assem_debug("eor %s,%s,%s",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0x4a000000|HOST_TEMPREG<<16|rs<<5|rt); } } static void emit_shlimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); //if(imm==1) ... assem_debug("lsl %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x53000000|((31-imm)+1)<<16|(31-imm)<<10|rs<<5|rt); } static void emit_shlimm64(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<64); assem_debug("lsl %s,%s,#%d",regname64[rt],regname64[rs],imm); output_w32(0xd3400000|((63-imm)+1)<<16|(63-imm)<<10|rs<<5|rt); } static void emit_shrimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("lsr %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x53000000|imm<<16|0x1f<<10|rs<<5|rt); } static void emit_shrimm64(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<64); assem_debug("lsr %s,%s,#%d",regname64[rt],regname64[rs],imm); output_w32(0xd3400000|imm<<16|0x3f<<10|rs<<5|rt); } static void emit_sarimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("asr %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x13000000|imm<<16|0x1f<<10|rs<<5|rt); } static void emit_rorimm(int rs,u_int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("ror %s,%s,#%d",regname[rt],regname[rs],imm); output_w32(0x13800000|rs<<16|imm<<10|rs<<5|rt); } static void emit_shl(u_int rs,u_int shift,u_int rt) { //if(imm==1) ... assem_debug("lsl %s,%s,%s",regname[rt],regname[rs],regname[shift]); output_w32(0x1ac02000|shift<<16|rs<<5|rt); } static void emit_shl64(u_int rs,u_int shift,u_int rt) { //if(imm==1) ... assem_debug("lsl %s,%s,%s",regname64[rt],regname64[rs],regname64[shift]); output_w32(0x9ac02000|shift<<16|rs<<5|rt); } static void emit_shr(u_int rs,u_int shift,u_int rt) { assem_debug("lsr %s,%s,%s",regname[rt],regname[rs],regname[shift]); output_w32(0x1ac02400|shift<<16|rs<<5|rt); } static void emit_shr64(u_int rs,u_int shift,u_int rt) { assem_debug("lsr %s,%s,%s",regname64[rt],regname64[rs],regname64[shift]); output_w32(0x9ac02400|shift<<16|rs<<5|rt); } static void emit_sar(u_int rs,u_int shift,u_int rt) { assem_debug("asr %s,%s,%s",regname[rt],regname[rs],regname[shift]); output_w32(0x1ac02800|shift<<16|rs<<5|rt); } static void emit_sar64(u_int rs,u_int shift,u_int rt) { assem_debug("asr %s,%s,%s",regname64[rt],regname64[rs],regname64[shift]); output_w32(0x9ac02800|shift<<16|rs<<5|rt); } static void emit_orrshlimm(u_int rs,int imm,u_int rt) { assert(imm<32); assem_debug("orr %s,%s,%s,lsl #%d",regname[rt],regname[rt],regname[rs],imm); output_w32(0x2a000000|rs<<16|imm<<10|rt<<5|rt); } static void emit_orrshlimm64(u_int rs,int imm,u_int rt) { assert(imm<64); assem_debug("orr %s,%s,%s,lsl #%d",regname64[rt],regname64[rt],regname64[rs],imm); output_w32(0xaa000000|rs<<16|imm<<10|rt<<5|rt); } static void emit_orrshrimm(u_int rs,int imm,u_int rt) { assert(imm<32); assem_debug("orr %s,%s,%s,lsr #%d",regname[rt],regname[rt],regname[rs],imm); output_w32(0x2a400000|rs<<16|imm<<10|rt<<5|rt); } static void emit_shldimm(int rs,int rs2,u_int imm,int rt) { assem_debug("shld %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); assert(imm<32); //if(imm==1) ... emit_shlimm(rs,imm,rt); emit_orrshrimm(rs2,32-imm,rt); } static void emit_shrdimm(int rs,int rs2,u_int imm,int rt) { assem_debug("shrd %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); assert(imm<32); //if(imm==1) ... emit_shrimm(rs,imm,rt); emit_orrshlimm(rs2,32-imm,rt); } static void emit_cmpimm(int rs,int imm) { if(imm<0&&imm>-4096) { assem_debug("cmn %s,#%d",regname[rs],-imm&0xfff); output_w32(0x31000000|((-imm)&0xfff)<<10|rs<<5|WZR); }else if(imm>0&&imm<4096) { assem_debug("cmp %s,#%d",regname[rs],imm&0xfff); output_w32(0x71000000|(imm&0xfff)<<10|rs<<5|WZR); }else if(imm<0) { if((-imm&0xfff)==0) { assem_debug("cmn %s,#%d,lsl #12",regname[rs],-imm&0xfff); output_w32(0x31400000|((-imm>>12)&0xfff)<<10|rs<<5|WZR); }else{ assert(rs!=HOST_TEMPREG); assert(imm>-65536); emit_movz(-imm,HOST_TEMPREG); assem_debug("cmn %s,%s",regname[rs],regname[HOST_TEMPREG]); output_w32(0x2b000000|HOST_TEMPREG<<16|rs<<5|WZR); } }else { if((imm&0xfff)==0) { assem_debug("cmp %s,#%d,lsl #12",regname[rs],imm&0xfff); output_w32(0x71400000|((imm>>12)&0xfff)<<10|rs<<5|WZR); }else{ assert(rs!=HOST_TEMPREG); assert(imm<65536); emit_movz(imm,HOST_TEMPREG); assem_debug("cmp %s,%s",regname[rs],regname[HOST_TEMPREG]); output_w32(0x6b000000|HOST_TEMPREG<<16|rs<<5|WZR); } } } static void emit_cmovne_imm(int imm,int rt) { assert(imm==0||imm==1); if(imm){ assem_debug("csinc %s,%s,%s,eq",regname[rt],regname[rt],regname[WZR]); output_w32(0x1a800400|WZR<<16|COND_EQ<<12|rt<<5|rt); }else{ assem_debug("csel %s,%s,%s,ne",regname[rt],regname[WZR],regname[rt]); output_w32(0x1a800000|rt<<16|COND_NE<<12|WZR<<5|rt); } } static void emit_cmovl_imm(int imm,int rt) { assert(imm==0||imm==1); if(imm){ assem_debug("csinc %s,%s,%s,ge",regname[rt],regname[rt],regname[WZR]); output_w32(0x1a800400|WZR<<16|COND_GE<<12|rt<<5|rt); }else{ assem_debug("csel %s,%s,%s,lt",regname[rt],regname[WZR],regname[rt]); output_w32(0x1a800000|rt<<16|COND_LT<<12|WZR<<5|rt); } } static void emit_cmovb_imm(int imm,int rt) { assert(imm==0||imm==1); if(imm){ assem_debug("csinc %s,%s,%s,cs",regname[rt],regname[rt],regname[WZR]); output_w32(0x1a800400|WZR<<16|COND_CS<<12|rt<<5|rt); }else{ assem_debug("csel %s,%s,%s,cc",regname[rt],regname[WZR],regname[rt]); output_w32(0x1a800000|rt<<16|COND_CC<<12|WZR<<5|rt); } } static void emit_cmovs_imm(int imm,int rt) { assert(imm==0||imm==1); if(imm){ assem_debug("csinc %s,%s,%s,pl",regname[rt],regname[rt],regname[WZR]); output_w32(0x1a800400|WZR<<16|COND_PL<<12|rt<<5|rt); }else{ assem_debug("csel %s,%s,%s,mi",regname[rt],regname[WZR],regname[rt]); output_w32(0x1a800000|rt<<16|COND_MI<<12|WZR<<5|rt); } } static void emit_cmove_reg(int rs,int rt) { assem_debug("csel %s,%s,%s,eq",regname[rt],regname[rs],regname[rt]); output_w32(0x1a800000|rt<<16|COND_EQ<<12|rs<<5|rt); } static void emit_cmovne_reg(int rs,int rt) { assem_debug("csel %s,%s,%s,ne",regname[rt],regname[rs],regname[rt]); output_w32(0x1a800000|rt<<16|COND_NE<<12|rs<<5|rt); } static void emit_cmovl_reg(int rs,int rt) { assem_debug("csel %s,%s,%s,lt",regname[rt],regname[rs],regname[rt]); output_w32(0x1a800000|rt<<16|COND_LT<<12|rs<<5|rt); } static void emit_cmovs_reg(int rs,int rt) { assem_debug("csel %s,%s,%s,mi",regname[rt],regname[rs],regname[rt]); output_w32(0x1a800000|rt<<16|COND_MI<<12|rs<<5|rt); } static void emit_csel_vs(int rs1,int rs2,int rt) { assem_debug("csel %s,%s,%s,vs",regname[rt],regname[rs1],regname[rs2]); output_w32(0x1a800000|rs2<<16|COND_VS<<12|rs1<<5|rt); } static void emit_csel_eq(int rs1,int rs2,int rt) { assem_debug("csel %s,%s,%s,eq",regname[rt],regname[rs1],regname[rs2]); output_w32(0x1a800000|rs2<<16|COND_EQ<<12|rs1<<5|rt); } static void emit_csel_cc(int rs1,int rs2,int rt) { assem_debug("csel %s,%s,%s,cc",regname[rt],regname[rs1],regname[rs2]); output_w32(0x1a800000|rs2<<16|COND_CC<<12|rs1<<5|rt); } static void emit_csel_ls(int rs1,int rs2,int rt) { assem_debug("csel %s,%s,%s,ls",regname[rt],regname[rs1],regname[rs2]); output_w32(0x1a800000|rs2<<16|COND_LS<<12|rs1<<5|rt); } static void emit_slti32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_cmovl_imm(1,rt); } static void emit_sltiu32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_cmovb_imm(1,rt); } static void emit_slti64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_slti32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne_imm(0,rt); emit_cmovs_imm(1,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne_imm(0,rt); emit_cmovl_imm(1,rt); } } static void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_sltiu32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne_imm(0,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne_imm(1,rt); } } static void emit_cmp(int rs,int rt) { assem_debug("cmp %s,%s",regname[rs],regname[rt]); output_w32(0x6b000000|rt<<16|rs<<5|WZR); } static void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_cmovl_imm(0,rt); } static void emit_set_nz32(int rs, int rt) { //assem_debug("set_nz32"); if(rs!=rt) emit_mov(rs,rt); emit_test(rs,rs); emit_cmovne_imm(1,rt); } static void emit_set_gz64_32(int rsh, int rsl, int rt) { //assem_debug("set_gz64"); emit_set_gz32(rsl,rt); emit_test(rsh,rsh); emit_cmovne_imm(1,rt); emit_cmovs_imm(0,rt); } static void emit_set_nz64_32(int rsh, int rsl, int rt) { //assem_debug("set_nz64"); emit_or(rsh,rsl,rt); emit_test(rt,rt); emit_cmovne_imm(1,rt); } static void emit_set_if_less32(int rs1, int rs2, int rt) { //assem_debug("set if less (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovl_imm(1,rt); } static void emit_set_if_carry32(int rs1, int rs2, int rt) { //assem_debug("set if carry (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovb_imm(1,rt); } static void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_movimm(0,rt); emit_sbcs(u1,u2,HOST_TEMPREG); emit_cmovl_imm(1,rt); } static void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_movimm(0,rt); emit_sbcs(u1,u2,HOST_TEMPREG); emit_cmovb_imm(1,rt); } static void emit_call(intptr_t a) { assem_debug("bl %x (%x+%x)",a,(intptr_t)out,a-(intptr_t)out); u_int offset=genjmp(a); output_w32(0x94000000|offset); } static void emit_jmp(intptr_t a) { assem_debug("b %x (%x+%x)",a,(intptr_t)out,a-(intptr_t)out); u_int offset=genjmp(a); output_w32(0x14000000|offset); } static void emit_jne(intptr_t a) { assem_debug("bne %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_NE); } static void emit_jeq(intptr_t a) { assem_debug("beq %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_EQ); } static void emit_js(intptr_t a) { assem_debug("bmi %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_MI); } static void emit_jns(intptr_t a) { assem_debug("bpl %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_PL); } static void emit_jl(intptr_t a) { assem_debug("blt %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_LT); } static void emit_jge(intptr_t a) { assem_debug("bge %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_GE); } static void emit_jno(intptr_t a) { assem_debug("bvc %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_VC); } static void emit_jcc(intptr_t a) { assem_debug("bcc %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_CC); } static void emit_jae(intptr_t a) { assem_debug("bcs %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_CS); } static void emit_jb(intptr_t a) { assem_debug("bcc %x",a); u_int offset=gencondjmp(a); output_w32(0x54000000|offset<<5|COND_CC); } static void emit_pushreg(u_int r) { assert(0); } static void emit_popreg(u_int r) { assert(0); } static void emit_jmpreg(u_int r) { assem_debug("br %s",regname64[r]); output_w32(0xd61f0000|r<<5); } static void emit_readword_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldur %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0xb8400000|((u_int)offset&0x1ff)<<12|rs<<5|rt); } static void emit_readdword_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldur %s,%s+%d",regname64[rt],regname64[rs],offset); output_w32(0xf8400000|((u_int)offset&0x1ff)<<12|rs<<5|rt); } static void emit_readword_dualindexedx4(int rs1, int rs2, int rt) { assem_debug("ldr %s, [%s,%s lsl #2]",regname[rt],regname64[rs1],regname64[rs2]); output_w32(0xb8607800|rs2<<16|rs1<<5|rt); } static void emit_readdword_dualindexedx8(int rs1, int rs2, int rt) { assem_debug("ldr %s, [%s,%s lsl #3]",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0xf8607800|rs2<<16|rs1<<5|rt); } static void emit_readword_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_readword_indexed(addr, rs, rt); else { assert(addr==0); emit_readword_dualindexedx4(rs, map, rt); } } static void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl) { assert(map>=0); if(map<0) { if(rh>=0) emit_readword_indexed(addr, rs, rh); emit_readword_indexed(addr+4, rs, rl); }else{ assert(rh!=rs); if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh); emit_addimm64(map,1,HOST_TEMPREG); emit_readword_indexed_tlb(addr, rs, HOST_TEMPREG, rl); } } static void emit_movsbl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldursb %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0x38c00000|((u_int)offset&0x1ff)<<12|rs<<5|rt); } static void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_movsbl_indexed(addr, rs, rt); else { if(addr==0) { emit_shlimm64(map,2,HOST_TEMPREG); assem_debug("ldrsb %s,[%s,%s]",regname[rt],regname64[rs],regname64[HOST_TEMPREG]); output_w32(0x38e06800|HOST_TEMPREG<<16|rs<<5|rt); }else{ assem_debug("add %s,%s,%s,lsl #2",regname64[rt],regname64[rs],regname64[map]); output_w32(0x8b000000|map<<16|2<<10|rs<<5|rt); emit_movsbl_indexed(addr, rt, rt); } } } static void emit_movswl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldursh %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0x78c00000|((u_int)offset&0x1ff)<<12|rs<<5|rt); } static void emit_movswl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_movswl_indexed(addr, rs, rt); else { if(addr==0) { emit_shlimm64(map,2,HOST_TEMPREG); assem_debug("ldrsh %s,[%s,%s]",regname[rt],regname64[rs],regname64[HOST_TEMPREG]); output_w32(0x78e06800|HOST_TEMPREG<<16|rs<<5|rt); }else{ assem_debug("add %s,%s,%s,lsl #2",regname64[rt],regname64[rs],regname64[map]); output_w32(0x8b000000|map<<16|2<<10|rs<<5|rt); emit_movswl_indexed(addr, rt, rt); } } } static void emit_movzbl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldurb %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0x38400000|((u_int)offset&0x1ff)<<12|rs<<5|rt); } static void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_movzbl_indexed(addr, rs, rt); else { if(addr==0) { emit_shlimm64(map,2,HOST_TEMPREG); assem_debug("ldrb %s,[%s,%s]",regname[rt],regname64[rs],regname64[HOST_TEMPREG]); output_w32(0x38606800|HOST_TEMPREG<<16|rs<<5|rt); }else{ assem_debug("add %s,%s,%s,lsl #2",regname64[rt],regname64[rs],regname64[map]); output_w32(0x8b000000|map<<16|2<<10|rs<<5|rt); emit_movzbl_indexed(addr, rt, rt); } } } static void emit_movzwl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldurh %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0x78400000|((u_int)offset&0x1ff)<<12|rs<<5|rt); } static void emit_movzwl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_movzwl_indexed(addr, rs, rt); else { if(addr==0) { emit_shlimm64(map,2,HOST_TEMPREG); assem_debug("ldrh %s,[%s,%s]",regname[rt],regname64[rs],regname64[HOST_TEMPREG]); output_w32(0x78606800|HOST_TEMPREG<<16|rs<<5|rt); }else{ assem_debug("add %s,%s,%s,lsl #2",regname64[rt],regname64[rs],regname64[map]); output_w32(0x8b000000|map<<16|2<<10|rs<<5|rt); emit_movzwl_indexed(addr, rt, rt); } } } static void emit_readword(intptr_t addr, int rt) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<16380LL); assert(offset%4 == 0); /* 4 bytes aligned */ assem_debug("ldr %s,fp+%d",regname[rt],offset); output_w32(0xb9400000|((offset>>2)<<10)|(FP<<5)|rt); } static void emit_readdword(intptr_t addr, int rt) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<32760LL); assert(offset%8 == 0); /* 8 bytes aligned */ assem_debug("ldr %s,fp+%d",regname64[rt],offset); output_w32(0xf9400000|((offset>>3)<<10)|(FP<<5)|rt); } static void emit_readptr(intptr_t addr, int rt) { emit_readdword(addr,rt); } static void emit_movsbl(int addr, int rt) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<4096LL); assem_debug("ldrsb %s,fp+%d",regname[rt],offset); output_w32(0x39800000|offset<<10|FP<<5|rt); } static void emit_movswl(int addr, int rt) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<8190LL); assert(offset%2 == 0); /* 2 bytes aligned */ assem_debug("ldrsh %s,fp+%d",regname[rt],offset); output_w32(0x79800000|((offset>>1)<<10)|(FP<<5)|rt); } static void emit_movzbl(intptr_t addr, int rt) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<4096LL); assem_debug("ldrb %s,fp+%d",regname[rt],offset); output_w32(0x39400000|offset<<10|FP<<5|rt); } static void emit_movzwl(int addr, int rt) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<8190LL); assert(offset%2 == 0); /* 2 bytes aligned */ assem_debug("ldrh %s,fp+%d",regname[rt],offset); output_w32(0x79400000|((offset>>1)<<10)|(FP<<5)|rt); } static void emit_writeword_indexed(int rt, int offset, int rs) { assert(offset>-256&&offset<256); assem_debug("stur %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0xb8000000|(((u_int)offset)&0x1ff)<<12|rs<<5|rt); } static void emit_writedword_indexed(int rt, int offset, int rs) { assert(offset>-256&&offset<256); assem_debug("stur %s,%s+%d",regname64[rt],regname64[rs],offset); output_w32(0xf8000000|(((u_int)offset)&0x1ff)<<12|rs<<5|rt); } static void emit_writeword_dualindexedx4(int rt, int rs1, int rs2) { assem_debug("str %s,[%s,%s lsl #2]",regname[rt],regname64[rs1],regname64[rs2]); output_w32(0xb8207800|rs2<<16|rs1<<5|rt); } static void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writeword_indexed(rt, addr, rs); else { if(addr==0) { emit_writeword_dualindexedx4(rt, rs, map); }else{ assem_debug("add %s,%s,%s,lsl #2",regname64[HOST_TEMPREG],regname64[rs],regname64[map]); output_w32(0x8b000000|map<<16|2<<10|rs<<5|HOST_TEMPREG); emit_writeword_indexed(rt,addr,HOST_TEMPREG); } } } static void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map) { //emit_writeword_indexed_tlb modifies HOST_TEMPREG when addr!=0 if(map==HOST_TEMPREG) assert(addr==0); assert(map>=0); assert(rh>=0); emit_writeword_indexed_tlb(rh, addr, rs, map); emit_writeword_indexed_tlb(rl, addr+4, rs, map); } static void emit_writehword_indexed(int rt, int offset, int rs) { assert(offset>-256&&offset<256); assem_debug("sturh %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0x78000000|(((u_int)offset)&0x1ff)<<12|rs<<5|rt); } static void emit_writehword_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writehword_indexed(rt, addr, rs); else { if(addr==0) { emit_shlimm64(map,2,HOST_TEMPREG); assem_debug("strh %s,[%s,%s]",regname[rt],regname64[rs],regname64[HOST_TEMPREG]); output_w32(0x78206800|HOST_TEMPREG<<16|rs<<5|rt); }else{ assem_debug("add %s,%s,%s,lsl #2",regname64[HOST_TEMPREG],regname64[rs],regname64[map]); output_w32(0x8b000000|map<<16|2<<10|rs<<5|HOST_TEMPREG); emit_writehword_indexed(rt,addr,HOST_TEMPREG); } } } static void emit_writebyte_indexed(int rt, int offset, int rs) { assert(offset>-256&&offset<256); assem_debug("sturb %s,%s+%d",regname[rt],regname64[rs],offset); output_w32(0x38000000|(((u_int)offset)&0x1ff)<<12|rs<<5|rt); } static void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writebyte_indexed(rt, addr, rs); else { if(addr==0) { emit_shlimm64(map,2,HOST_TEMPREG); assem_debug("strb %s,[%s,%s]",regname[rt],regname64[rs],regname64[HOST_TEMPREG]); output_w32(0x38206800|HOST_TEMPREG<<16|rs<<5|rt); }else{ assem_debug("add %s,%s,%s,lsl #2",regname64[HOST_TEMPREG],regname64[rs],regname64[map]); output_w32(0x8b000000|map<<16|2<<10|rs<<5|HOST_TEMPREG); emit_writebyte_indexed(rt,addr,HOST_TEMPREG); } } } static void emit_writeword(int rt, intptr_t addr) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<16380LL); assert(offset%4 == 0); /* 4 bytes aligned */ assem_debug("str %s,fp+%d",regname[rt],offset); output_w32(0xb9000000|((offset>>2)<<10)|(FP<<5)|rt); } static void emit_writedword(int rt, intptr_t addr) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<32760LL); assert(offset%8 == 0); /* 8 bytes aligned */ assem_debug("str %s,fp+%d",regname64[rt],offset); output_w32(0xf9000000|((offset>>3)<<10)|(FP<<5)|rt); } static void emit_writehword(int rt, int addr) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<8190LL); assert(offset%2 == 0); /* 2 bytes aligned */ assem_debug("strh %s,fp+%d",regname[rt],offset); output_w32(0x79000000|((offset>>1)<<10)|(FP<<5)|rt); } static void emit_writebyte(int rt, intptr_t addr) { intptr_t offset = addr-(intptr_t)&g_dev.r4300.new_dynarec_hot_state; assert(offset<4096LL); assem_debug("strb %s,fp+%d",regname[rt],offset); output_w32(0x39000000|offset<<10|(FP<<5)|rt); } static void emit_msub(u_int rs1,u_int rs2,u_int rs3,u_int rt) { assem_debug("msub %s,%s,%s,%s",regname[rt],regname[rs1],regname[rs2],regname[rs3]); output_w32(0x1b008000|(rs2<<16)|(rs3<<10)|(rs1<<5)|rt); } static void emit_mul64(u_int rs1,u_int rs2,u_int rt) { assem_debug("mul %s,%s,%s",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0x9b000000|(rs2<<16)|(WZR<<10)|(rs1<<5)|rt); } static void emit_msub64(u_int rs1,u_int rs2,u_int rs3,u_int rt) { assem_debug("msub %s,%s,%s,%s",regname64[rt],regname64[rs1],regname64[rs2],regname64[rs3]); output_w32(0x9b008000|(rs2<<16)|(rs3<<10)|(rs1<<5)|rt); } static void emit_umull(u_int rs1, u_int rs2, u_int rt) { assem_debug("umull %s, %s, %s",regname64[rt],regname[rs1],regname[rs2]); output_w32(0x9ba00000|(rs2<<16)|(WZR<<10)|(rs1<<5)|rt); } static void emit_umulh(u_int rs1, u_int rs2, u_int rt) { assem_debug("umulh %s, %s, %s",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0x9bc00000|(rs2<<16)|(WZR<<10)|(rs1<<5)|rt); } static void emit_smull(u_int rs1, u_int rs2, u_int rt) { assem_debug("smull %s, %s, %s",regname64[rt],regname[rs1],regname[rs2]); output_w32(0x9b200000|(rs2<<16)|(WZR<<10)|(rs1<<5)|rt); } static void emit_smulh(u_int rs1, u_int rs2, u_int rt) { assem_debug("smulh %s, %s, %s",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0x9b400000|(rs2<<16)|(WZR<<10)|(rs1<<5)|rt); } static void emit_sdiv(u_int rs1,u_int rs2,u_int rt) { assem_debug("sdiv %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x1ac00c00|(rs2<<16)|(rs1<<5)|rt); } static void emit_udiv(u_int rs1,u_int rs2,u_int rt) { assem_debug("udiv %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x1ac00800|(rs2<<16)|(rs1<<5)|rt); } static void emit_sdiv64(u_int rs1,u_int rs2,u_int rt) { assem_debug("sdiv %s,%s,%s",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0x9ac00c00|(rs2<<16)|(rs1<<5)|rt); } static void emit_udiv64(u_int rs1,u_int rs2,u_int rt) { assem_debug("udiv %s,%s,%s",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0x9ac00800|(rs2<<16)|(rs1<<5)|rt); } static void emit_bic(u_int rs1,u_int rs2,u_int rt) { assem_debug("bic %s,%s,%s",regname[rt],regname[rs1],regname[rs2]); output_w32(0x0a200000|rs2<<16|rs1<<5|rt); } static void emit_bic64(u_int rs1,u_int rs2,u_int rt) { assem_debug("bic %s,%s,%s",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0x8a200000|rs2<<16|rs1<<5|rt); } // Load 2 immediates optimizing for small code size static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2) { emit_movimm(imm1,rt1); int imm=imm2-imm1; if(imm<0&&imm>-4096) { assem_debug("sub %s, %s, #%d",regname[rt2],regname[rt1],-imm&0xfff); output_w32(0x51000000|((-imm)&0xfff)<<10|rt1<<5|rt2); }else if(imm>=0&&imm<4096) { assem_debug("add %s, %s, #%d",regname[rt2],regname[rt1],imm&0xfff); output_w32(0x11000000|(imm&0xfff)<<10|rt1<<5|rt2); }else if(imm<0&&(-imm&0xfff)==0) { assem_debug("sub %s, %s, #%d lsl #%d",regname[rt2],regname[rt1],((-imm)>>12)&0xfff,12); output_w32(0x51400000|(((-imm)>>12)&0xfff)<<10|rt1<<5|rt2); }else if(imm>=0&&(imm&0xfff)==0) { assem_debug("add %s, %s, #%d lsl #%d",regname[rt2],regname[rt1],(imm>>12)&0xfff,12); output_w32(0x11400000|((imm>>12)&0xfff)<<10|rt1<<5|rt2); } else emit_movimm(imm2,rt2); } #ifdef HAVE_CMOV_IMM // Conditionally select one of two immediates, optimizing for small code size // This will only be called if HAVE_CMOV_IMM is defined static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt) { assert(0); } #endif // special case for checking pending_exception static void emit_cmpmem_imm(intptr_t addr, int imm) { assert(imm==0); emit_readword(addr,HOST_TEMPREG); emit_test(HOST_TEMPREG,HOST_TEMPREG); } #ifndef HOST_IMM8 // special case for checking invalid_code static void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) { assert(0); } #endif // special case for checking invalid_code static void emit_cmpmem_indexedsr12_reg(int base,int r,int imm) { assert(imm<128&&imm>=0); assert(r>=0&&r<29); emit_shrimm(r,12,HOST_TEMPREG); assem_debug("ldrb %s,[%s,%s]",regname[HOST_TEMPREG],regname64[base],regname64[HOST_TEMPREG]); output_w32(0x38606800|HOST_TEMPREG<<16|base<<5|HOST_TEMPREG); emit_cmpimm(HOST_TEMPREG,imm); } // special case for tlb mapping static void emit_addsr12(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s lsr #12",regname[rt],regname[rs1],regname[rs2]); output_w32(0x0b400000|rs2<<16|12<<10|rs1<<5|rt); } static void emit_addsl2(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s lsl #2",regname64[rt],regname64[rs1],regname64[rs2]); output_w32(0x8b000000|rs2<<16|2<<10|rs1<<5|rt); } #ifdef HAVE_CONDITIONAL_CALL static void emit_callne(intptr_t a) { assert(0); } #endif #ifdef IMM_PREFETCH // Used to preload hash table entries static void emit_prefetch(void *addr) { assert(0); } #endif #ifdef REG_PREFETCH static void emit_prefetchreg(int r) { assert(0); } #endif static void emit_flds(int r,int sr) { assert((sr==30)||(sr==31)); assem_debug("ldr s%d,[%s]",sr,regname[r]); output_w32(0xbd400000|r<<5|sr); } static void emit_fldd(int r,int dr) { assert((dr==30)||(dr==31)); assem_debug("ldr d%d,[%s]",dr,regname[r]); output_w32(0xfd400000|r<<5|dr); } static void emit_fsts(int sr,int r) { assert((sr==30)||(sr==31)); assem_debug("str s%d,[%s]",sr,regname[r]); output_w32(0xbd000000|r<<5|sr); } static void emit_fstd(int dr,int r) { assert((dr==30)||(dr==31)); assem_debug("str d%d,[%s]",dr,regname[r]); output_w32(0xfd000000|r<<5|dr); } static void emit_fsqrts(int s,int d) { assert(s==31); assert(d==31); assem_debug("fsqrts s%d,s%d",d,s); output_w32(0x1e21c000|s<<5|d); } static void emit_fsqrtd(int s,int d) { assert(s==31); assert(d==31); assem_debug("fsqrtd d%d,d%d",d,s); output_w32(0x1e61c000|s<<5|d); } static void emit_fabss(int s,int d) { assert(s==31); assert(d==31); assem_debug("fabss s%d,s%d",d,s); output_w32(0x1e20c000|s<<5|d); } static void emit_fabsd(int s,int d) { assert(s==31); assert(d==31); assem_debug("fabsd d%d,d%d",d,s); output_w32(0x1e60c000|s<<5|d); } static void emit_fnegs(int s,int d) { assert(s==31); assert(d==31); assem_debug("fnegs s%d,s%d",d,s); output_w32(0x1e214000|s<<5|d); } static void emit_fnegd(int s,int d) { assert(s==31); assert(d==31); assem_debug("fnegd d%d,d%d",d,s); output_w32(0x1e614000|s<<5|d); } static void emit_fadds(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("fadds s%d,s%d,s%d",d,s1,s2); output_w32(0x1e202800|s2<<16|s1<<5|d); } static void emit_faddd(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("faddd d%d,d%d,d%d",d,s1,s2); output_w32(0x1e602800|s2<<16|s1<<5|d); } static void emit_fsubs(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("fsubs s%d,s%d,s%d",d,s1,s2); output_w32(0x1e203800|s2<<16|s1<<5|d); } static void emit_fsubd(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("fsubd d%d,d%d,d%d",d,s1,s2); output_w32(0x1e603800|s2<<16|s1<<5|d); } static void emit_fmuls(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("fmuls s%d,s%d,s%d",d,s1,s2); output_w32(0x1e200800|s2<<16|s1<<5|d); } static void emit_fmuld(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("fmuld d%d,d%d,d%d",d,s1,s2); output_w32(0x1e600800|s2<<16|s1<<5|d); } static void emit_fdivs(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("fdivs s%d,s%d,s%d",d,s1,s2); output_w32(0x1e201800|s2<<16|s1<<5|d); } static void emit_fdivd(int s1,int s2,int d) { assert(s1==31); assert((s2==30)||(s2==31)); assert(d==31); assem_debug("fdivd d%d,d%d,d%d",d,s1,s2); output_w32(0x1e601800|s2<<16|s1<<5|d); } static void emit_scvtf_s_w(int rs,int rd) { //int32_t -> float assert(rd==31); assem_debug("scvtf s%d,%s",rd,regname[rs]); output_w32(0x1e220000|rs<<5|rd); } static void emit_scvtf_d_w(int rs,int rd) { //int32_t -> double assert(rd==31); assem_debug("scvtf d%d,%s",rd,regname[rs]); output_w32(0x1e620000|rs<<5|rd); } static void emit_scvtf_s_l(int rs,int rd) { //int64_t -> float assert(rd==31); assem_debug("scvtf s%d,%s",rd,regname64[rs]); output_w32(0x9e220000|rs<<5|rd); } static void emit_scvtf_d_l(int rs,int rd) { //int64_t -> double assert(rd==31); assem_debug("scvtf d%d,%s",rd,regname64[rs]); output_w32(0x9e620000|rs<<5|rd); } static void emit_fcvt_d_s(int rs,int rd) { //float -> double assert(rs==31); assert(rd==31); assem_debug("fcvt d%d,s%d",rd,rs); output_w32(0x1e22c000|rs<<5|rd); } static void emit_fcvt_s_d(int rs,int rd) { //double -> float assert(rs==31); assert(rd==31); assem_debug("fcvt s%d,d%d",rd,rs); output_w32(0x1e624000|rs<<5|rd); } static void emit_fcvtns_l_s(int rs,int rd) { //float -> int64_t round toward nearest assert(rs==31); assem_debug("fcvtns %s,s%d,",regname64[rd],rs); output_w32(0x9e200000|rs<<5|rd); } static void emit_fcvtns_w_s(int rs,int rd) { //float -> int32_t round toward nearest assert(rs==31); assem_debug("fcvtns %s,s%d,",regname[rd],rs); output_w32(0x1e200000|rs<<5|rd); } static void emit_fcvtns_l_d(int rs,int rd) { //double -> int64_t round toward nearest assert(rs==31); assem_debug("fcvtns %s,d%d,",regname64[rd],rs); output_w32(0x9e600000|rs<<5|rd); } static void emit_fcvtns_w_d(int rs,int rd) { //double -> int32_t round toward nearest assert(rs==31); assem_debug("fcvtns %s,d%d,",regname[rd],rs); output_w32(0x1e600000|rs<<5|rd); } static void emit_fcvtzs_l_s(int rs,int rd) { //float -> int64_t round toward zero assert(rs==31); assem_debug("fcvtzs %s,s%d,",regname64[rd],rs); output_w32(0x9e380000|rs<<5|rd); } static void emit_fcvtzs_w_s(int rs,int rd) { //float -> int32_t round toward zero assert(rs==31); assem_debug("fcvtzs %s,s%d,",regname[rd],rs); output_w32(0x1e380000|rs<<5|rd); } static void emit_fcvtzs_l_d(int rs,int rd) { //double -> int64_t round toward zero assert(rs==31); assem_debug("fcvtzs %s,d%d,",regname64[rd],rs); output_w32(0x9e780000|rs<<5|rd); } static void emit_fcvtzs_w_d(int rs,int rd) { //double -> int32_t round toward zero assert(rs==31); assem_debug("fcvtzs %s,d%d,",regname[rd],rs); output_w32(0x1e780000|rs<<5|rd); } static void emit_fcvtps_l_s(int rs,int rd) { //float -> int64_t round toward +inf assert(rs==31); assem_debug("fcvtps %s,s%d,",regname64[rd],rs); output_w32(0x9e280000|rs<<5|rd); } static void emit_fcvtps_w_s(int rs,int rd) { //float -> int32_t round toward +inf assert(rs==31); assem_debug("fcvtps %s,s%d,",regname[rd],rs); output_w32(0x1e280000|rs<<5|rd); } static void emit_fcvtps_l_d(int rs,int rd) { //double -> int64_t round toward +inf assert(rs==31); assem_debug("fcvtps %s,d%d,",regname64[rd],rs); output_w32(0x9e680000|rs<<5|rd); } static void emit_fcvtps_w_d(int rs,int rd) { //double -> int32_t round toward +inf assert(rs==31); assem_debug("fcvtps %s,d%d,",regname[rd],rs); output_w32(0x1e680000|rs<<5|rd); } static void emit_fcvtms_l_s(int rs,int rd) { //float -> int64_t round toward -inf assert(rs==31); assem_debug("fcvtms %s,s%d,",regname64[rd],rs); output_w32(0x9e300000|rs<<5|rd); } static void emit_fcvtms_w_s(int rs,int rd) { //float -> int32_t round toward -inf assert(rs==31); assem_debug("fcvtms %s,s%d,",regname[rd],rs); output_w32(0x1e300000|rs<<5|rd); } static void emit_fcvtms_l_d(int rs,int rd) { //double -> int64_t round toward -inf assert(rs==31); assem_debug("fcvtms %s,d%d,",regname64[rd],rs); output_w32(0x9e700000|rs<<5|rd); } static void emit_fcvtms_w_d(int rs,int rd) { //double -> int32_t round toward -inf assert(rs==31); assem_debug("fcvtms %s,d%d,",regname[rd],rs); output_w32(0x1e700000|rs<<5|rd); } static void emit_fcmps(int x,int y) { assert(x==30); assert(y==31); assem_debug("fcmp s%d, s%d",x,y); output_w32(0x1e202000|y<<16|x<<5); } static void emit_fcmpd(int x,int y) { assert(x==30); assert(y==31); assem_debug("fcmp d%d, d%d",x,y); output_w32(0x1e602000|y<<16|x<<5); } static void emit_jno_unlikely(intptr_t a) { emit_jno(a); } static void emit_breakpoint(u_int imm) { assem_debug("brk #%d",imm); output_w32(0xd4200000|imm<<5); } static void emit_adr(intptr_t addr, int rt) { intptr_t out_rx=(intptr_t)out; if(addr<(intptr_t)base_addr||addr>=(intptr_t)base_addr+(1<=-1048576LL&&offset<1048576LL); assem_debug("adr %d,#%d",regname64[rt],offset); output_w32(0x10000000|(offset&0x3)<<29|((offset>>2)&0x7ffff)<<5|rt); } static void emit_adrp(intptr_t addr, int rt) { intptr_t out_rx=(intptr_t)out; if(addr<(intptr_t)base_addr||addr>=(intptr_t)base_addr+(1<=-4294967296LL&&offset<4294967296LL); offset>>=12; assert((((intptr_t)out_rx&~0xfffLL)+(offset<<12))==(addr&~0xfffLL)); assem_debug("adrp %d,#%d",regname64[rt],offset); output_w32(0x90000000|(offset&0x3)<<29|((offset>>2)&0x7ffff)<<5|rt); } static void emit_pc_relative_addr(intptr_t addr, int rt) { intptr_t out_rx=(intptr_t)out; if(addr<(intptr_t)base_addr||addr>=(intptr_t)base_addr+(1<=-1048576LL&&offset<1048576LL){ emit_adr(addr,rt); } else{ emit_adrp(addr,rt); if((addr&0xfffLL)!=0){ emit_addimm64(rt,(addr&0xfffLL),rt); } } } // Save registers before function call static void save_regs(u_int reglist) { signed char rt[2]; int index=0; int offset=0; reglist&=CALLER_SAVED_REGS; // only save the caller-save registers, x0-x18 if(!reglist) return; int i; for(i=0; reglist!=0; i++){ if(reglist&1){ rt[index]=i; index++; } if(index>1){ assert(offset>=0&&offset<=136); assem_debug("stp %s,%s,[fp+#%d]",regname64[rt[0]],regname64[rt[1]],offset); output_w32(0xa9000000|(offset>>3)<<15|rt[1]<<10|FP<<5|rt[0]); offset+=16; index=0; } reglist>>=1; } if(index!=0) { assert(index==1); assert(offset>=0&&offset<=144); assem_debug("str %s,[fp+#%d]",regname64[rt[0]],offset); output_w32(0xf9000000|(offset>>3)<<10|FP<<5|rt[0]); } } // Restore registers after function call static void restore_regs(u_int reglist) { signed char rt[2]; int index=0; int offset=0; reglist&=CALLER_SAVED_REGS; // only restore the caller-save registers, x0-x18 if(!reglist) return; int i; for(i=0; reglist!=0; i++){ if(reglist&1){ rt[index]=i; index++; } if(index>1){ assert(offset>=0&&offset<=136); assem_debug("ldp %s,%s,[fp+#%d]",regname[rt[0]],regname[rt[1]],offset); output_w32(0xa9400000|(offset>>3)<<15|rt[1]<<10|FP<<5|rt[0]); offset+=16; index=0; } reglist>>=1; } if(index!=0) { assert(index==1); assert(offset>=0&&offset<=144); assem_debug("ldr %s,[fp+#%d]",regname[rt[0]],offset); output_w32(0xf9400000|(offset>>3)<<10|FP<<5|rt[0]); } } /* Stubs/epilogue */ static void literal_pool(int n) { if((!literalcount)||(n!=0)) return; u_int *ptr; int i; for(i=0;i=-1048576LL&&offset<1048576LL); assert((offset&3)==0); *ptr|=((offset>>2)<<5); output_w64(literals[i][1]); } literalcount=0; } static void literal_pool_jumpover(int n) { (void)n; } static void emit_extjump2(intptr_t addr, int target, intptr_t linker) { u_char *ptr=(u_char *)addr; assert(((ptr[3]&0xfc)==0x14)||((ptr[3]&0xff)==0x54)); //b or b.cond emit_movz_lsl16(((u_int)target>>16)&0xffff,1); emit_movk((u_int)target&0xffff,1); //addr is in the current recompiled block (max 256k) //offset shouldn't exceed +/-1MB emit_adr(addr,0); emit_jmp(linker); } static void do_invstub(int n) { literal_pool(20); u_int reglist=stubs[n][3]; set_jump_target(stubs[n][1],(intptr_t)out); save_regs(reglist); if(stubs[n][4]!=0) emit_mov(stubs[n][4],0); emit_call((intptr_t)&invalidate_addr); restore_regs(reglist); emit_jmp(stubs[n][2]); // return address } static intptr_t do_dirty_stub(int i, struct ll_entry * head) { assem_debug("do_dirty_stub %x",head->vaddr); intptr_t out_rx=((intptr_t)out-(intptr_t)base_addr)+(intptr_t)base_addr_rx; intptr_t offset=(((intptr_t)head&~0xfffLL)-((intptr_t)out_rx&~0xfffLL)); if((uintptr_t)head<4294967296LL){ emit_movz_lsl16(((uintptr_t)head>>16)&0xffff,ARG1_REG); emit_movk(((uintptr_t)head)&0xffff,ARG1_REG); }else if(offset>=-4294967296LL&&offset<4294967296LL){ emit_adrp((intptr_t)head,ARG1_REG); emit_addimm64(ARG1_REG,((intptr_t)head&0xfffLL),ARG1_REG); }else{ emit_loadlp((intptr_t)head,ARG1_REG); } emit_call((intptr_t)verify_code); intptr_t entry=(intptr_t)out; load_regs_entry(i); if(entry==(intptr_t)out) entry=instr_addr[i]; emit_jmp(instr_addr[i]); return entry; } static void do_dirty_stub_ds(struct ll_entry *head) { assem_debug("do_dirty_stub_ds %x",head->vaddr); intptr_t out_rx=((intptr_t)out-(intptr_t)base_addr)+(intptr_t)base_addr_rx; intptr_t offset=(((intptr_t)head&~0xfffLL)-((intptr_t)out_rx&~0xfffLL)); if((uintptr_t)head<4294967296LL){ emit_movz_lsl16(((uintptr_t)head>>16)&0xffff,ARG1_REG); emit_movk(((uintptr_t)head)&0xffff,ARG1_REG); }else if(offset>=-4294967296LL&&offset<4294967296LL){ emit_adrp((intptr_t)head,ARG1_REG); emit_addimm64(ARG1_REG,((intptr_t)head&0xfffLL),ARG1_REG); }else{ emit_loadlp((intptr_t)head,ARG1_REG); } emit_call((intptr_t)verify_code); } /* TLB */ static int do_tlb_r(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { if((signed int)addr>=(signed int)0xC0000000) { // address_generation already loaded the const emit_readdword_dualindexedx8(FP,map,map); } else if((signed int)addr<(signed int)0x80800000){ emit_loadreg(ROREG,HOST_TEMPREG); // On 64bit ROREG is needed to load from RDRAM return HOST_TEMPREG; } else return -1; // No mapping } else { assert(s!=map); if(cache>=0) { // Use cached offset to memory map emit_addsr12(cache,s,map); }else{ emit_loadreg(MMREG,map); emit_addsr12(map,s,map); } // Schedule this while we wait on the load //if(x) emit_xorimm(s,x,ar); emit_readdword_dualindexedx8(FP,map,map); } return map; } static int do_tlb_r_branch(int map, int c, u_int addr, intptr_t *jaddr) { if(!c||(signed int)addr>=(signed int)0xC0000000) { emit_test64(map,map); *jaddr=(intptr_t)out; emit_js(0); } return map; } static int do_tlb_w(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { if(addr<0x80800000||addr>=0xC0000000) { // address_generation already loaded the const emit_readdword_dualindexedx8(FP,map,map); } else return -1; // No mapping } else { assert(s!=map); if(cache>=0) { // Use cached offset to memory map emit_addsr12(cache,s,map); }else{ emit_loadreg(MMREG,map); emit_addsr12(map,s,map); } // Schedule this while we wait on the load //if(x) emit_xorimm(s,x,ar); emit_readdword_dualindexedx8(FP,map,map); } return map; } static void do_tlb_w_branch(int map, int c, u_int addr, intptr_t *jaddr) { if(!c||addr<0x80800000||addr>=0xC0000000) { emit_testimm64(map,WRITE_PROTECT); *jaddr=(intptr_t)out; emit_jne(0); } } // Generate the address of the memory_map entry, relative to dynarec_local static void generate_map_const(u_int addr,int tr) { //DebugMessage(M64MSG_VERBOSE, "generate_map_const(%x,%s)",addr,regname[tr]); emit_movimm((addr>>12)+(fp_memory_map>>3),tr); } static void set_rounding_mode(int s,int temp) { assert(temp>=0); emit_andimm(s,3,temp); emit_addimm64(FP,fp_rounding_modes,HOST_TEMPREG); emit_readword_dualindexedx4(HOST_TEMPREG,temp,temp); output_w32(0xd53b4400|HOST_TEMPREG); /*Read FPCR*/ emit_andimm(HOST_TEMPREG,~0xc00000,HOST_TEMPREG); /*Clear RMode*/ emit_or(temp,HOST_TEMPREG,HOST_TEMPREG); /*Set RMode*/ output_w32(0xd51b4400|HOST_TEMPREG); /*Write FPCR*/ } /* Special assem */ static void shift_assemble_arm64(int i,struct regstat *i_regs) { if(rt1[i]) { if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV { signed char s,t,shift; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(t>=0){ if(rs1[i]==0) { emit_zeroreg(t); } else if(rs2[i]==0) { assert(s>=0); if(s!=t) emit_mov(s,t); } else { emit_andimm(shift,31,HOST_TEMPREG); if(opcode2[i]==4) // SLLV { emit_shl(s,HOST_TEMPREG,t); } if(opcode2[i]==6) // SRLV { emit_shr(s,HOST_TEMPREG,t); } if(opcode2[i]==7) // SRAV { emit_sar(s,HOST_TEMPREG,t); } } } } else { // DSLLV/DSRLV/DSRAV signed char sh,sl,th,tl,shift; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(tl>=0){ if(rs1[i]==0) { emit_zeroreg(tl); if(th>=0) emit_zeroreg(th); } else if(rs2[i]==0) { assert(sl>=0); if(sl!=tl) emit_mov(sl,tl); if(th>=0&&sh!=th) emit_mov(sh,th); } else { assert(sl>=0); assert(sh>=0); if(opcode2[i]==0x14) // DSLLV { emit_mov(sl,HOST_TEMPREG); emit_orrshlimm64(sh,32,HOST_TEMPREG); emit_shl64(HOST_TEMPREG,shift,HOST_TEMPREG); emit_mov(HOST_TEMPREG,tl); if(th>=0) emit_shrimm64(HOST_TEMPREG,32,th); } if(opcode2[i]==0x16) // DSRLV { emit_mov(sl,HOST_TEMPREG); emit_orrshlimm64(sh,32,HOST_TEMPREG); emit_shr64(HOST_TEMPREG,shift,HOST_TEMPREG); emit_mov(HOST_TEMPREG,tl); if(th>=0) emit_shrimm64(HOST_TEMPREG,32,th); } if(opcode2[i]==0x17) // DSRAV { emit_mov(sl,HOST_TEMPREG); emit_orrshlimm64(sh,32,HOST_TEMPREG); emit_sar64(HOST_TEMPREG,shift,HOST_TEMPREG); emit_mov(HOST_TEMPREG,tl); if(th>=0) emit_shrimm64(HOST_TEMPREG,32,th); } } } } } } #define shift_assemble shift_assemble_arm64 static void loadlr_assemble_arm64(int i,struct regstat *i_regs) { signed char s,th,tl,temp,temp2,temp2h,addr,map=-1,cache=-1; int offset,type=0,memtarget=0,c=0; intptr_t jaddr=0; u_int hr,reglist=0; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); temp=get_reg(i_regs->regmap,-1); temp2=get_reg(i_regs->regmap,FTEMP); temp2h=get_reg(i_regs->regmap,FTEMP|64); addr=get_reg(i_regs->regmap,AGEN1+(i&1)); assert(addr<0); assert(temp>=0); assert(temp2>=0); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { c=(i_regs->wasconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } if(offset||s<0||c) addr=temp2; else addr=s; int dummy=(rt1[i]==0)||(tl!=get_reg(i_regs->regmap,rt1[i])); // ignore loads to r0 and unneeded reg switch(opcode[i]) { case 0x22: type=LOADWL_STUB; break; case 0x26: type=LOADWR_STUB; break; case 0x1A: type=LOADDL_STUB; break; case 0x1B: type=LOADDR_STUB; break; } #ifndef INTERPRET_LOADLR int ldlr=(opcode[i]==0x1A||opcode[i]==0x1B); // LDL/LDR always do inline_readstub if non constant if(!using_tlb) { if(!c&&!ldlr) { emit_cmpimm(addr,0x800000); jaddr=(intptr_t)out; emit_jno(0); } #ifdef RAM_OFFSET if(((!c&&!ldlr)||memtarget)&&!dummy) { map=get_reg(i_regs->regmap,ROREG); if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); } #endif }else{ // using tlb map=get_reg(i_regs->regmap,TLREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<=0); if(!c) { emit_shlimm(addr,3,temp); emit_andimm(addr,~3,temp2); emit_readword_indexed_tlb(0,temp2,map,temp2); emit_andimm(temp,24,temp); if (opcode[i]==0x26) emit_xorimm(temp,24,temp); // LWR emit_movimm(-1,HOST_TEMPREG); if (opcode[i]==0x26) { emit_shr(temp2,temp,temp2); emit_shr(HOST_TEMPREG,temp,HOST_TEMPREG); }else{ emit_shl(temp2,temp,temp2); emit_shl(HOST_TEMPREG,temp,HOST_TEMPREG); } emit_bic(tl,HOST_TEMPREG,tl); emit_or(temp2,tl,tl); } else { int shift=((constmap[i][s]+offset)&3)<<3; uint32_t mask=~UINT32_C(0); if (opcode[i]==0x26) { //LWR shift^=24; mask>>=shift; } else { //LWL mask<<=shift; } if((constmap[i][s]+offset)&3) emit_andimm(addr,~3,temp2); if(shift) { emit_readword_indexed_tlb(0,temp2,map,temp2); if (opcode[i]==0x26) emit_shrimm(temp2,shift,temp2); else emit_shlimm(temp2,shift,temp2); emit_andimm(tl,~mask,tl); emit_or(temp2,tl,tl); } else emit_readword_indexed_tlb(0,temp2,map,tl); } } if(opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR assert(tl>=0); assert(th>=0); assert(temp2h>=0); if(!c) { //TODO: implement recompiled code inline_readstub(type,i,0,addr,i_regs,rt1[i],ccadj[i],reglist); } else { int shift=((constmap[i][s]+offset)&7)<<3; uint64_t mask=~UINT64_C(0); if (opcode[i]==0x1B) { //LDR shift^=56; mask>>=shift; } else { //LDL mask<<=shift; } if((constmap[i][s]+offset)&7) emit_andimm(addr,~7,temp2); if(shift) { emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2); if (opcode[i]==0x1B) { emit_shrdimm(temp2h,temp2,shift,temp2h); emit_shrimm(temp2,shift,temp2); } else { emit_shldimm(temp2h,temp2,shift,temp2h); emit_shlimm(temp2,shift,temp2); } emit_andimm(tl,~mask,tl); emit_andimm(th,~mask>>32,th); emit_or(temp2,tl,tl); emit_or(temp2h,th,th); } else emit_readdword_indexed_tlb(0,temp2,map,th,tl); } } } if(jaddr) { add_stub(type,jaddr,(intptr_t)out,i,addr,(intptr_t)i_regs,ccadj[i],reglist); } else if(c&&!memtarget) { inline_readstub(type,i,(constmap[i][s]+offset),addr,i_regs,rt1[i],ccadj[i],reglist); } #else inline_readstub(type,i,c?(constmap[i][s]+offset):0,addr,i_regs,rt1[i],ccadj[i],reglist); #endif } #define loadlr_assemble loadlr_assemble_arm64 static void fconv_assemble_arm64(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char rs=get_reg(i_regs->regmap,CSREG); assert(rs>=0); emit_testimm(rs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,rs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCONV /*Single-precision to Integer*/ //TOBEDONE //if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) { //cvt_w_s //} //if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) { //cvt_l_s //} if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) { //round_l_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtns_l_s(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) { //trunc_l_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtzs_l_s(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) { //ceil_l_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtps_l_s(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) { //floor_l_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtms_l_s(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) { //round_w_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtns_w_s(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { //trunc_w_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtzs_w_s(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) { //ceil_w_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtps_w_s(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) { //floor_w_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_fcvtms_w_s(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } /*Double-precision to Integer*/ //TOBEDONE //if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) { //cvt_w_d //} //if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) { //cvt_l_d //} if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) { //round_l_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtns_l_d(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) { //trunc_l_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtzs_l_d(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) { //ceil_l_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtps_l_d(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) { //floor_l_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtms_l_d(31,HOST_TEMPREG); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_writedword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) { //round_w_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtns_w_d(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { //trunc_w_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtzs_w_d(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) { //ceil_w_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtps_w_d(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) { //floor_w_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvtms_w_d(31,HOST_TEMPREG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_writeword_indexed(HOST_TEMPREG,0,temp); return; } /*Single-precision to Double-precision*/ if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { //cvt_d_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fcvt_d_s(31,31); emit_fstd(31,temp); return; } /*Double-precision to Single-precision*/ if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { //cvt_s_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); emit_fcvt_s_d(31,31); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fsts(31,temp); return; } /*Integer to Single-precision*/ if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { //cvt_s_w emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_readword_indexed(0,temp,HOST_TEMPREG); emit_scvtf_s_w(HOST_TEMPREG,31); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fsts(31,temp); return; } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { //cvt_s_l emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_readdword_indexed(0,temp,HOST_TEMPREG); emit_scvtf_s_l(HOST_TEMPREG,31); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fsts(31,temp); return; } /*Integer Double-precision*/ if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { //cvt_d_w emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_readword_indexed(0,temp,HOST_TEMPREG); emit_scvtf_d_w(HOST_TEMPREG,31); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstd(31,temp); return; } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { //cvt_d_l emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_readdword_indexed(0,temp,HOST_TEMPREG); emit_scvtf_d_l(HOST_TEMPREG,31); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstd(31,temp); return; } #endif // C emulation code u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,FSREG); save_regs(reglist); if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_s_w); } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)cvt_d_w); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_s_l); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_d_l); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)cvt_d_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_l_s); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_s_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_l_d); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_w_s); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_w_d); } restore_regs(reglist); } #define fconv_assemble fconv_assemble_arm64 static void fcomp_assemble(int i,struct regstat *i_regs) { signed char fs=get_reg(i_regs->regmap,FSREG); signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,cs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCOMP if((source[i]&0x3f)==0x30) { emit_andimm(fs,~0x800000,fs); return; } if((source[i]&0x3e)==0x38) { // sf/ngle - these should throw exceptions for NaNs emit_andimm(fs,~0x800000,fs); return; } if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_flds(temp,30); emit_flds(HOST_TEMPREG,31); emit_andimm(fs,~0x800000,fs); emit_orimm(fs,0x800000,temp); emit_fcmps(30,31); if((source[i]&0x3f)==0x31) emit_csel_vs(temp,fs,fs); // c_un_s if((source[i]&0x3f)==0x32) emit_csel_eq(temp,fs,fs); // c_eq_s if((source[i]&0x3f)==0x33) {emit_csel_eq(temp,fs,fs);emit_csel_vs(temp,fs,fs);} // c_ueq_s if((source[i]&0x3f)==0x34) emit_csel_cc(temp,fs,fs); // c_olt_s if((source[i]&0x3f)==0x35) {emit_csel_cc(temp,fs,fs);emit_csel_vs(temp,fs,fs);} // c_ult_s if((source[i]&0x3f)==0x36) emit_csel_ls(temp,fs,fs); // c_ole_s if((source[i]&0x3f)==0x37) {emit_csel_ls(temp,fs,fs);emit_csel_vs(temp,fs,fs);} // c_ule_s if((source[i]&0x3f)==0x3a) emit_csel_eq(temp,fs,fs); // c_seq_s if((source[i]&0x3f)==0x3b) emit_csel_eq(temp,fs,fs); // c_ngl_s if((source[i]&0x3f)==0x3c) emit_csel_cc(temp,fs,fs); // c_lt_s if((source[i]&0x3f)==0x3d) emit_csel_cc(temp,fs,fs); // c_nge_s if((source[i]&0x3f)==0x3e) emit_csel_ls(temp,fs,fs); // c_le_s if((source[i]&0x3f)==0x3f) emit_csel_ls(temp,fs,fs); // c_ngt_s return; } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_fldd(temp,30); emit_fldd(HOST_TEMPREG,31); emit_andimm(fs,~0x800000,fs); emit_orimm(fs,0x800000,temp); emit_fcmpd(30,31); if((source[i]&0x3f)==0x31) emit_csel_vs(temp,fs,fs); // c_un_d if((source[i]&0x3f)==0x32) emit_csel_eq(temp,fs,fs); // c_eq_d if((source[i]&0x3f)==0x33) {emit_csel_eq(temp,fs,fs);emit_csel_vs(temp,fs,fs);} // c_ueq_d if((source[i]&0x3f)==0x34) emit_csel_cc(temp,fs,fs); // c_olt_d if((source[i]&0x3f)==0x35) {emit_csel_cc(temp,fs,fs);emit_csel_vs(temp,fs,fs);} // c_ult_d if((source[i]&0x3f)==0x36) emit_csel_ls(temp,fs,fs); // c_ole_d if((source[i]&0x3f)==0x37) {emit_csel_ls(temp,fs,fs);emit_csel_vs(temp,fs,fs);} // c_ule_d if((source[i]&0x3f)==0x3a) emit_csel_eq(temp,fs,fs); // c_seq_d if((source[i]&0x3f)==0x3b) emit_csel_eq(temp,fs,fs); // c_ngl_d if((source[i]&0x3f)==0x3c) emit_csel_cc(temp,fs,fs); // c_lt_d if((source[i]&0x3f)==0x3d) emit_csel_cc(temp,fs,fs); // c_nge_d if((source[i]&0x3f)==0x3e) emit_csel_ls(temp,fs,fs); // c_le_d if((source[i]&0x3f)==0x3f) emit_csel_ls(temp,fs,fs); // c_ngt_d return; } #endif // C only u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],ARG3_REG); if((source[i]&0x3f)==0x30) emit_call((intptr_t)c_f_s); if((source[i]&0x3f)==0x31) emit_call((intptr_t)c_un_s); if((source[i]&0x3f)==0x32) emit_call((intptr_t)c_eq_s); if((source[i]&0x3f)==0x33) emit_call((intptr_t)c_ueq_s); if((source[i]&0x3f)==0x34) emit_call((intptr_t)c_olt_s); if((source[i]&0x3f)==0x35) emit_call((intptr_t)c_ult_s); if((source[i]&0x3f)==0x36) emit_call((intptr_t)c_ole_s); if((source[i]&0x3f)==0x37) emit_call((intptr_t)c_ule_s); if((source[i]&0x3f)==0x38) emit_call((intptr_t)c_sf_s); if((source[i]&0x3f)==0x39) emit_call((intptr_t)c_ngle_s); if((source[i]&0x3f)==0x3a) emit_call((intptr_t)c_seq_s); if((source[i]&0x3f)==0x3b) emit_call((intptr_t)c_ngl_s); if((source[i]&0x3f)==0x3c) emit_call((intptr_t)c_lt_s); if((source[i]&0x3f)==0x3d) emit_call((intptr_t)c_nge_s); if((source[i]&0x3f)==0x3e) emit_call((intptr_t)c_le_s); if((source[i]&0x3f)==0x3f) emit_call((intptr_t)c_ngt_s); } if(opcode2[i]==0x11) { emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],ARG3_REG); if((source[i]&0x3f)==0x30) emit_call((intptr_t)c_f_d); if((source[i]&0x3f)==0x31) emit_call((intptr_t)c_un_d); if((source[i]&0x3f)==0x32) emit_call((intptr_t)c_eq_d); if((source[i]&0x3f)==0x33) emit_call((intptr_t)c_ueq_d); if((source[i]&0x3f)==0x34) emit_call((intptr_t)c_olt_d); if((source[i]&0x3f)==0x35) emit_call((intptr_t)c_ult_d); if((source[i]&0x3f)==0x36) emit_call((intptr_t)c_ole_d); if((source[i]&0x3f)==0x37) emit_call((intptr_t)c_ule_d); if((source[i]&0x3f)==0x38) emit_call((intptr_t)c_sf_d); if((source[i]&0x3f)==0x39) emit_call((intptr_t)c_ngle_d); if((source[i]&0x3f)==0x3a) emit_call((intptr_t)c_seq_d); if((source[i]&0x3f)==0x3b) emit_call((intptr_t)c_ngl_d); if((source[i]&0x3f)==0x3c) emit_call((intptr_t)c_lt_d); if((source[i]&0x3f)==0x3d) emit_call((intptr_t)c_nge_d); if((source[i]&0x3f)==0x3e) emit_call((intptr_t)c_le_d); if((source[i]&0x3f)==0x3f) emit_call((intptr_t)c_ngt_d); } restore_regs(reglist); emit_loadreg(FSREG,fs); } static void float_assemble(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,cs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FLOAT if((source[i]&0x3f)==6) // mov { if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],HOST_TEMPREG); emit_flds(temp,31); emit_fsts(31,HOST_TEMPREG); } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],HOST_TEMPREG); emit_fldd(temp,31); emit_fstd(31,HOST_TEMPREG); } } return; } if((source[i]&0x3f)>3) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp,31); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==4) // sqrt emit_fsqrts(31,31); if((source[i]&0x3f)==5) // abs emit_fabss(31,31); if((source[i]&0x3f)==7) // neg emit_fnegs(31,31); emit_fsts(31,temp); } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldd(temp,31); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==4) // sqrt emit_fsqrtd(31,31); if((source[i]&0x3f)==5) // abs emit_fabsd(31,31); if((source[i]&0x3f)==7) // neg emit_fnegd(31,31); emit_fstd(31,temp); } return; } if((source[i]&0x3f)<4) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); } if(((source[i]>>11)&0x1f)!=((source[i]>>16)&0x1f)) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_flds(temp,31); emit_flds(HOST_TEMPREG,30); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } } if((source[i]&0x3f)==0) emit_fadds(31,30,31); if((source[i]&0x3f)==1) emit_fsubs(31,30,31); if((source[i]&0x3f)==2) emit_fmuls(31,30,31); if((source[i]&0x3f)==3) emit_fdivs(31,30,31); if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) { emit_fsts(31,HOST_TEMPREG); }else{ emit_fsts(31,temp); } } else if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],HOST_TEMPREG); emit_fldd(temp,31); emit_fldd(HOST_TEMPREG,30); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } } if((source[i]&0x3f)==0) emit_faddd(31,30,31); if((source[i]&0x3f)==1) emit_fsubd(31,30,31); if((source[i]&0x3f)==2) emit_fmuld(31,30,31); if((source[i]&0x3f)==3) emit_fdivd(31,30,31); if(((source[i]>>16)&0x1f)==((source[i]>>6)&0x1f)) { emit_fstd(31,HOST_TEMPREG); }else{ emit_fstd(31,temp); } } } else { if(opcode2[i]==0x10) { emit_flds(temp,31); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==0) emit_fadds(31,31,31); if((source[i]&0x3f)==1) emit_fsubs(31,31,31); if((source[i]&0x3f)==2) emit_fmuls(31,31,31); if((source[i]&0x3f)==3) emit_fdivs(31,31,31); emit_fsts(31,temp); } else if(opcode2[i]==0x11) { emit_fldd(temp,31); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } if((source[i]&0x3f)==0) emit_faddd(31,31,31); if((source[i]&0x3f)==1) emit_fsubd(31,31,31); if((source[i]&0x3f)==2) emit_fmuld(31,31,31); if((source[i]&0x3f)==3) emit_fdivd(31,31,31); emit_fstd(31,temp); } } return; } #endif u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,FSREG); if(opcode2[i]==0x10) { // Single precision save_regs(reglist); switch(source[i]&0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],ARG3_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG4_REG); break; case 0x04: emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); break; case 0x05: case 0x06: case 0x07: emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); break; } switch(source[i]&0x3f) { case 0x00: emit_call((intptr_t)add_s);break; case 0x01: emit_call((intptr_t)sub_s);break; case 0x02: emit_call((intptr_t)mul_s);break; case 0x03: emit_call((intptr_t)div_s);break; case 0x04: emit_call((intptr_t)sqrt_s);break; case 0x05: emit_call((intptr_t)abs_s);break; case 0x06: emit_call((intptr_t)mov_s);break; case 0x07: emit_call((intptr_t)neg_s);break; } restore_regs(reglist); } if(opcode2[i]==0x11) { // Double precision save_regs(reglist); switch(source[i]&0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],ARG3_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG4_REG); break; case 0x04: emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); break; case 0x05: case 0x06: case 0x07: emit_addimm64(FP,fp_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); break; } switch(source[i]&0x3f) { case 0x00: emit_call((intptr_t)add_d);break; case 0x01: emit_call((intptr_t)sub_d);break; case 0x02: emit_call((intptr_t)mul_d);break; case 0x03: emit_call((intptr_t)div_d);break; case 0x04: emit_call((intptr_t)sqrt_d);break; case 0x05: emit_call((intptr_t)abs_d);break; case 0x06: emit_call((intptr_t)mov_d);break; case 0x07: emit_call((intptr_t)neg_d);break; } restore_regs(reglist); } } static void multdiv_assemble_arm64(int i,struct regstat *i_regs) { // case 0x18: MULT // case 0x19: MULTU // case 0x1A: DIV // case 0x1B: DIVU // case 0x1C: DMULT // case 0x1D: DMULTU // case 0x1E: DDIV // case 0x1F: DDIVU if(rs1[i]&&rs2[i]) { if((opcode2[i]&4)==0) // 32-bit { #ifndef INTERPRET_MULT if((opcode2[i]==0x18) || (opcode2[i]==0x19)) { signed char m1=get_reg(i_regs->regmap,rs1[i]); signed char m2=get_reg(i_regs->regmap,rs2[i]); signed char high=get_reg(i_regs->regmap,HIREG); signed char low=get_reg(i_regs->regmap,LOREG); assert(m1>=0); assert(m2>=0); assert(high>=0); assert(low>=0); if(opcode2[i]==0x18) //MULT emit_smull(m1,m2,high); else if(opcode2[i]==0x19) //MULTU emit_umull(m1,m2,high); emit_mov(high,low); emit_shrimm64(high,32,high); } else #endif #ifndef INTERPRET_DIV if((opcode2[i]==0x1A) || (opcode2[i]==0x1B)) { signed char numerator=get_reg(i_regs->regmap,rs1[i]); signed char denominator=get_reg(i_regs->regmap,rs2[i]); assert(numerator>=0); assert(denominator>=0); signed char quotient=get_reg(i_regs->regmap,LOREG); signed char remainder=get_reg(i_regs->regmap,HIREG); assert(quotient>=0); assert(remainder>=0); emit_test(denominator,denominator); intptr_t jaddr=(intptr_t)out; emit_jeq(0); // Division by zero if(opcode2[i]==0x1A) //DIV emit_sdiv(numerator,denominator,quotient); else if(opcode2[i]==0x1B) //DIVU emit_udiv(numerator,denominator,quotient); emit_msub(quotient,denominator,numerator,remainder); set_jump_target(jaddr,(intptr_t)out); } else #endif { u_int reglist=0; signed char r1=get_reg(i_regs->regmap,rs1[i]); signed char r2=get_reg(i_regs->regmap,rs2[i]); signed char hi=get_reg(i_regs->regmap,HIREG); signed char lo=get_reg(i_regs->regmap,LOREG); assert(r1>=0); assert(r2>=0); for(int hr=0;hrregmap[hr]>=0) reglist|=1<=0) reglist&=~(1<=0) reglist&=~(1<=0) emit_loadreg(HIREG,hi); if(lo>=0) emit_loadreg(LOREG,lo); } } else // 64-bit { #ifndef INTERPRET_MULT64 if(opcode2[i]==0x1C||opcode2[i]==0x1D) { signed char m1h=get_reg(i_regs->regmap,rs1[i]|64); signed char m1l=get_reg(i_regs->regmap,rs1[i]); signed char m2h=get_reg(i_regs->regmap,rs2[i]|64); signed char m2l=get_reg(i_regs->regmap,rs2[i]); assert(m1h>=0); assert(m2h>=0); assert(m1l>=0); assert(m2l>=0); signed char hih=get_reg(i_regs->regmap,HIREG|64); signed char hil=get_reg(i_regs->regmap,HIREG); signed char loh=get_reg(i_regs->regmap,LOREG|64); signed char lol=get_reg(i_regs->regmap,LOREG); assert(hih>=0); assert(hil>=0); assert(loh>=0); assert(lol>=0); emit_mov(m1l,lol); emit_orrshlimm64(m1h,32,lol); emit_mov(m2l,loh); emit_orrshlimm64(m2h,32,loh); if(opcode2[i]==0x1C) // DMULT { emit_mul64(lol,loh,hil); emit_smulh(lol,loh,hih); } else if(opcode2[i]==0x1D) // DMULTU { emit_mul64(lol,loh,hil); emit_umulh(lol,loh,hih); } emit_mov(hil,lol); emit_shrimm64(hil,32,loh); emit_mov(hih,hil); emit_shrimm64(hih,32,hih); } else #endif #ifndef INTERPRET_DIV64 if((opcode2[i]==0x1E)||(opcode2[i]==0x1F)) { signed char numh=get_reg(i_regs->regmap,rs1[i]|64); signed char numl=get_reg(i_regs->regmap,rs1[i]); signed char denomh=get_reg(i_regs->regmap,rs2[i]|64); signed char denoml=get_reg(i_regs->regmap,rs2[i]); assert(numh>=0); assert(numl>=0); assert(denomh>=0); assert(denoml>=0); signed char remh=get_reg(i_regs->regmap,HIREG|64); signed char reml=get_reg(i_regs->regmap,HIREG); signed char quoh=get_reg(i_regs->regmap,LOREG|64); signed char quol=get_reg(i_regs->regmap,LOREG); assert(remh>=0); assert(reml>=0); assert(quoh>=0); assert(quol>=0); emit_mov(denoml,quoh); emit_orrshlimm64(denomh,32,quoh); emit_test64(quoh,quoh); intptr_t jaddr=(intptr_t)out; emit_jeq(0); // Division by zero emit_mov(numl,quol); emit_orrshlimm64(numh,32,quol); if(opcode2[i]==0x1E) // DDIV { emit_sdiv64(quol,quoh,reml); emit_msub64(reml,quoh,quol,remh); } else if(opcode2[i]==0x1F) // DDIVU { emit_udiv64(quol,quoh,reml); emit_msub64(reml,quoh,quol,remh); } emit_mov(reml,quol); emit_shrimm64(reml,32,quoh); emit_mov(remh,reml); emit_shrimm64(remh,32,remh); set_jump_target(jaddr,(intptr_t)out); } else #endif { u_int reglist=0; signed char r1h=get_reg(i_regs->regmap,rs1[i]|64); signed char r1l=get_reg(i_regs->regmap,rs1[i]); signed char r2h=get_reg(i_regs->regmap,rs2[i]|64); signed char r2l=get_reg(i_regs->regmap,rs2[i]); signed char hih=get_reg(i_regs->regmap,HIREG|64); signed char hil=get_reg(i_regs->regmap,HIREG); signed char loh=get_reg(i_regs->regmap,LOREG|64); signed char lol=get_reg(i_regs->regmap,LOREG); assert(r1h>=0); assert(r2h>=0); assert(r1l>=0); assert(r2l>=0); for(int hr=0;hrregmap[hr]>=0) reglist|=1<=0) reglist&=~(1<=0) reglist&=~(1<=0) reglist&=~(1<=0) reglist&=~(1<=0) emit_loadreg(HIREG|64,hih); if(hil>=0) emit_loadreg(HIREG,hil); if(loh>=0) emit_loadreg(LOREG|64,loh); if(lol>=0) emit_loadreg(LOREG,lol); } } } else { // Multiply by zero is zero. // MIPS does not have a divide by zero exception. // The result is undefined, we return zero. signed char hr=get_reg(i_regs->regmap,HIREG); signed char lr=get_reg(i_regs->regmap,LOREG); if(hr>=0) emit_zeroreg(hr); if(lr>=0) emit_zeroreg(lr); } } #define multdiv_assemble multdiv_assemble_arm64 static void do_preload_rhash(int r) { // Don't need this for ARM64. On x86, this puts the value 0xf8 into the // register. On ARM64 the hash can be done with a single instruction (below) } static void do_preload_rhtbl(int ht) { emit_addimm64(FP,fp_mini_ht,ht); } static void do_rhash(int rs,int rh) { emit_andimm(rs,0x1f0,rh); } static void do_miniht_load(int ht,int rh) { assem_debug("add %s,%s,%s",regname64[ht],regname64[ht],regname64[rh]); output_w32(0x8b000000|rh<<16|ht<<5|ht); assem_debug("ldr %s,[%s]",regname[rh],regname64[ht]); output_w32(0xb9400000|ht<<5|rh); } static void do_miniht_jump(int rs,int rh,int ht) { emit_cmp(rh,rs); intptr_t jaddr=(intptr_t)out; emit_jeq(0); if(rs==18) { // x18 is used for trampoline jumps, move it to another register (x0) emit_mov(rs,0); rs=0; } emit_jmp(jump_vaddr_reg[rs]); set_jump_target(jaddr,(intptr_t)out); assem_debug("ldr %s,[%s,#8]",regname64[ht],regname64[ht]); output_w32(0xf9400000|(8>>3)<<10|ht<<5|ht); emit_jmpreg(ht); } static void do_miniht_insert(u_int return_address,int rt,int temp) { emit_movz_lsl16((return_address>>16)&0xffff,rt); emit_movk(return_address&0xffff,rt); add_to_linker((intptr_t)out,return_address,1); emit_adr((intptr_t)out,temp); emit_writedword(temp,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0x1FF)>>4][1]); emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0x1FF)>>4][0]); } // Clearing the cache is rather slow on ARM Linux, so mark the areas // that need to be cleared, and then only clear these areas once. static void do_clear_cache(void) { int i,j; for (i=0;i<(1<<(TARGET_SIZE_2-17));i++) { u_int bitmap=needs_clear_cache[i]; if(bitmap) { uintptr_t start,end; for(j=0;j<32;j++) { if(bitmap&(1<>12); } // CPU-architecture-specific initialization static void arch_init(void) { assert((fp_memory_map&7)==0); g_dev.r4300.new_dynarec_hot_state.rounding_modes[0]=0x0<<22; // round g_dev.r4300.new_dynarec_hot_state.rounding_modes[1]=0x3<<22; // trunc g_dev.r4300.new_dynarec_hot_state.rounding_modes[2]=0x1<<22; // ceil g_dev.r4300.new_dynarec_hot_state.rounding_modes[3]=0x2<<22; // floor #ifdef RAM_OFFSET g_dev.r4300.new_dynarec_hot_state.ram_offset=((intptr_t)g_dev.rdram.dram-(intptr_t)0x80000000)>>2; #endif jump_table_symbols[0] = (intptr_t)cached_interp_TLBR; jump_table_symbols[1] = (intptr_t)cached_interp_TLBP; jump_table_symbols[2] = (intptr_t)cached_interp_MULT; jump_table_symbols[3] = (intptr_t)cached_interp_MULTU; jump_table_symbols[4] = (intptr_t)cached_interp_DIV; jump_table_symbols[5] = (intptr_t)cached_interp_DIVU; jump_table_symbols[6] = (intptr_t)cached_interp_DMULT; jump_table_symbols[7] = (intptr_t)cached_interp_DMULTU; jump_table_symbols[8] = (intptr_t)cached_interp_DDIV; jump_table_symbols[9] = (intptr_t)cached_interp_DDIVU; // Trampolines for jumps >128MB intptr_t *ptr,*ptr2,*ptr3; ptr=(intptr_t *)jump_table_symbols; ptr2=(intptr_t *)((char *)base_addr+(1<=-134217728LL&&offset<134217728LL) { *ptr4=0x14000000|((offset>>2)&0x3ffffff); // direct branch }else{ *ptr4=0x58000000|((8>>2)<<5)|18; // ldr x18,[pc,#8] *(ptr4+1)=0xd61f0000|(18<<5); } ptr2++; *ptr2=*ptr; ptr++; ptr2++; ptr3+=2; } } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm64/assem_arm64.h000066400000000000000000000022671464506436200257740ustar00rootroot00000000000000#ifndef M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ASSEM_ARM64_H #define M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ASSEM_ARM64_H #define HOST_REGS 29 #define HOST_CCREG 20 /* callee-save */ #define HOST_BTREG 19 /* callee-save */ #define EXCLUDE_REG 29 /* FP */ #define NATIVE_64 1 #define HOST_IMM8 1 //#define HAVE_CMOV_IMM 1 //#define CORTEX_A8_BRANCH_PREDICTION_HACK 1 //#define REG_PREFETCH 1 //#define HAVE_CONDITIONAL_CALL 1 #define RAM_OFFSET 1 #define USE_MINI_HT 1 /* ARM calling convention: x0-x18: caller-save x19-x28: callee-save */ #define ARG1_REG 0 #define ARG2_REG 1 #define ARG3_REG 2 #define ARG4_REG 3 /* GCC register naming convention: x16 = ip0 (scratch) x17 = ip1 (scratch) x29 = fp (frame pointer) x30 = lr (link register) x31 = sp (stack pointer) */ #define FP 29 #define LR 30 #define WZR 31 #define XZR WZR #define CALLER_SAVED_REGS 0x7ffff #define HOST_TEMPREG 30 // Note: FP is set to &dynarec_local when executing generated code. // Thus the local variables are actually global and not on the stack. #define TARGET_SIZE_2 25 // 2^25 = 32 megabytes #define JUMP_TABLE_SIZE (sizeof(jump_table_symbols)*2) #endif /* M64P_DEVICE_R4300_NEW_DYNAREC_ARM_ASSEM_ARM64_H */ mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/arm64/linkage_arm64.S000066400000000000000000000157301464506436200262500ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - linkage_arm64.S * * Copyright (C) 2009-2018 Gillou68310 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define GLOBAL_FUNCTION(name) \ .globl name; \ .hidden name; \ .type name, %function; \ name #define LOCAL_FUNCTION(name) \ .hidden name; \ .type name, %function; \ name #define GLOBAL_VARIABLE(name, size_) \ .global name; \ .hidden name; \ .type name, %object; \ .size name, size_ .macro movl Wn, imm movz \Wn, (\imm >> 16) & 0xFFFF, lsl 16 movk \Wn, \imm & 0xFFFF .endm #define TEXT_SECTION .text #define END_SECTION #include "asm_defines_gas.h" device_r4300_new_dynarec_hot_state_dynarec_local = (offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_dynarec_local) saved_context = 160 /* Defines offsets for fp addressed variables */ fp_cycle_count = offsetof_struct_new_dynarec_hot_state_cycle_count fp_pending_exception = offsetof_struct_new_dynarec_hot_state_pending_exception fp_pcaddr = offsetof_struct_new_dynarec_hot_state_pcaddr fp_stop = offsetof_struct_new_dynarec_hot_state_stop TEXT_SECTION GLOBAL_FUNCTION(jump_vaddr_x0): b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x1): mov w0, w1 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x2): mov w0, w2 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x3): mov w0, w3 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x4): mov w0, w4 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x5): mov w0, w5 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x6): mov w0, w6 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x8): mov w0, w8 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x9): mov w0, w9 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x10): mov w0, w10 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x11): mov w0, w11 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x12): mov w0, w12 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x13): mov w0, w13 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x14): mov w0, w14 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x15): mov w0, w15 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x16): mov w0, w16 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x17): mov w0, w17 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x19): mov w0, w19 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x21): mov w0, w21 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x22): mov w0, w22 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x23): mov w0, w23 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x24): mov w0, w24 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x25): mov w0, w25 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x26): mov w0, w26 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x27): mov w0, w27 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x28): mov w0, w28 b jump_vaddr GLOBAL_FUNCTION(jump_vaddr_x7): mov w0, w7 GLOBAL_FUNCTION(jump_vaddr): bl get_addr_ht br x0 GLOBAL_FUNCTION(verify_code): /* x0 = head */ mov x21, x30 /* Save link register */ bl verify_dirty tst x0, x0 b.ne .D1 mov x30, x21 /* Restore link register */ ret .D1: bl get_addr br x0 GLOBAL_FUNCTION(cc_interrupt): str w20, [x29, #fp_cycle_count] str wzr, [x29, #fp_pending_exception] mov x20, x30 /* Save link register */ bl dynarec_gen_interrupt mov x30, x20 /* Restore link register */ ldr w20, [x29, #fp_cycle_count] ldr w1, [x29, #fp_pending_exception] ldr w2, [x29, #fp_stop] tst w2, w2 b.ne new_dyna_stop tst w1, w1 b.ne .E1 ret .E1: ldr w0, [x29, #fp_pcaddr] bl get_addr_ht br x0 LOCAL_FUNCTION(new_dyna_stop): add x16, x29, #saved_context ldp x19,x20,[x16,#0] ldp x21,x22,[x16,#16] ldp x23,x24,[x16,#32] ldp x25,x26,[x16,#48] ldp x27,x28,[x16,#64] ldp x29,x30,[x16,#80] ret GLOBAL_FUNCTION(do_interrupt): ldr w2, [x29, #fp_stop] tst w2, w2 b.ne new_dyna_stop ldr w0, [x29, #fp_pcaddr] bl get_addr_ht ldr w20, [x29, #fp_cycle_count] br x0 GLOBAL_FUNCTION(fp_exception): str w0, [x29, #fp_pcaddr] bl cop1_unusable br x0 GLOBAL_FUNCTION(jump_syscall): str w0, [x29, #fp_pcaddr] bl SYSCALL_new br x0 GLOBAL_FUNCTION(jump_eret): str w20, [x29, #fp_cycle_count] bl ERET_new ldr w20, [x29, #fp_cycle_count] tst w0, w0 b.eq new_dyna_stop br x0 GLOBAL_FUNCTION(dyna_linker): bl dynamic_linker br x0 GLOBAL_FUNCTION(dyna_linker_ds): bl dynamic_linker_ds br x0 GLOBAL_FUNCTION(new_dyna_start): adrp x16, g_dev add x16, x16, :lo12:g_dev movl x1, (device_r4300_new_dynarec_hot_state_dynarec_local + saved_context) add x16, x16, x1 adrp x1, base_addr_rx add x1, x1, :lo12:base_addr_rx mov w0, #0xa4000000 stp x19,x20,[x16,#0] stp x21,x22,[x16,#16] stp x23,x24,[x16,#32] stp x25,x26,[x16,#48] stp x27,x28,[x16,#64] stp x29,x30,[x16,#80] sub x29, x16, #saved_context ldr x19, [x1] add w0, w0, #0x40 bl new_recompile_block ldr w20, [x29, #fp_cycle_count] br x19 GLOBAL_FUNCTION(breakpoint): brk 0 ret END_SECTIONmupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/new_dynarec.c000066400000000000000000014211611464506436200252120ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - new_dynarec.c * * Copyright (C) 2009-2011 Ari64 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include #include // needed for u_int, u_char, etc #include #if defined(__APPLE__) #define MAP_ANONYMOUS MAP_ANON #endif #include "new_dynarec.h" #include "api/m64p_types.h" #include "api/callbacks.h" #include "main/main.h" #include "main/rom.h" #include "device/memory/memory.h" #include "device/r4300/cached_interp.h" #include "device/r4300/cp0.h" #include "device/r4300/cp1.h" #include "device/r4300/interrupt.h" #include "device/r4300/tlb.h" #include "device/r4300/fpu.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/rsp/rsp_core.h" #if !defined(WIN32) #include #endif #if defined(RECOMPILER_DEBUG) && !defined(RECOMP_DBG) void recomp_dbg_init(void); void recomp_dbg_cleanup(void); void recomp_dbg_block(int addr); #endif #if NEW_DYNAREC == NEW_DYNAREC_X86 #include "x86/assem_x86.h" #elif NEW_DYNAREC == NEW_DYNAREC_X64 #include "x64/assem_x64.h" #elif NEW_DYNAREC == NEW_DYNAREC_ARM #include "arm/arm_cpu_features.h" #include "arm/assem_arm.h" #elif NEW_DYNAREC == NEW_DYNAREC_ARM64 #include "arm64/assem_arm64.h" #else #error Unsupported dynarec architecture #endif /* debug */ #define ASSEM_DEBUG 0 #define INV_DEBUG 0 #define COUNT_NOTCOMPILEDS 0 //#define INTERPRET_LOAD //#define INTERPRET_STORE //#define INTERPRET_C1LS //#define INTERPRET_LOADLR //#define INTERPRET_STORELR //#define INTERPRET_MULT //#define INTERPRET_DIV //#define INTERPRET_MULT64 //#define INTERPRET_DIV64 //#define INTERPRET_FCONV //#define INTERPRET_FLOAT //#define INTERPRET_FCOMP #if ASSEM_DEBUG #define assem_debug(...) DebugMessage(M64MSG_VERBOSE, __VA_ARGS__) #else #define assem_debug(...) #endif #if INV_DEBUG #define inv_debug(...) DebugMessage(M64MSG_VERBOSE, __VA_ARGS__) #else #define inv_debug(...) #endif #ifdef NDEBUG #define assem_strcpy(...) #else #define assem_strcpy strcpy #endif /* registers that may be allocated */ /* 1-31 gpr */ #define HIREG 32 // hi #define LOREG 33 // lo #define FSREG 34 // FPU status (FCSR) #define CSREG 35 // Coprocessor status #define CCREG 36 // Cycle count #define INVCP 37 // Pointer to invalid_code #define MMREG 38 // Pointer to memory_map #define ROREG 39 // ram offset (if rdram!=0x80000000) #define TEMPREG 40 #define FTEMP 40 // FPU temporary register #define PTEMP 41 // Prefetch temporary register #define TLREG 42 // TLB mapping offset #define RHASH 43 // Return address hash #define RHTBL 44 // Return address hash table address #define RTEMP 45 // JR/JALR address register #define MAXREG 45 #define AGEN1 46 // Address generation temporary register #define AGEN2 47 // Address generation temporary register #define MGEN1 48 // Maptable address generation temporary register #define MGEN2 49 // Maptable address generation temporary register #define BTREG 50 // Branch target temporary register /* instruction types */ #define NOP 0 // No operation #define LOAD 1 // Load #define STORE 2 // Store #define LOADLR 3 // Unaligned load #define STORELR 4 // Unaligned store #define MOV 5 // Move #define ALU 6 // Arithmetic/logic #define MULTDIV 7 // Multiply/divide #define SHIFT 8 // Shift by register #define SHIFTIMM 9// Shift by immediate #define IMM16 10 // 16-bit immediate #define RJUMP 11 // Unconditional jump to register #define UJUMP 12 // Unconditional jump #define CJUMP 13 // Conditional branch (BEQ/BNE/BGTZ/BLEZ) #define SJUMP 14 // Conditional branch (regimm format) #define COP0 15 // Coprocessor 0 #define COP1 16 // Coprocessor 1 #define C1LS 17 // Coprocessor 1 load/store #define FJUMP 18 // Conditional branch (floating point) #define FLOAT 19 // Floating point unit #define FCONV 20 // Convert integer to float #define FCOMP 21 // Floating point compare (sets FSREG) #define SYSCALL 22// SYSCALL #define OTHER 23 // Other #define SPAN 24 // Branch/delay slot spans 2 pages #define NI 25 // Not implemented /* stubs */ #define CC_STUB 1 #define FP_STUB 2 #define LOADB_STUB 3 #define LOADH_STUB 4 #define LOADW_STUB 5 #define LOADD_STUB 6 #define LOADBU_STUB 7 #define LOADHU_STUB 8 #define LOADWU_STUB 9 #define STOREB_STUB 10 #define STOREH_STUB 11 #define STOREW_STUB 12 #define STORED_STUB 13 #define LOADWR_STUB 14 #define LOADWL_STUB 15 #define LOADDR_STUB 16 #define LOADDL_STUB 17 #define STOREWL_STUB 18 #define STOREWR_STUB 19 #define STOREDL_STUB 20 #define STOREDR_STUB 21 #define INVCODE_STUB 22 /* branch codes */ #define TAKEN 1 #define NOTTAKEN 2 #define NULLDS 3 #define MAXBLOCK 4096 #define MAX_OUTPUT_BLOCK_SIZE 262144 #define CLOCK_DIVIDER g_dev.r4300.cp0.count_per_op struct regstat { signed char regmap_entry[HOST_REGS]; signed char regmap[HOST_REGS]; uint64_t was32; uint64_t is32; uint64_t wasdirty; uint64_t dirty; uint64_t u; uint64_t uu; u_int wasconst; u_int isconst; uint64_t constmap[HOST_REGS]; }; struct ll_entry { void *addr; void *clean_addr; void *copy; struct ll_entry *next; u_int vaddr; u_int reg32; u_int start; u_int length; }; /* linkage */ void verify_code(void); void cc_interrupt(void); void do_interrupt(void); void fp_exception(void); void jump_syscall(void); void jump_eret(void); void dyna_linker(void); void dyna_linker_ds(void); void breakpoint(void); int new_recompile_block(int addr); void invalidate_block(u_int block); void *get_addr_ht(u_int vaddr); void *get_addr_32(u_int vaddr,u_int flags); static void load_regs_entry(int t); static void inline_readstub(int type,int i,u_int addr_const,char addr,struct regstat *i_regs,int target,int adj,u_int reglist); void *base_addr; void *base_addr_rx; u_char *out; unsigned int using_tlb; unsigned int stop_after_jal; static u_int start; static u_int *source; static u_int pagelimit; static char insn[MAXBLOCK][10]; static u_char itype[MAXBLOCK]; static u_char opcode[MAXBLOCK]; static u_char opcode2[MAXBLOCK]; static u_char bt[MAXBLOCK]; static u_char rs1[MAXBLOCK]; static u_char rs2[MAXBLOCK]; static u_char rt1[MAXBLOCK]; static u_char rt2[MAXBLOCK]; static u_char us1[MAXBLOCK]; static u_char us2[MAXBLOCK]; static u_char dep1[MAXBLOCK]; static u_char dep2[MAXBLOCK]; static u_char lt1[MAXBLOCK]; static int imm[MAXBLOCK]; static u_int ba[MAXBLOCK]; static char likely[MAXBLOCK]; static char is_ds[MAXBLOCK]; static char ooo[MAXBLOCK]; static uint64_t unneeded_reg[MAXBLOCK]; static uint64_t unneeded_reg_upper[MAXBLOCK]; static uint64_t branch_unneeded_reg[MAXBLOCK]; static uint64_t branch_unneeded_reg_upper[MAXBLOCK]; static uint64_t p32[MAXBLOCK]; static uint64_t pr32[MAXBLOCK]; static signed char regmap_pre[MAXBLOCK][HOST_REGS]; static uint64_t constmap[MAXBLOCK][HOST_REGS]; static struct regstat regs[MAXBLOCK]; static struct regstat branch_regs[MAXBLOCK]; static signed char minimum_free_regs[MAXBLOCK]; static u_int needed_reg[MAXBLOCK]; static uint64_t requires_32bit[MAXBLOCK]; static u_int wont_dirty[MAXBLOCK]; static u_int will_dirty[MAXBLOCK]; static int ccadj[MAXBLOCK]; static int slen; static uintptr_t instr_addr[MAXBLOCK]; static uintptr_t link_addr[MAXBLOCK][3]; static int linkcount; static uintptr_t stubs[MAXBLOCK*3][8]; static int stubcount; static int literalcount; static int is_delayslot; static int cop1_usable; static char *copy; static int expirep; static u_int dirty_entry_count; static u_int copy_size; static struct ll_entry* hash_table[65536][2]; static struct ll_entry *jump_in[4096]; static struct ll_entry *jump_dirty[4096]; static struct ll_entry *jump_out[4096]; static unsigned char restore_candidate[512]; #if COUNT_NOTCOMPILEDS static int notcompiledCount = 0; #endif #if ASSEM_DEBUG static signed char regmap[MAXBLOCK][HOST_REGS]; static signed char regmap_entry[MAXBLOCK][HOST_REGS]; #endif static void clear_all_regs(signed char regmap[]) { int hr; for (hr=0;hrregmap[hr]&63)==reg) { cur->dirty|=1LL<dirty>>hr)&1) { reg=cur->regmap[hr]; if(reg>=64) if((cur->is32>>(reg&63))&1) cur->regmap[hr]=-1; } } } static void set_const(struct regstat *cur,signed char reg,uint64_t value) { int hr; if(!reg) return; for (hr=0;hrregmap[hr]==reg) { cur->isconst|=1<constmap[hr]=value; } else if((cur->regmap[hr]^64)==reg) { cur->isconst|=1<constmap[hr]=value>>32; } } } static void clear_const(struct regstat *cur,signed char reg) { int hr; if(!reg) return; for (hr=0;hrregmap[hr]&63)==reg) { cur->isconst&=~(1<regmap[hr]&63)==reg) { return (cur->isconst>>hr)&1; } } return 0; } static uint64_t get_const(struct regstat *cur,signed char reg) { int hr; if(!reg) return 0; for (hr=0;hrregmap[hr]==reg) { return cur->constmap[hr]; } } DebugMessage(M64MSG_ERROR, "Unknown constant in r%d",reg); exit(1); } // Least soon needed registers // Look at the next ten instructions and see which registers // will be used. Try not to reallocate these. static void lsn(u_char hsn[], int i, int *preferred_reg) { int j; int b=-1; for(j=0;j<9;j++) { if(i+j>=slen) { j=slen-i-1; break; } if(itype[i+j]==UJUMP||itype[i+j]==RJUMP||(source[i+j]>>16)==0x1000) { // Don't go past an unconditional jump j++; break; } } for(;j>=0;j--) { if(rs1[i+j]) hsn[rs1[i+j]]=j; if(rs2[i+j]) hsn[rs2[i+j]]=j; if(rt1[i+j]) hsn[rt1[i+j]]=j; if(rt2[i+j]) hsn[rt2[i+j]]=j; if(itype[i+j]==STORE || itype[i+j]==STORELR) { // Stores can allocate zero hsn[rs1[i+j]]=j; hsn[rs2[i+j]]=j; } // On some architectures stores need invc_ptr #if defined(HOST_IMM8) || defined(NEED_INVC_PTR) if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39) { hsn[INVCP]=j; } #endif if(i+j>=0&&(itype[i+j]==UJUMP||itype[i+j]==CJUMP||itype[i+j]==SJUMP||itype[i+j]==FJUMP)) { hsn[CCREG]=j; b=j; } } if(b>=0) { if(ba[i+b]>=start && ba[i+b]<(start+slen*4)) { // Follow first branch int t=(ba[i+b]-start)>>2; j=7-b;if(t+j>=slen) j=slen-t-1; for(;j>=0;j--) { if(rs1[t+j]) if(hsn[rs1[t+j]]>j+b+2) hsn[rs1[t+j]]=j+b+2; if(rs2[t+j]) if(hsn[rs2[t+j]]>j+b+2) hsn[rs2[t+j]]=j+b+2; //if(rt1[t+j]) if(hsn[rt1[t+j]]>j+b+2) hsn[rt1[t+j]]=j+b+2; //if(rt2[t+j]) if(hsn[rt2[t+j]]>j+b+2) hsn[rt2[t+j]]=j+b+2; } } // TODO: preferred register based on backward branch } // Delay slot should preferably not overwrite branch conditions or cycle count if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP)) { if(rs1[i-1]) if(hsn[rs1[i-1]]>1) hsn[rs1[i-1]]=1; if(rs2[i-1]) if(hsn[rs2[i-1]]>1) hsn[rs2[i-1]]=1; hsn[CCREG]=1; // ...or hash tables hsn[RHASH]=1; hsn[RHTBL]=1; } // Coprocessor load/store needs FTEMP, even if not declared if(itype[i]==C1LS) { hsn[FTEMP]=0; } // Load L/R also uses FTEMP as a temporary register if(itype[i]==LOADLR) { hsn[FTEMP]=0; } // Also 64-bit SDL/SDR if(opcode[i]==0x2c||opcode[i]==0x2d) { hsn[FTEMP]=0; } // Don't remove the TLB registers either if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS ) { hsn[TLREG]=0; } // Don't remove the miniht registers if(itype[i]==UJUMP||itype[i]==RJUMP) { hsn[RHASH]=0; hsn[RHTBL]=0; } } // We only want to allocate registers if we're going to use them again soon static int needed_again(int r, int i) { int j; /*int b=-1;*/ int rn=10; if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) { if(ba[i-1]start+slen*4-4) return 0; // Don't need any registers if exiting the block } for(j=0;j<9;j++) { if(i+j>=slen) { j=slen-i-1; break; } if(itype[i+j]==UJUMP||itype[i+j]==RJUMP||(source[i+j]>>16)==0x1000) { // Don't go past an unconditional jump j++; break; } if(itype[i+j]==SYSCALL||((source[i+j]&0xfc00003f)==0x0d)) { break; } } for(;j>=1;j--) { if(rs1[i+j]==r) rn=j; if(rs2[i+j]==r) rn=j; if((unneeded_reg[i+j]>>r)&1) rn=10; if(i+j>=0&&(itype[i+j]==UJUMP||itype[i+j]==CJUMP||itype[i+j]==SJUMP||itype[i+j]==FJUMP)) { /*b=j;*/ } } /* if(b>=0) { if(ba[i+b]>=start && ba[i+b]<(start+slen*4)) { // Follow first branch int o=rn; int t=(ba[i+b]-start)>>2; j=7-b;if(t+j>=slen) j=slen-t-1; for(;j>=0;j--) { if(!((unneeded_reg[t+j]>>r)&1)) { if(rs1[t+j]==r) if(rn>j+b+2) rn=j+b+2; if(rs2[t+j]==r) if(rn>j+b+2) rn=j+b+2; } else rn=o; } } }*/ if(rn<10) return 1; return 0; } // Try to match register allocations at the end of a loop with those // at the beginning static int loop_reg(int i, int r, int hr) { int j,k; for(j=0;j<9;j++) { if(i+j>=slen) { j=slen-i-1; break; } if(itype[i+j]==UJUMP||itype[i+j]==RJUMP||(source[i+j]>>16)==0x1000) { // Don't go past an unconditional jump j++; break; } } k=0; if(i>0){ if(itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP) k--; } for(;k>r)&1)) return hr; if(r>64&&((unneeded_reg_upper[i+k]>>r)&1)) return hr; if(i+k>=0&&(itype[i+k]==UJUMP||itype[i+k]==CJUMP||itype[i+k]==SJUMP||itype[i+k]==FJUMP)) { if(ba[i+k]>=start && ba[i+k]<(start+i*4)) { int t=(ba[i+k]-start)>>2; int reg=get_reg(regs[t].regmap_entry,r); if(reg>=0) return reg; //reg=get_reg(regs[t+1].regmap_entry,r); //if(reg>=0) return reg; } } } return hr; } // Basic liveness analysis for MIPS registers static void unneeded_registers(int istart,int iend,int r) { int i; uint64_t u,uu,b,bu; uint64_t temp_u,temp_uu; uint64_t tdep; if(iend==slen-1) { u=1;uu=1; }else{ u=unneeded_reg[iend+1]; uu=unneeded_reg_upper[iend+1]; u=1;uu=1; } for (i=iend;i>=istart;i--) { //DebugMessage(M64MSG_VERBOSE, "unneeded registers i=%d (%d,%d) r=%d",i,istart,iend,r); if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { // If subroutine call, flag return address as a possible branch target if(rt1[i]==31 && i=(start+slen*4)) { // Branch out of this block, flush all regs u=1; uu=1; /* Hexagon hack if(itype[i]==UJUMP&&rt1[i]==31) { uu=u=0x300C00F; // Discard at, v0-v1, t6-t9 } if(itype[i]==RJUMP&&rs1[i]==31) { uu=u=0x300C0F3; // Discard at, a0-a3, t6-t9 } if(start>0x80000400&&start<0x80800000) { if(itype[i]==UJUMP&&rt1[i]==31) { //uu=u=0x30300FF0FLL; // Discard at, v0-v1, t0-t9, lo, hi uu=u=0x300FF0F; // Discard at, v0-v1, t0-t9 } if(itype[i]==RJUMP&&rs1[i]==31) { //uu=u=0x30300FFF3LL; // Discard at, a0-a3, t0-t9, lo, hi uu=u=0x300FFF3; // Discard at, a0-a3, t0-t9 } }*/ branch_unneeded_reg[i]=u; branch_unneeded_reg_upper[i]=uu; // Merge in delay slot tdep=(~uu>>rt1[i+1])&1; u|=(1LL<>2]=1; if(ba[i]<=start+i*4) { // Backward branch if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) { // Unconditional branch temp_u=1;temp_uu=1; } else { // Conditional branch (not taken case) temp_u=unneeded_reg[i+2]; temp_uu=unneeded_reg_upper[i+2]; } // Merge in delay slot tdep=(~temp_uu>>rt1[i+1])&1; temp_u|=(1LL<>rt1[i])&1; temp_u|=(1LL<>2,i-1,r+1); }else{ unneeded_reg[(ba[i]-start)>>2]=1; unneeded_reg_upper[(ba[i]-start)>>2]=1; } } /*else*/ if(1) { if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) { // Unconditional branch u=unneeded_reg[(ba[i]-start)>>2]; uu=unneeded_reg_upper[(ba[i]-start)>>2]; branch_unneeded_reg[i]=u; branch_unneeded_reg_upper[i]=uu; //u=1; //uu=1; //branch_unneeded_reg[i]=u; //branch_unneeded_reg_upper[i]=uu; // Merge in delay slot tdep=(~uu>>rt1[i+1])&1; u|=(1LL<>2]; bu=unneeded_reg_upper[(ba[i]-start)>>2]; branch_unneeded_reg[i]=b; branch_unneeded_reg_upper[i]=bu; //b=1; //bu=1; //branch_unneeded_reg[i]=b; //branch_unneeded_reg_upper[i]=bu; // Branch delay slot tdep=(~uu>>rt1[i+1])&1; b|=(1LL<>rt1[i])&1; // Written registers are unneeded u|=1LL<>r)&1) { if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); else DebugMessage(M64MSG_VERBOSE, " r%d",r); } } DebugMessage(M64MSG_VERBOSE, " UU:"); for(r=1;r<=CCREG;r++) { if(((unneeded_reg_upper[i]&~unneeded_reg[i])>>r)&1) { if(r==HIREG) DebugMessage(M64MSG_VERBOSE, " HI"); else if(r==LOREG) DebugMessage(M64MSG_VERBOSE, " LO"); else DebugMessage(M64MSG_VERBOSE, " r%d",r); } }*/ } } // Identify registers which are likely to contain 32-bit values // This is used to predict whether any branches will jump to a // location with 64-bit values in registers. static void provisional_32bit(void) { int i,j; uint64_t is32=1; uint64_t lastbranch=1; for(i=0;i0) { if(itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP) { if(i>1) is32=lastbranch; else is32=1; } } if(i>1) { if(itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP) { if(likely[i-2]) { if(i>2) is32=lastbranch; else is32=1; } } if((opcode[i-2]&0x2f)==0x05) // BNE/BNEL { if(rs1[i-2]==0||rs2[i-2]==0) { if(rs1[i-2]) { is32|=1LL<=0;j--) { if(ba[j]==start+i*4) //temp_is32&=branch_regs[j].is32; temp_is32&=p32[j]; } for(j=i;j>s1)&1LL)<>s1)&1LL); is32&=~(1LL<=0x20&&op2<=0x23) { // ADD/ADDU/SUB/SUBU is32|=1LL<=0x24&&op2<=0x27) { // AND/OR/XOR/NOR uint64_t sr=((is32>>s1)&(is32>>s2)&1LL); is32&=~(1LL<=0x2c&&op2<=0x2d) { // DADD/DADDU if(s1==0&&s2==0) { is32|=1LL<>s1)&1LL); is32&=~(1LL<>s2)&1LL); is32&=~(1LL<=0x2e&&op2<=0x2f) { // DSUB/DSUBU if(s1==0&&s2==0) { is32|=1LL<>s1)&1LL); is32&=~(1LL<=0x1c&&op2<=0x1f) { // DMULT/DMULTU/DDIV/DDIVU is32&=~((1LL<>s1)&1LL); is32&=~(1LL<=0x14&&op2<=0x17) is32&=~(1LL<=0x38&&op2<0x3f) is32&=~(1LL<0) { if(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000) { if(rt1[i-1]==31) // JAL/JALR { // Subroutine call will return here, don't alloc any registers is32=1; } else if(i+1=0;i--) { int hr; if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { if(ba[i]=(start+slen*4)) { // Branch out of this block, don't need anything r32=0; } else { // Internal branch // Need whatever matches the target // (and doesn't get overwritten by the delay slot instruction) r32=0; int t=(ba[i]-start)>>2; if(ba[i]>start+i*4) { // Forward branch //if(!(requires_32bit[t]&~regs[i].was32)) // r32|=requires_32bit[t]&(~(1LL<>16)!=0x1000) { if(i0) { if((regs[i].was32>>us1[i+1])&1) r32|=1LL<0) { if((regs[i].was32>>us2[i+1])&1) r32|=1LL<>dep1[i+1])&1)) { if((regs[i].was32>>dep1[i+1])&1) r32|=1LL<>dep2[i+1])&1)) { if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<0) { if((regs[i].was32>>us1[i])&1) r32|=1LL<0) { if((regs[i].was32>>us2[i])&1) r32|=1LL<>dep1[i])&1)) { if((regs[i].was32>>dep1[i])&1) r32|=1LL<>dep2[i])&1)) { if((regs[i].was32>>dep2[i])&1) r32|=1LL<0&®s[i].regmap_entry[hr]<64) { if((regs[i].was32>>regs[i].regmap_entry[hr])&(regs[i].wasdirty>>hr)&1) { if(!((unneeded_reg_upper[i]>>regs[i].regmap_entry[hr])&1)) pr32[i]|=1LL<=istart;i--) { if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { if(ba[i]=(start+slen*4)) { // Branch out of this block, flush all regs if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) { // Unconditional branch will_dirty_i=0; wont_dirty_i=0; // Merge in delay slot (will dirty) for(r=0;r33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<>16)==0x1000) { // Unconditional branch temp_will_dirty=0; temp_wont_dirty=0; // Merge in delay slot (will dirty) for(r=0;r33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<0 && (regmap_pre[i][r]&63)>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<>2,i-1,0); }else{ // Limit recursion. It can take an excessive amount // of time if there are a lot of nested loops. will_dirty[(ba[i]-start)>>2]=0; wont_dirty[(ba[i]-start)>>2]=-1; } } /*else*/ if(1) { if(itype[i]==RJUMP||itype[i]==UJUMP||(source[i]>>16)==0x1000) { // Unconditional branch will_dirty_i=0; wont_dirty_i=0; //if(ba[i]>start+i*4) { // Disable recursion (for debugging) for(r=0;r>2].regmap_entry[r]) { will_dirty_i|=will_dirty[(ba[i]-start)>>2]&(1<>2]&(1<=0) { will_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<>2]>>(branch_regs[i].regmap[r]&63))&1)<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<start+i*4) { // Disable recursion (for debugging) for(r=0;r>2].regmap_entry[r]) { will_dirty_i&=will_dirty[(ba[i]-start)>>2]&(1<>2]&(1<=0) { will_dirty_i&=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<>2]>>(target_reg&63))&1)<>2].regmap_entry[r]) { will_dirty[i+1]&=will_dirty[(ba[i]-start)>>2]&(1<>2]&(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<istart) { if(itype[i]!=RJUMP&&itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP&&itype[i]!=FJUMP) { // Don't store a register immediately after writing it, // may prevent dual-issue. if((regs[i].regmap[r]&63)==rt1[i-1]) wont_dirty_i|=1<>r)&1) { DebugMessage(M64MSG_VERBOSE, " r%d",r); } }*/ //if(i==istart||(itype[i-1]!=RJUMP&&itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=FJUMP)) { regs[i].dirty|=will_dirty_i; #ifndef DESTRUCTIVE_WRITEBACK regs[i].dirty&=wont_dirty_i; if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { if(i>16)!=0x1000) { for(r=0;r>r)&1));*/} } } } } else { if(i>r)&1));*/} } } } } #endif //} } // Deal with changed mappings temp_will_dirty=will_dirty_i; temp_wont_dirty=wont_dirty_i; for(r=0;r=0&&(nr=get_reg(regs[i].regmap,regmap_pre[i][r]))>=0) { // Register moved to a different register will_dirty_i&=~(1<>nr)&1)<>nr)&1)<0 && (regmap_pre[i][r]&63)>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<>r)&1));*/ } } } } } } // Is the branch target a valid internal jump? static int internal_branch(uint64_t i_is32,int addr) { if(addr&1) return 0; // Indirect (register) jump if((u_int)addr>=start && (u_int)addr>2; // Delay slots are not valid branch targets //if(t>0&&(itype[t-1]==RJUMP||itype[t-1]==UJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) return 0; // 64 -> 32 bit transition requires a recompile /*if(is32[t]&~unneeded_reg_upper[t]&~i_is32) { if(requires_32bit[t]&~i_is32) DebugMessage(M64MSG_VERBOSE, "optimizable: no"); else DebugMessage(M64MSG_VERBOSE, "optimizable: yes"); }*/ //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0; if(requires_32bit[t]&~i_is32) return 0; else return 1; } return 0; } static int get_final_value(int hr, int i, int *value) { int reg=regs[i].regmap[hr]; while(i>hr)&1)) break; if(bt[i+1]) break; i++; } if(i>reg)&1); }else{ return !((unneeded_reg_upper[i+1]>>reg)&1); } } static int match_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) { if((u_int)addr>=start && (u_int)addr>2; int hr; if(regs[t].regmap_entry[HOST_CCREG]!=CCREG) return 0; for(hr=0;hr=0&&(regs[t].regmap_entry[hr]|64)>hr)&1) { if(i_regmap[hr]>i_regmap[hr])&1)) return 0; } else if(i_regmap[hr]>=64&&i_regmap[hr]>(i_regmap[hr]&63))&1)) return 0; } } } else // Same register but is it 32-bit or dirty? if(i_regmap[hr]>=0) { if(!((regs[t].dirty>>hr)&1)) { if((i_dirty>>hr)&1) { if(!((unneeded_reg[t]>>i_regmap[hr])&1)) { //DebugMessage(M64MSG_VERBOSE, "%x: dirty no match",addr); return 0; } } } if((((regs[t].was32^i_is32)&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1) { //DebugMessage(M64MSG_VERBOSE, "%x: is32 no match",addr); return 0; } } } } //if(is32[t]&~unneeded_reg_upper[t]&~i_is32) return 0; if(requires_32bit[t]&~i_is32) return 0; // Delay slots are not valid branch targets //if(t>0&&(itype[t-1]==RJUMP||itype[t-1]==UJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) return 0; // Delay slots require additional processing, so do not match if(is_ds[t]) return 0; } else { int hr; for(hr=0;hr=0) { if(hr!=HOST_CCREG||i_regmap[hr]!=CCREG) { if((i_dirty>>hr)&1) { return 0; } } } } } } return 1; } // Allocate every register, preserving source/target regs static void alloc_all(struct regstat *cur,int i) { int hr; for(hr=0;hrregmap[hr]&63)!=rs1[i])&&((cur->regmap[hr]&63)!=rs2[i])&& ((cur->regmap[hr]&63)!=rt1[i])&&((cur->regmap[hr]&63)!=rt2[i])) { cur->regmap[hr]=-1; cur->dirty&=~(1LL<regmap[hr]&63)==0) { cur->regmap[hr]=-1; cur->dirty&=~(1LL<>16)^vaddr)&0xFFFF]; if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) { ht_bin[1]=NULL; } if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) { ht_bin[0]=ht_bin[1]; ht_bin[1]=NULL; } } /**** Interpreted opcodes ****/ #define UPDATE_COUNT_IN \ struct r4300_core* r4300 = &g_dev.r4300; \ struct new_dynarec_hot_state* state = &r4300->new_dynarec_hot_state; \ state->cycle_count += count; \ state->pending_exception = 0; #define UPDATE_COUNT_OUT \ state->cycle_count -= !state->pending_exception * count; void* SYSCALL_new(void) { struct r4300_core* r4300 = &g_dev.r4300; struct new_dynarec_hot_state* state = &r4300->new_dynarec_hot_state; r4300->delay_slot = 0; cached_interp_SYSCALL(); return get_addr_ht(state->pcaddr); } void* ERET_new(void) { struct r4300_core* r4300 = &g_dev.r4300; struct new_dynarec_hot_state* state = &r4300->new_dynarec_hot_state; cp0_update_count(r4300); if (state->cp0_regs[CP0_STATUS_REG] & CP0_STATUS_ERL) { DebugMessage(M64MSG_ERROR, "error in ERET"); state->stop = 1; } else { state->cp0_regs[CP0_STATUS_REG] &= ~CP0_STATUS_EXL; state->pcaddr = state->cp0_regs[CP0_EPC_REG]; } r4300->llbit = 0; r4300->delay_slot = 0; r4300_check_interrupt(r4300, CP0_CAUSE_IP2, r4300->mi->regs[MI_INTR_REG] & r4300->mi->regs[MI_INTR_MASK_REG]); // ??? r4300->cp0.last_addr = state->pcaddr; state->pending_exception = 0; if (state->cycle_count >= 0) { gen_interrupt(r4300); } if(state->stop) return NULL; if(state->pending_exception) return get_addr_ht(state->pcaddr); else { uint32_t is64 = 0; for(int i=0;i<32;i++) is64 = (((int)(state->regs[i]>>32)^((int)state->regs[i]>>31))!=0)<hi>>32)^((int)state->hi>>31))!=0); is64 |= (((int)(state->lo>>32)^((int)state->lo>>31))!=0); return get_addr_32(state->pcaddr, is64); } } static void TLBWI_new(int pcaddr, int count) { unsigned int i; UPDATE_COUNT_IN state->pcaddr = pcaddr; /* Remove old entries */ unsigned int old_start_even=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].start_even; unsigned int old_end_even=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].end_even; unsigned int old_start_odd=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].start_odd; unsigned int old_end_odd=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].end_odd; for (i=old_start_even>>12; i<=old_end_even>>12; i++) { if(i<0x80000||i>0xBFFFF) { invalidate_block(i); state->memory_map[i]=(uintptr_t)-1; } } for (i=old_start_odd>>12; i<=old_end_odd>>12; i++) { if(i<0x80000||i>0xBFFFF) { invalidate_block(i); state->memory_map[i]=(uintptr_t)-1; } } cached_interp_TLBWI(); //DebugMessage(M64MSG_VERBOSE, "TLBWI: index=%d",state->cp0_regs[CP0_INDEX_REG]); //DebugMessage(M64MSG_VERBOSE, "TLBWI: start_even=%x end_even=%x phys_even=%x v=%d d=%d",r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].start_even,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].end_even,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].phys_even,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].v_even,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].d_even); //DebugMessage(M64MSG_VERBOSE, "TLBWI: start_odd=%x end_odd=%x phys_odd=%x v=%d d=%d",r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].start_odd,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].end_odd,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].phys_odd,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].v_odd,r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].d_odd); /* Combine r4300->cp0.tlb.LUT_r, r4300->cp0.tlb.LUT_w, and invalid_code into a single table for fast look up. */ for (i=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].start_even>>12; i<=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].end_even>>12; i++) { //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,r4300->cp0.tlb.LUT_r[i],r4300->cp0.tlb.LUT_w[i]); if(i<0x80000||i>0xBFFFF) { if(r4300->cp0.tlb.LUT_r[i]) { state->memory_map[i]=((uintptr_t)g_dev.rdram.dram+(uintptr_t)((r4300->cp0.tlb.LUT_r[i]&0xFFFFF000)-0x80000000)-(i<<12))>>2; // FIXME: should make sure the physical page is invalid too if(!r4300->cp0.tlb.LUT_w[i]||!r4300->cached_interp.invalid_code[i]) { state->memory_map[i]|=WRITE_PROTECT; // Write protect }else{ assert(r4300->cp0.tlb.LUT_r[i]==r4300->cp0.tlb.LUT_w[i]); } if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); // Tell the dynamic recompiler to generate tlb lookup code using_tlb=1; } else state->memory_map[i]=(uintptr_t)-1; } //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,state->memory_map[i],state->memory_map[i]<<2); } for (i=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].start_odd>>12; i<=r4300->cp0.tlb.entries[state->cp0_regs[CP0_INDEX_REG]&0x3F].end_odd>>12; i++) { //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,r4300->cp0.tlb.LUT_r[i],r4300->cp0.tlb.LUT_w[i]); if(i<0x80000||i>0xBFFFF) { if(r4300->cp0.tlb.LUT_r[i]) { state->memory_map[i]=((uintptr_t)g_dev.rdram.dram+(uintptr_t)((r4300->cp0.tlb.LUT_r[i]&0xFFFFF000)-0x80000000)-(i<<12))>>2; // FIXME: should make sure the physical page is invalid too if(!r4300->cp0.tlb.LUT_w[i]||!r4300->cached_interp.invalid_code[i]) { state->memory_map[i]|=WRITE_PROTECT; // Write protect }else{ assert(r4300->cp0.tlb.LUT_r[i]==r4300->cp0.tlb.LUT_w[i]); } if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); // Tell the dynamic recompiler to generate tlb lookup code using_tlb=1; } else state->memory_map[i]=(uintptr_t)-1; } //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,state->memory_map[i],state->memory_map[i]<<2); } UPDATE_COUNT_OUT } static void TLBWR_new(int pcaddr, int count) { unsigned int i; UPDATE_COUNT_IN state->pcaddr = pcaddr; cp0_update_count(r4300); state->cp0_regs[CP0_RANDOM_REG] = (state->cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - state->cp0_regs[CP0_WIRED_REG])) + state->cp0_regs[CP0_WIRED_REG]; /* Remove old entries */ unsigned int old_start_even=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].start_even; unsigned int old_end_even=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].end_even; unsigned int old_start_odd=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].start_odd; unsigned int old_end_odd=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].end_odd; for (i=old_start_even>>12; i<=old_end_even>>12; i++) { if(i<0x80000||i>0xBFFFF) { invalidate_block(i); state->memory_map[i]=(uintptr_t)-1; } } for (i=old_start_odd>>12; i<=old_end_odd>>12; i++) { if(i<0x80000||i>0xBFFFF) { invalidate_block(i); state->memory_map[i]=(uintptr_t)-1; } } cached_interp_TLBWR(); /* Combine r4300->cp0.tlb.LUT_r, r4300->cp0.tlb.LUT_w, and invalid_code into a single table for fast look up. */ for (i=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].start_even>>12; i<=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].end_even>>12; i++) { //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,r4300->cp0.tlb.LUT_r[i],r4300->cp0.tlb.LUT_w[i]); if(i<0x80000||i>0xBFFFF) { if(r4300->cp0.tlb.LUT_r[i]) { state->memory_map[i]=((uintptr_t)g_dev.rdram.dram+(uintptr_t)((r4300->cp0.tlb.LUT_r[i]&0xFFFFF000)-0x80000000)-(i<<12))>>2; // FIXME: should make sure the physical page is invalid too if(!r4300->cp0.tlb.LUT_w[i]||!r4300->cached_interp.invalid_code[i]) { state->memory_map[i]|=WRITE_PROTECT; // Write protect }else{ assert(r4300->cp0.tlb.LUT_r[i]==r4300->cp0.tlb.LUT_w[i]); } if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); // Tell the dynamic recompiler to generate tlb lookup code using_tlb=1; } else state->memory_map[i]=(uintptr_t)-1; } //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,state->memory_map[i],state->memory_map[i]<<2); } for (i=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].start_odd>>12; i<=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].end_odd>>12; i++) { //DebugMessage(M64MSG_VERBOSE, "%x: r:%8x w:%8x",i,r4300->cp0.tlb.LUT_r[i],r4300->cp0.tlb.LUT_w[i]); if(i<0x80000||i>0xBFFFF) { if(r4300->cp0.tlb.LUT_r[i]) { state->memory_map[i]=((uintptr_t)g_dev.rdram.dram+(uintptr_t)((r4300->cp0.tlb.LUT_r[i]&0xFFFFF000)-0x80000000)-(i<<12))>>2; // FIXME: should make sure the physical page is invalid too if(!r4300->cp0.tlb.LUT_w[i]||!r4300->cached_interp.invalid_code[i]) { state->memory_map[i]|=WRITE_PROTECT; // Write protect }else{ assert(r4300->cp0.tlb.LUT_r[i]==r4300->cp0.tlb.LUT_w[i]); } if(!using_tlb) DebugMessage(M64MSG_VERBOSE, "Enabled TLB"); // Tell the dynamic recompiler to generate tlb lookup code using_tlb=1; } else state->memory_map[i]=(uintptr_t)-1; } //DebugMessage(M64MSG_VERBOSE, "memory_map[%x]: %8x (+%8x)",i,state->memory_map[i],state->memory_map[i]<<2); } UPDATE_COUNT_OUT } static void MFC0_new(int copr, int count) { UPDATE_COUNT_IN state->fake_pc.f.r.nrd = copr; cached_interp_MFC0(); UPDATE_COUNT_OUT } static void MTC0_new(int copr, int count, int pcaddr) { UPDATE_COUNT_IN state->pcaddr = pcaddr; r4300->delay_slot = 0; state->fake_pc.f.r.nrd = copr; cached_interp_MTC0(); UPDATE_COUNT_OUT } #define BITS_BELOW_MASK32(x) ((UINT32_C(1) << (x)) - 1) #define BITS_ABOVE_MASK32(x) (~(BITS_BELOW_MASK32((x)))) #define BITS_BELOW_MASK64(x) ((UINT64_C(1) << (x)) - 1) #define BITS_ABOVE_MASK64(x) (~(BITS_BELOW_MASK64((x)))) static unsigned int bshift(uint32_t address) { return ((address & 3) ^ 3) << 3; } static unsigned int hshift(uint32_t address) { return ((address & 2) ^ 2) << 3; } static void read_byte_new(int pcaddr, int count) { uint32_t value; UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int shift = bshift(state->address); if (r4300_read_aligned_word(r4300, state->address, &value)) { state->rdword = (uint64_t)((value >> shift) & 0xff); } UPDATE_COUNT_OUT } static void read_hword_new(int pcaddr, int count) { uint32_t value; UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int shift = hshift(state->address); if (r4300_read_aligned_word(r4300, state->address, &value)) { state->rdword = (uint64_t)((value >> shift) & 0xffff); } UPDATE_COUNT_OUT } static void read_word_new(int pcaddr, int count) { uint32_t value; UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; if (r4300_read_aligned_word(r4300, state->address, &value)) { state->rdword = (uint64_t)(value); } UPDATE_COUNT_OUT } static void read_dword_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; r4300_read_aligned_dword(r4300, state->address, (uint64_t*)&state->rdword); UPDATE_COUNT_OUT } static void write_byte_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int shift = bshift(state->address); state->wword <<= shift; r4300_write_aligned_word(r4300, state->address, state->wword, UINT32_C(0xff) << shift); UPDATE_COUNT_OUT } static void write_hword_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int shift = hshift(state->address); state->wword <<= shift; r4300_write_aligned_word(r4300, state->address, state->wword, UINT32_C(0xffff) << shift); UPDATE_COUNT_OUT } static void write_word_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; r4300_write_aligned_word(r4300, state->address, state->wword, UINT32_C(0xffffffff)); UPDATE_COUNT_OUT } static void write_dword_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; /* NOTE: in dynarec, we only need an all-one mask */ r4300_write_aligned_dword(r4300, state->address, state->wdword, ~UINT64_C(0)); UPDATE_COUNT_OUT } static void LWL_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; uint32_t value; unsigned int n = (state->address & 3); unsigned int shift = 8 * n; uint32_t mask = BITS_BELOW_MASK32(8 * n); if (r4300_read_aligned_word(r4300, state->address & ~UINT32_C(0x3), &value)) { state->rdword = (uint64_t)((state->wword & mask) | (value << shift)); } UPDATE_COUNT_OUT } static void LWR_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; uint32_t value; unsigned int n = (state->address & 3); unsigned int shift = 8 * (3 - n); uint32_t mask = (n == 3) ? UINT32_C(0) : BITS_ABOVE_MASK32(8 * (n + 1)); if (r4300_read_aligned_word(r4300, state->address & ~UINT32_C(0x3), &value)) { state->rdword = (uint64_t)((state->wword & mask) | (value >> shift)); } UPDATE_COUNT_OUT } static void LDL_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; uint64_t value; unsigned int n = (state->address & 7); unsigned int shift = 8 * n; uint64_t mask = BITS_BELOW_MASK64(8 * n); if(r4300_read_aligned_dword(r4300, state->address & ~UINT32_C(7), &value)) { state->rdword = (state->wdword & mask) | (value << shift); } UPDATE_COUNT_OUT } static void LDR_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; uint64_t value; unsigned int n = (state->address & 7); unsigned int shift = 8 * (7 - n); uint64_t mask = (n == 7) ? UINT64_C(0) : BITS_ABOVE_MASK64(8 * (n + 1)); if(r4300_read_aligned_dword(r4300, state->address & ~UINT32_C(7), &value)){ state->rdword = (state->wdword & mask) | (value >> shift); } UPDATE_COUNT_OUT } static void SWL_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int n = (state->address & 3); unsigned int shift = 8 * n; uint32_t mask = (n == 0) ? ~UINT32_C(0) : BITS_BELOW_MASK32(8 * (4 - n)); r4300_write_aligned_word(r4300, state->address & ~UINT32_C(0x3), state->wword >> shift, mask); UPDATE_COUNT_OUT } static void SWR_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int n = (state->address & 3); unsigned int shift = 8 * (3 - n); uint32_t mask = BITS_ABOVE_MASK32(8 * (3 - n)); r4300_write_aligned_word(r4300, state->address & ~UINT32_C(0x3), state->wword << shift, mask); UPDATE_COUNT_OUT } static void SDL_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int n = (state->address & 7); unsigned int shift = 8 * n; uint64_t mask = (n == 0) ? ~UINT64_C(0) : BITS_BELOW_MASK64(8 * (8 - n)); r4300_write_aligned_dword(r4300, state->address & ~UINT32_C(0x7), state->wdword >> shift, mask); UPDATE_COUNT_OUT } static void SDR_new(int pcaddr, int count) { UPDATE_COUNT_IN state->pcaddr = pcaddr&~1; r4300->delay_slot = pcaddr & 1; unsigned int n = (state->address & 7); unsigned int shift = 8 * (7 - n); uint64_t mask = BITS_ABOVE_MASK64(8 * (7 - n)); r4300_write_aligned_dword(r4300, state->address & ~UINT32_C(0x7), state->wdword << shift, mask); UPDATE_COUNT_OUT } #if NEW_DYNAREC == NEW_DYNAREC_X86 #include "x86/assem_x86.c" #elif NEW_DYNAREC == NEW_DYNAREC_X64 #include "x64/assem_x64.c" #elif NEW_DYNAREC == NEW_DYNAREC_ARM #include "arm/assem_arm.c" #elif NEW_DYNAREC == NEW_DYNAREC_ARM64 #include "arm64/assem_arm64.c" #else #error Unsupported dynarec architecture #endif static void tlb_speed_hacks() { // Goldeneye hack if (strncmp((char *) ROM_HEADER.Name, "GOLDENEYE",9) == 0) { u_int addr; int n; switch (ROM_HEADER.Country_code) { case 0x45: // U addr=0x34b30; break; case 0x4A: // J addr=0x34b70; break; case 0x50: // E addr=0x329f0; break; default: // Unknown country code addr=0; break; } uintptr_t rom_addr=(uintptr_t)g_dev.cart.cart_rom.rom; #ifdef ROM_COPY // Since memory_map is 32-bit, on 64-bit systems the rom needs to be // in the lower 4G of memory to use this hack. Copy it if necessary. if((void *)g_dev.cart.cart_rom.rom>(void *)0xffffffff) { munmap(ROM_COPY, 67108864); if(mmap(ROM_COPY, 12582912, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) <= 0) {DebugMessage(M64MSG_ERROR, "mmap() failed");} memcpy(ROM_COPY,g_dev.cart.cart_rom.rom,12582912); rom_addr=(uintptr_t)ROM_COPY; } #endif if(addr) { for(n=0x7F000;n<0x80000;n++) { g_dev.r4300.new_dynarec_hot_state.memory_map[n]=(((uintptr_t)(rom_addr+addr-0x7F000000))>>2)|WRITE_PROTECT; } } } } /**** Linker ****/ u_int verify_dirty(struct ll_entry * head) { void *source; if((int)head->start>=0xa0000000&&(int)head->start<0xa07fffff) { source=(void *)((uintptr_t)g_dev.rdram.dram+head->start-0xa0000000); }else if((int)head->start>=0xa4000000&&(int)head->start<0xa4001000) { source=(void *)((uintptr_t)g_dev.sp.mem+head->start-0xa4000000); }else if((int)head->start>=0x80000000&&(int)head->start<0x80800000) { source=(void *)((uintptr_t)g_dev.rdram.dram+head->start-(uintptr_t)0x80000000); } else if((signed int)head->start>=(signed int)0xC0000000) { unsigned int page=head->start>>12; uintptr_t map_value=g_dev.r4300.new_dynarec_hot_state.memory_map[page]; if((intptr_t)map_value<(intptr_t)0) return head->vaddr; while(page<((head->start+head->length-1)>>12)) { if((g_dev.r4300.new_dynarec_hot_state.memory_map[++page]<<2)!=(map_value<<2)) return head->vaddr; } source=(void*)(head->start+(map_value<<2)); } else assert(0); if(memcmp(source,head->copy,head->length)) return head->vaddr; else return 0; } // Add virtual address mapping for 32-bit compiled block static struct ll_entry *ll_add_32(struct ll_entry **head,int vaddr,u_int reg32,void *addr,void *clean_addr,u_int start,void *copy,u_int length) { struct ll_entry *new_entry; new_entry=(struct ll_entry *)malloc(sizeof(struct ll_entry)); assert(new_entry!=NULL); new_entry->vaddr=vaddr; new_entry->reg32=reg32; new_entry->addr=addr; new_entry->clean_addr=clean_addr; new_entry->start=start; new_entry->copy=copy; new_entry->length=length; new_entry->next=*head; *head=new_entry; return new_entry; } // Add virtual address mapping to linked list static struct ll_entry *ll_add(struct ll_entry **head,int vaddr,void *addr,void *clean_addr,u_int start,void *copy,u_int length) { return ll_add_32(head,vaddr,0,addr,clean_addr,start,copy,length); } static void ll_remove_matching_addrs(struct ll_entry **head,intptr_t addr,int shift) { struct ll_entry **cur=head; struct ll_entry *next; while(*cur) { if((((uintptr_t)((*cur)->addr)-(uintptr_t)base_addr)>>shift)==((addr-(uintptr_t)base_addr)>>shift) || (((uintptr_t)((*cur)->addr)-(uintptr_t)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((addr-(uintptr_t)base_addr)>>shift)) { if((*cur)->addr!=(*cur)->clean_addr){ //jump_dirty assert(head>=jump_dirty&&head<(jump_dirty+4096)); u_int length=(*cur)->length; u_int* ptr=(u_int*)(*cur)->copy; ptr[length>>2]--; if(ptr[length>>2]==0){ free(ptr); copy_size-=length+4; } } inv_debug("EXP: Remove pointer to %x (%x)\n",(intptr_t)(*cur)->addr,(*cur)->vaddr); remove_hash((*cur)->vaddr); next=(*cur)->next; free(*cur); *cur=next; } else { cur=&((*cur)->next); } } } // Remove all entries from linked list static void ll_clear(struct ll_entry **head) { struct ll_entry *cur; struct ll_entry *next; if((cur=*head)) { *head=0; while(cur) { if(cur->addr!=cur->clean_addr){ //jump_dirty assert(head>=jump_dirty&&head<(jump_dirty+4096)); u_int length=cur->length; u_int* ptr=(u_int*)cur->copy; ptr[length>>2]--; if(ptr[length>>2]==0){ free(ptr); copy_size-=length+4; } } next=cur->next; free(cur); cur=next; } } } // Dereference the pointers and remove if it matches static void ll_kill_pointers(struct ll_entry *head,intptr_t addr,int shift) { while(head) { uintptr_t ptr=get_pointer(head->addr); inv_debug("EXP: Lookup pointer to %x at %x (%x)\n",(intptr_t)ptr,(intptr_t)head->addr,head->vaddr); if((((ptr-(uintptr_t)base_addr)>>shift)==((addr-(uintptr_t)base_addr)>>shift)) || (((ptr-(uintptr_t)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((addr-(uintptr_t)base_addr)>>shift))) { inv_debug("EXP: Kill pointer at %x (%x)\n",(intptr_t)head->addr,head->vaddr); uintptr_t host_addr=(intptr_t)kill_pointer(head->addr); #if NEW_DYNAREC >= NEW_DYNAREC_ARM needs_clear_cache[(host_addr-(uintptr_t)base_addr)>>17]|=1<<(((host_addr-(uintptr_t)base_addr)>>12)&31); #else /* avoid unused variable warning */ (void)host_addr; #endif } head=head->next; } } // Add an entry to jump_out after making a link static void add_link(u_int vaddr,void *src) { u_int page=(vaddr^0x80000000)>>12; if(page>262143&&g_dev.r4300.cp0.tlb.LUT_r[vaddr>>12]) page=(g_dev.r4300.cp0.tlb.LUT_r[vaddr>>12]^0x80000000)>>12; if(page>4095) page=2048+(page&2047); inv_debug("add_link: %x -> %x (%d)\n",(intptr_t)src,vaddr,page); (void)ll_add(jump_out+page,vaddr,src,src,0,NULL,0); //int ptr=get_pointer(src); //inv_debug("add_link: Pointer is to %x\n",(intptr_t)ptr); } static struct ll_entry *get_clean(struct r4300_core* r4300,u_int vaddr,u_int flags) { u_int page=(vaddr^0x80000000)>>12; if(page>262143&&r4300->cp0.tlb.LUT_r[vaddr>>12]) page=(r4300->cp0.tlb.LUT_r[vaddr>>12]^0x80000000)>>12; if(page>2048) page=2048+(page&2047); struct ll_entry *head; head=jump_in[page]; while(head!=NULL) { if(head->vaddr==vaddr&&(head->reg32&flags)==0) { return head; } head=head->next; } return NULL; } static struct ll_entry *get_dirty(struct r4300_core* r4300,u_int vaddr,u_int flags) { u_int page=(vaddr^0x80000000)>>12; u_int vpage=page; if(page>262143&&r4300->cp0.tlb.LUT_r[vaddr>>12]) page=(r4300->cp0.tlb.LUT_r[vaddr>>12]^0x80000000)>>12; if(page>2048) page=2048+(page&2047); if(vpage>262143&&r4300->cp0.tlb.LUT_r[vaddr>>12]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead if(vpage>2048) vpage=2048+(vpage&2047); struct ll_entry *head; head=jump_dirty[vpage]; while(head!=NULL) { if(head->vaddr==vaddr&&(head->reg32&flags)==0) { // Don't restore blocks which are about to expire from the cache if((((uintptr_t)head->addr-(uintptr_t)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { if(verify_dirty(head)==0) { r4300->cached_interp.invalid_code[vaddr>>12]=0; r4300->new_dynarec_hot_state.memory_map[vaddr>>12]|=WRITE_PROTECT; if(vpage<2048) { if(r4300->cp0.tlb.LUT_r[vaddr>>12]) { r4300->cached_interp.invalid_code[r4300->cp0.tlb.LUT_r[vaddr>>12]>>12]=0; r4300->new_dynarec_hot_state.memory_map[r4300->cp0.tlb.LUT_r[vaddr>>12]>>12]|=WRITE_PROTECT; } restore_candidate[vpage>>3]|=1<<(vpage&7); } else restore_candidate[page>>3]|=1<<(page&7); return head; } } } head=head->next; } return NULL; } void *dynamic_linker(void * src, u_int vaddr) { assert((vaddr&1)==0); struct r4300_core* r4300 = &g_dev.r4300; struct ll_entry *head; #ifndef DISABLE_BLOCK_LINKING head=get_clean(r4300,vaddr,~0); if(head!=NULL){ void* src_rw=(void*)(((intptr_t)src-(intptr_t)base_addr_rx)+(intptr_t)base_addr); #if NEW_DYNAREC == NEW_DYNAREC_ARM64 //TODO: Avoid disabling link between blocks for conditional branches int *ptr=(int*)src_rw; if((*ptr&0xfc000000)==0x14000000) { //b add_link(vaddr, add_pointer(src_rw,head->addr)); } #else add_link(vaddr, add_pointer(src_rw,head->addr)); #endif return (void*)(((intptr_t)head->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } #endif struct ll_entry **ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[0]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[1]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); #ifdef DISABLE_BLOCK_LINKING head=get_clean(r4300,vaddr,~0); if(head!=NULL){ ht_bin[1]=ht_bin[0]; ht_bin[0]=head; return (void*)(((intptr_t)head->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } #endif head=get_dirty(r4300,vaddr,~0); if(head!=NULL){ if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) { ht_bin[0]=head; // Replace existing entry } else { ht_bin[1]=ht_bin[0]; ht_bin[0]=head; } return (void*)(((intptr_t)head->clean_addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } int r=new_recompile_block(vaddr); if(r==0) return dynamic_linker(src,vaddr); // Execute in unmapped page, generate pagefault execption assert(r4300->cp0.tlb.LUT_r[(vaddr&~1) >> 12] == 0); assert((intptr_t)r4300->new_dynarec_hot_state.memory_map[(vaddr&~1) >> 12] < 0); r4300->delay_slot = vaddr&1; TLB_refill_exception(r4300, vaddr&~1, 2); return get_addr_ht(r4300->new_dynarec_hot_state.pcaddr); } void *dynamic_linker_ds(void * src, u_int vaddr) { struct r4300_core* r4300 = &g_dev.r4300; struct ll_entry *head; #ifndef DISABLE_BLOCK_LINKING head=get_clean(r4300,vaddr,~0); if(head!=NULL){ void* src_rw=(void*)(((intptr_t)src-(intptr_t)base_addr_rx)+(intptr_t)base_addr); #if NEW_DYNAREC == NEW_DYNAREC_ARM64 //TODO: Avoid disabling link between blocks for conditional branches int *ptr=(int*)src_rw; if((*ptr&0xfc000000)==0x14000000) { //b add_link(vaddr, add_pointer(src_rw,head->addr)); } #else add_link(vaddr, add_pointer(src_rw,head->addr)); #endif return (void*)(((intptr_t)head->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } #endif struct ll_entry **ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[0]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[1]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); #ifdef DISABLE_BLOCK_LINKING head=get_clean(r4300,vaddr,~0); if(head!=NULL){ ht_bin[1]=ht_bin[0]; ht_bin[0]=head; return (void*)(((intptr_t)head->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } #endif head=get_dirty(r4300,vaddr,~0); if(head!=NULL){ if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) { ht_bin[0]=head; // Replace existing entry } else { ht_bin[1]=ht_bin[0]; ht_bin[0]=head; } return (void*)(((intptr_t)head->clean_addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } int r=new_recompile_block((vaddr&0xFFFFFFF8)+1); if(r==0) return dynamic_linker_ds(src,vaddr); // Execute in unmapped page, generate pagefault execption assert(r4300->cp0.tlb.LUT_r[(vaddr&~1) >> 12] == 0); assert((intptr_t)r4300->new_dynarec_hot_state.memory_map[(vaddr&~1) >> 12] < 0); r4300->delay_slot = vaddr&1; TLB_refill_exception(r4300, vaddr&~1, 2); return get_addr_ht(r4300->new_dynarec_hot_state.pcaddr); } // Get address from virtual address // This is called from the recompiled JR/JALR instructions void *get_addr(u_int vaddr) { struct r4300_core* r4300 = &g_dev.r4300; struct ll_entry *head; struct ll_entry **ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; head=get_clean(r4300,vaddr,~0); if(head!=NULL){ ht_bin[1]=ht_bin[0]; ht_bin[0]=head; return (void*)(((intptr_t)head->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } head=get_dirty(r4300,vaddr,~0); if(head!=NULL){ if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) { ht_bin[0]=head; // Replace existing entry } else { ht_bin[1]=ht_bin[0]; ht_bin[0]=head; } return (void*)(((intptr_t)head->clean_addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } int r=new_recompile_block(vaddr); if(r==0) return get_addr(vaddr); // Execute in unmapped page, generate pagefault execption assert(r4300->cp0.tlb.LUT_r[(vaddr&~1) >> 12] == 0); assert((intptr_t)r4300->new_dynarec_hot_state.memory_map[(vaddr&~1) >> 12] < 0); r4300->delay_slot = vaddr&1; TLB_refill_exception(r4300, vaddr&~1, 2); return get_addr_ht(r4300->new_dynarec_hot_state.pcaddr); } // Look up address in hash table first void *get_addr_ht(u_int vaddr) { struct ll_entry **ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[0]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[1]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); return get_addr(vaddr); } void *get_addr_32(u_int vaddr,u_int flags) { struct ll_entry **ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[0]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) return (void *)(((intptr_t)ht_bin[1]->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); struct r4300_core* r4300 = &g_dev.r4300; struct ll_entry *head; head=get_clean(r4300,vaddr,flags); if(head!=NULL){ if(head->reg32==0) { if(ht_bin[0]==NULL) { ht_bin[0]=head; }else if(ht_bin[1]==NULL) { ht_bin[1]=head; } } return (void*)(((intptr_t)head->addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } head=get_dirty(r4300,vaddr,flags); if(head!=NULL){ if(head->reg32==0) { if(ht_bin[0]==NULL) { ht_bin[0]=head; }else if(ht_bin[1]==NULL) { ht_bin[1]=head; } } return (void*)(((intptr_t)head->clean_addr-(intptr_t)base_addr)+(intptr_t)base_addr_rx); } int r=new_recompile_block(vaddr); if(r==0) return get_addr(vaddr); // Execute in unmapped page, generate pagefault execption assert(r4300->cp0.tlb.LUT_r[(vaddr&~1) >> 12] == 0); assert((intptr_t)r4300->new_dynarec_hot_state.memory_map[(vaddr&~1) >> 12] < 0); r4300->delay_slot = vaddr&1; TLB_refill_exception(r4300, vaddr&~1, 2); return get_addr_ht(r4300->new_dynarec_hot_state.pcaddr); } // Check if an address is already compiled // but don't return addresses which are about to expire from the cache static void *check_addr(u_int vaddr) { struct ll_entry **ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) { if((((uintptr_t)ht_bin[0]->addr-MAX_OUTPUT_BLOCK_SIZE-(uintptr_t)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) if(ht_bin[0]->addr==ht_bin[0]->clean_addr) return ht_bin[0]->addr; //jump_in } if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) { if((((uintptr_t)ht_bin[1]->addr-MAX_OUTPUT_BLOCK_SIZE-(uintptr_t)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) if(ht_bin[1]->addr==ht_bin[1]->clean_addr) return ht_bin[1]->addr; //jump_in } struct r4300_core* r4300 = &g_dev.r4300; struct ll_entry *head; head=get_clean(r4300,vaddr,~0); if(head!=NULL){ if((((uintptr_t)head->addr-(uintptr_t)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { // Update existing entry with current address if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) { ht_bin[0]=head; return head->addr; } if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) { ht_bin[1]=head; return head->addr; } // Insert into hash table with low priority. // Don't evict existing entries, as they are probably // addresses that are being accessed frequently. if(ht_bin[0]==NULL) { ht_bin[0]=head; }else if(ht_bin[1]==NULL) { ht_bin[1]=head; } return head->addr; } } return NULL; } // This is called when we write to a compiled block (see do_invstub) static void invalidate_page(u_int page) { struct ll_entry *head; struct ll_entry *next; head=jump_in[page]; jump_in[page]=0; while(head!=NULL) { inv_debug("INVALIDATE: %x\n",head->vaddr); remove_hash(head->vaddr); next=head->next; free(head); head=next; } head=jump_out[page]; jump_out[page]=0; while(head!=NULL) { inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(intptr_t)head->addr); uintptr_t host_addr=(intptr_t)kill_pointer(head->addr); #if NEW_DYNAREC >= NEW_DYNAREC_ARM needs_clear_cache[(host_addr-(uintptr_t)base_addr)>>17]|=1<<(((host_addr-(uintptr_t)base_addr)>>12)&31); #else /* avoid unused variable warning */ (void)host_addr; #endif next=head->next; free(head); head=next; } } void invalidate_block(u_int block) { u_int page; page=block^0x80000; if(page>262143&&g_dev.r4300.cp0.tlb.LUT_r[block]) page=(g_dev.r4300.cp0.tlb.LUT_r[block]^0x80000000)>>12; if(page>2048) page=2048+(page&2047); inv_debug("INVALIDATE: %x (%d)\n",block<<12,page); u_int first,last; first=last=page; struct ll_entry *head; head=jump_in[page]; u_int start,end; while(head!=NULL) { if((signed int)head->vaddr>=0x80000000&&(signed int)head->vaddr<0x80800000) { assert(page<2048); start=(head->start^0x80000000)>>12; end=((head->start+head->length-1)^0x80000000)>>12; assert(start<2048&&end<2048); } if((signed int)head->vaddr>=(signed int)0xC0000000) { assert(page<2048); assert(g_dev.r4300.new_dynarec_hot_state.memory_map[head->vaddr>>12]!=(uintptr_t)-1); u_int paddr=head->vaddr+(g_dev.r4300.new_dynarec_hot_state.memory_map[head->vaddr>>12]<<2)-(uintptr_t)g_dev.rdram.dram; start=(paddr-(head->vaddr-head->start))>>12; end=(paddr+((head->start+head->length)-head->vaddr)-1)>>12; assert(start<2048&&end<2048); } else if((signed int)head->vaddr>=(signed int)0x80800000) { assert(page>=2048); start=(head->start^0x80000000)>>12; end=((head->start+head->length-1)^0x80000000)>>12; assert(start>=2048&&end>=2048); start=2048+(start&2047); end=2048+(end&2047); } if((start<=page)&&(end>=page)) { if(startlast) last=end; } head=head->next; } invalidate_page(page); assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages) assert(last= NEW_DYNAREC_ARM do_clear_cache(); #endif // Don't trap writes g_dev.r4300.cached_interp.invalid_code[block]=1; // If there is a valid TLB entry for this page, remove write protect if(g_dev.r4300.cp0.tlb.LUT_w[block]) { assert(g_dev.r4300.cp0.tlb.LUT_r[block]==g_dev.r4300.cp0.tlb.LUT_w[block]); g_dev.r4300.new_dynarec_hot_state.memory_map[block]=((uintptr_t)g_dev.rdram.dram+(uintptr_t)((g_dev.r4300.cp0.tlb.LUT_w[block]&0xFFFFF000)-0x80000000)-(block<<12))>>2; u_int real_block=g_dev.r4300.cp0.tlb.LUT_w[block]>>12; g_dev.r4300.cached_interp.invalid_code[real_block]=1; if(real_block>=0x80000&&real_block<0x80800) g_dev.r4300.new_dynarec_hot_state.memory_map[real_block]=((uintptr_t)g_dev.rdram.dram-(uintptr_t)0x80000000)>>2; } else if(block>=0x80000&&block<0x80800) g_dev.r4300.new_dynarec_hot_state.memory_map[block]=((uintptr_t)g_dev.rdram.dram-(uintptr_t)0x80000000)>>2; #ifdef USE_MINI_HT memset(g_dev.r4300.new_dynarec_hot_state.mini_ht,-1,sizeof(g_dev.r4300.new_dynarec_hot_state.mini_ht)); #endif } // This is called when loading a save state. // Anything could have changed, so invalidate everything. static void invalidate_all_pages(void) { u_int page; for(page=0;page<4096;page++) invalidate_page(page); for(page=0;page<1048576;page++) { if(!g_dev.r4300.cached_interp.invalid_code[page]) { restore_candidate[(page&2047)>>3]|=1<<(page&7); restore_candidate[((page&2047)>>3)+256]|=1<<(page&7); } } #if NEW_DYNAREC >= NEW_DYNAREC_ARM cache_flush((char *)base_addr_rx,(char *)base_addr_rx+(1<>2; if(!g_dev.r4300.cp0.tlb.LUT_w[page]||!g_dev.r4300.cached_interp.invalid_code[page]) g_dev.r4300.new_dynarec_hot_state.memory_map[page]|=WRITE_PROTECT; // Write protect } else g_dev.r4300.new_dynarec_hot_state.memory_map[page]=(uintptr_t)-1; if(page==0x80000) page=0xC0000; } tlb_speed_hacks(); } void invalidate_cached_code_new_dynarec(struct r4300_core* r4300, uint32_t address, size_t size) { size_t i; size_t begin; size_t end; if (size == 0) { invalidate_all_pages(); } else { begin = address >> 12; end = (address+size-1) >> 12; for(i = begin; i <= end; ++i) { if(r4300->cached_interp.invalid_code[i] == 0) { invalidate_block(i); } } } } // If a code block was found to be unmodified (bit was set in // restore_candidate) and it remains unmodified (bit is clear // in invalid_code) then move the entries for that 4K page from // the dirty list to the clean list. void clean_blocks(u_int page) { struct ll_entry *head; inv_debug("INV: clean_blocks page=%d\n",page); head=jump_dirty[page]; while(head!=NULL) { if(!g_dev.r4300.cached_interp.invalid_code[head->vaddr>>12]) { // Don't restore blocks which are about to expire from the cache if((((uintptr_t)head->addr-(uintptr_t)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { if(verify_dirty(head)==0) { //DebugMessage(M64MSG_VERBOSE, "Possibly Restore %x (%x)",head->vaddr, (intptr_t)head->addr); u_int i,j; u_int inv=0; u_int start,end; if((signed int)head->vaddr>=0x80000000&&(signed int)head->vaddr<0x80800000) { start=head->start>>12; end=(head->start+head->length-1)>>12; for(i=start;i<=end;i++) { inv|=g_dev.r4300.cached_interp.invalid_code[i]; } } else if((signed int)head->vaddr>=(signed int)0xC0000000) { uintptr_t map_value=g_dev.r4300.new_dynarec_hot_state.memory_map[head->vaddr>>12]; start=head->start>>12; end=(head->start+head->length-1)>>12; for(i=start;i<=end;i++) { inv|=g_dev.r4300.cached_interp.invalid_code[i]; assert((g_dev.r4300.new_dynarec_hot_state.memory_map[i]<<2)==(map_value<<2)); //mapping was already checked in verify_dirty j=(((uintptr_t)i<<12)+(uintptr_t)(g_dev.r4300.new_dynarec_hot_state.memory_map[i]<<2)-(uintptr_t)g_dev.rdram.dram+(uintptr_t)0x80000000)>>12; inv|=g_dev.r4300.cached_interp.invalid_code[j]; } } else if((signed int)head->vaddr>=(signed int)0x80800000) { //TODO: allow restoring? inv=1; } if(!inv) { if((((uintptr_t)head->clean_addr-(uintptr_t)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { u_int ppage=page; if(page<2048&&g_dev.r4300.cp0.tlb.LUT_r[head->vaddr>>12]) ppage=(g_dev.r4300.cp0.tlb.LUT_r[head->vaddr>>12]^0x80000000)>>12; inv_debug("INV: Restored %x (%x/%x)\n",head->vaddr, (intptr_t)head->addr, (intptr_t)head->clean_addr); //DebugMessage(M64MSG_VERBOSE, "page=%x, addr=%x",page,head->vaddr); //assert(head->vaddr>>12==(page|0x80000)); struct ll_entry *clean_head=ll_add_32(jump_in+ppage,head->vaddr,head->reg32,head->clean_addr,head->clean_addr,head->start,head->copy,head->length); struct ll_entry **ht_bin=hash_table[((head->vaddr>>16)^head->vaddr)&0xFFFF]; if(!head->reg32) { if(ht_bin[0]&&ht_bin[0]->vaddr==head->vaddr) { ht_bin[0]=clean_head; // Replace existing entry } if(ht_bin[1]&&ht_bin[1]->vaddr==head->vaddr) { ht_bin[1]=clean_head; // Replace existing entry } } } } } } } head=head->next; } } void* cop1_unusable(void) { struct r4300_core* r4300 = &g_dev.r4300; struct new_dynarec_hot_state* state = &r4300->new_dynarec_hot_state; r4300->delay_slot = state->pcaddr & 1; state->pcaddr &= ~1; state->cp0_regs[CP0_CAUSE_REG] = CP0_CAUSE_EXCCODE_CPU | CP0_CAUSE_CE1; exception_general(r4300); return get_addr_ht(state->pcaddr); } void dynarec_gen_interrupt(void) { struct r4300_core* r4300 = &g_dev.r4300; struct new_dynarec_hot_state* state = &r4300->new_dynarec_hot_state; cp0_update_count(r4300); uint32_t page = ((state->cp0_regs[CP0_COUNT_REG]>>19)&0x1fc); unsigned int *candidate = (unsigned int *)&restore_candidate[page]; page <<= 3; r4300->delay_slot = 0; if(*candidate) { for(int i=0;i<32;i++) { if((*candidate>>i)&1) clean_blocks(page+i); } *candidate = 0; } gen_interrupt(r4300); } /**** Register allocation ****/ static void mov_alloc(struct regstat *current,int i) { // Note: Don't need to actually alloc the source registers if((~current->is32>>rs1[i])&1) { //alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rt1[i]); current->is32&=~(1LL<is32|=(1LL<is32|=1LL<=0x38&&opcode2[i]<=0x3b) // DSLL/DSRL/DSRA { if(rt1[i]) { if(rs1[i]) alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rt1[i]); current->is32&=~(1LL<is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32|=1LL<is32|=1LL<is32&=~(1LL<=0x20&&opcode2[i]<=0x23) { // ADD/ADDU/SUB/SUBU if(rt1[i]) { if(rs1[i]&&rs2[i]) { alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); } else { if(rs1[i]&&needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); if(rs2[i]&&needed_again(rs2[i],i)) alloc_reg(current,i,rs2[i]); } alloc_reg(current,i,rt1[i]); } current->is32|=1LL<is32>>rs1[i])&(current->is32>>rs2[i])&1)) { alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rs2[i]); alloc_reg(current,i,rt1[i]); } else { alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); alloc_reg(current,i,rt1[i]); } } current->is32|=1LL<=0x24&&opcode2[i]<=0x27) { // AND/OR/XOR/NOR if(rt1[i]) { if(rs1[i]&&rs2[i]) { alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); } else { if(rs1[i]&&needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); if(rs2[i]&&needed_again(rs2[i],i)) alloc_reg(current,i,rs2[i]); } alloc_reg(current,i,rt1[i]); if(!((current->is32>>rs1[i])&(current->is32>>rs2[i])&1)) { if(!((current->uu>>rt1[i])&1)) { alloc_reg64(current,i,rt1[i]); } if(get_reg(current->regmap,rt1[i]|64)>=0) { if(rs1[i]&&rs2[i]) { alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rs2[i]); } else { // Is is really worth it to keep 64-bit values in registers? #ifdef NATIVE_64BIT if(rs1[i]&&needed_again(rs1[i],i)) alloc_reg64(current,i,rs1[i]); if(rs2[i]&&needed_again(rs2[i],i)) alloc_reg64(current,i,rs2[i]); #endif } } current->is32&=~(1LL<is32|=1LL<=0x2c&&opcode2[i]<=0x2f) { // DADD/DADDU/DSUB/DSUBU if(rt1[i]) { if(rs1[i]&&rs2[i]) { if(!((current->uu>>rt1[i])&1)||get_reg(current->regmap,rt1[i]|64)>=0) { alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rs2[i]); alloc_reg64(current,i,rt1[i]); } else { alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); alloc_reg(current,i,rt1[i]); } } else { alloc_reg(current,i,rt1[i]); if(!((current->uu>>rt1[i])&1)||get_reg(current->regmap,rt1[i]|64)>=0) { // DADD used as move, or zeroing // If we have a 64-bit source, then make the target 64 bits too if(rs1[i]&&!((current->is32>>rs1[i])&1)) { if(get_reg(current->regmap,rs1[i])>=0) alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rt1[i]); } else if(rs2[i]&&!((current->is32>>rs2[i])&1)) { if(get_reg(current->regmap,rs2[i])>=0) alloc_reg64(current,i,rs2[i]); alloc_reg64(current,i,rt1[i]); } if(opcode2[i]>=0x2e&&rs2[i]) { // DSUB used as negation - 64-bit result // If we have a 32-bit register, extend it to 64 bits if(get_reg(current->regmap,rs2[i])>=0) alloc_reg64(current,i,rs2[i]); alloc_reg64(current,i,rt1[i]); } } } if(rs1[i]&&rs2[i]) { current->is32&=~(1LL<is32&=~(1LL<is32>>rs1[i])&1) current->is32|=1LL<is32&=~(1LL<is32>>rs2[i])&1) current->is32|=1LL<is32|=1LL<is32&=~(1LL<uu>>rt1[i])&1)||get_reg(current->regmap,rt1[i]|64)>=0) { // TODO: Could preserve the 32-bit flag if the immediate is zero alloc_reg64(current,i,rt1[i]); alloc_reg64(current,i,rs1[i]); } clear_const(current,rs1[i]); clear_const(current,rt1[i]); } else if(opcode[i]==0x0a||opcode[i]==0x0b) { // SLTI/SLTIU if((~current->is32>>rs1[i])&1) alloc_reg64(current,i,rs1[i]); current->is32|=1LL<=0x0c&&opcode[i]<=0x0e) { // ANDI/ORI/XORI if(((~current->is32>>rs1[i])&1)&&opcode[i]>0x0c) { if(rs1[i]!=rt1[i]) { if(needed_again(rs1[i],i)) alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rt1[i]); current->is32&=~(1LL<is32|=1LL<is32|=1LL<is32|=1LL<u&=~1LL; // Allow allocating r0 if it's the source register if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); if(rt1[i]&&!((current->u>>rt1[i])&1)) { alloc_reg(current,i,rt1[i]); assert(get_reg(current->regmap,rt1[i])>=0); if(opcode[i]==0x27||opcode[i]==0x37||opcode[i]==0x1A||opcode[i]==0x1B) // LWU/LD/LDL/LDR { current->is32&=~(1LL<uu&=~(1LL<is32|=1LL<u&=~1LL; // Allow allocating r0 if necessary if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); if(opcode[i]==0x2c||opcode[i]==0x2d||opcode[i]==0x3f) { // 64-bit SDL/SDR/SD alloc_reg64(current,i,rs2[i]); if(rs2[i]) alloc_reg(current,i,FTEMP); } // If using TLB, need a register for pointer to the mapping table if(using_tlb) alloc_reg(current,i,TLREG); #if defined(HOST_IMM8) || defined(NEED_INVC_PTR) // On CPUs without 32-bit immediates we need a pointer to invalid_code else alloc_reg(current,i,INVCP); #endif if(opcode[i]==0x2c||opcode[i]==0x2d) { // 64-bit SDL/SDR alloc_reg(current,i,FTEMP); } // We need a temporary register for address generation alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } static void c1ls_alloc(struct regstat *current,int i) { //clear_const(current,rs1[i]); // FIXME clear_const(current,rt1[i]); if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); alloc_reg(current,i,CSREG); // Status alloc_reg(current,i,FTEMP); if(opcode[i]==0x35||opcode[i]==0x3d) { // 64-bit LDC1/SDC1 alloc_reg64(current,i,FTEMP); } // If using TLB, need a register for pointer to the mapping table if(using_tlb) alloc_reg(current,i,TLREG); #if defined(HOST_IMM8) || defined(NEED_INVC_PTR) // On CPUs without 32-bit immediates we need a pointer to invalid_code else if((opcode[i]&0x3b)==0x39) // SWC1/SDC1 alloc_reg(current,i,INVCP); #endif // We need a temporary register for address generation alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } #ifndef multdiv_alloc void multdiv_alloc(struct regstat *current,int i) { // case 0x18: MULT // case 0x19: MULTU // case 0x1A: DIV // case 0x1B: DIVU // case 0x1C: DMULT // case 0x1D: DMULTU // case 0x1E: DDIV // case 0x1F: DDIVU clear_const(current,rs1[i]); clear_const(current,rs2[i]); if(rs1[i]&&rs2[i]) { if((opcode2[i]&4)==0) // 32-bit { #ifndef INTERPRET_MULT if((opcode2[i]==0x18) || (opcode2[i]==0x19)) { //MULT/MULTU current->u&=~(1LL<u&=~(1LL<u&=~(1LL<u&=~(1LL<is32|=1LL<is32|=1LL<u&=~(1LL<uu&=~(1LL<u&=~(1LL<uu&=~(1LL<u&=~(1LL<uu&=~(1LL<u&=~(1LL<uu&=~(1LL<is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32|=1LL<is32|=1LL<u&=~1LL; alloc_reg(current,i,0); } } else { // TLBR/TLBWI/TLBWR/TLBP/ERET assert(opcode2[i]==0x10); if((source[i]&0x3f)==0x18) // ERET { alloc_all(current,i); minimum_free_regs[i]=HOST_REGS; } } } static void cop1_alloc(struct regstat *current,int i) { alloc_reg(current,i,CSREG); // Load status if(opcode2[i]<3) // MFC1/DMFC1/CFC1 { assert(rt1[i]); clear_const(current,rt1[i]); if(opcode2[i]==1) { alloc_reg64(current,i,rt1[i]); // DMFC1 current->is32&=~(1LL<is32|=1LL<3) // MTC1/DMTC1/CTC1 { if(rs1[i]){ clear_const(current,rs1[i]); if(opcode2[i]==5) alloc_reg64(current,i,rs1[i]); // DMTC1 else alloc_reg(current,i,rs1[i]); // MTC1/CTC1 alloc_reg_temp(current,i,-1); } else { current->u&=~1LL; alloc_reg(current,i,0); alloc_reg_temp(current,i,-1); } } minimum_free_regs[i]=1; } static void fconv_alloc(struct regstat *current,int i) { alloc_reg(current,i,CSREG); // Load status alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } static void float_alloc(struct regstat *current,int i) { alloc_reg(current,i,CSREG); // Load status alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } static void fcomp_alloc(struct regstat *current,int i) { alloc_reg(current,i,CSREG); // Load status alloc_reg(current,i,FSREG); // Load flags dirty_reg(current,FSREG); // Flag will be modified alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } static void syscall_alloc(struct regstat *current,int i) { alloc_cc(current,i); dirty_reg(current,CCREG); alloc_all(current,i); minimum_free_regs[i]=HOST_REGS; current->isconst=0; } static void delayslot_alloc(struct regstat *current,int i) { switch(itype[i]) { case UJUMP: case CJUMP: case SJUMP: case RJUMP: case FJUMP: case SYSCALL: case SPAN: assem_debug("jump in the delay slot. this shouldn't happen.");//exit(1); DebugMessage(M64MSG_VERBOSE, "Disabled speculative precompilation"); stop_after_jal=1; ccadj[i-1]+=1; break; case IMM16: imm16_alloc(current,i); break; case LOAD: case LOADLR: load_alloc(current,i); break; case STORE: case STORELR: store_alloc(current,i); break; case ALU: alu_alloc(current,i); break; case SHIFT: shift_alloc(current,i); break; case MULTDIV: multdiv_alloc(current,i); break; case SHIFTIMM: shiftimm_alloc(current,i); break; case MOV: mov_alloc(current,i); break; case COP0: cop0_alloc(current,i); break; case COP1: cop1_alloc(current,i); break; case C1LS: c1ls_alloc(current,i); break; case FCONV: fconv_alloc(current,i); break; case FLOAT: float_alloc(current,i); break; case FCOMP: fcomp_alloc(current,i); break; } } // Special case where a branch and delay slot span two pages in virtual memory static void pagespan_alloc(struct regstat *current,int i) { current->isconst=0; current->wasconst=0; regs[i].wasconst=0; minimum_free_regs[i]=HOST_REGS; alloc_all(current,i); alloc_cc(current,i); dirty_reg(current,CCREG); if(opcode[i]==3) // JAL { alloc_reg(current,i,31); dirty_reg(current,31); } if(opcode[i]==0&&(opcode2[i]&0x3E)==8) // JR/JALR { alloc_reg(current,i,rs1[i]); if (rt1[i]!=0) { alloc_reg(current,i,rt1[i]); dirty_reg(current,rt1[i]); } } if((opcode[i]&0x2E)==4) // BEQ/BNE/BEQL/BNEL { if(rs1[i]) alloc_reg(current,i,rs1[i]); if(rs2[i]) alloc_reg(current,i,rs2[i]); if(!((current->is32>>rs1[i])&(current->is32>>rs2[i])&1)) { if(rs1[i]) alloc_reg64(current,i,rs1[i]); if(rs2[i]) alloc_reg64(current,i,rs2[i]); } } else if((opcode[i]&0x2E)==6) // BLEZ/BGTZ/BLEZL/BGTZL { if(rs1[i]) alloc_reg(current,i,rs1[i]); if(!((current->is32>>rs1[i])&1)) { if(rs1[i]) alloc_reg64(current,i,rs1[i]); } } else if(opcode[i]==0x11) // BC1 { alloc_reg(current,i,FSREG); alloc_reg(current,i,CSREG); } //else ... } /**** Assembler utils ****/ static void wb_invalidate(signed char pre[],signed char entry[],uint64_t dirty,uint64_t is32,uint64_t u,uint64_t uu) { int hr; for(hr=0;hr=0) { if((dirty>>hr)&1) { if(get_reg(entry,pre[hr])<0) { if(pre[hr]<64) { if(!((u>>pre[hr])&1)) { emit_storereg(pre[hr],hr); if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) { emit_sarimm(hr,31,hr); emit_storereg(pre[hr]|64,hr); } } }else{ if(!((uu>>(pre[hr]&63))&1) && !((is32>>(pre[hr]&63))&1)) { emit_storereg(pre[hr],hr); } } } } } } } } // Move from one register to another (no writeback) for(hr=0;hr=0&&(pre[hr]&63)=0) { #ifdef NATIVE_64 if(pre[hr]>=INVCP) emit_mov64(hr,nr); else #endif emit_mov(hr,nr); } } } } } } // Write out all dirty registers (except cycle count) static void wb_dirtys(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty) { int hr; for(hr=0;hr0)&&((i_regmap[hr]&63)>hr)&1) { if(i_regmap[hr]<64) { emit_storereg(i_regmap[hr],hr); if(((i_is32>>i_regmap[hr])&1)) { #ifdef DESTRUCTIVE_WRITEBACK emit_sarimm(hr,31,hr); emit_storereg(i_regmap[hr]|64,hr); #else emit_sarimm(hr,31,HOST_TEMPREG); emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); #endif } }else{ if(!((i_is32>>(i_regmap[hr]&63))&1)) { emit_storereg(i_regmap[hr],hr); } } } } } } } // Write out dirty registers that we need to reload (pair with load_needed_regs) // This writes the registers not written by store_regs_bt static void wb_needed_dirtys(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) { int hr; int t=(addr-start)>>2; for(hr=0;hr0)&&((i_regmap[hr]&63)>hr)&1) && !(((i_is32&~regs[t].was32&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1)) { if((i_dirty>>hr)&1) { if(i_regmap[hr]<64) { emit_storereg(i_regmap[hr],hr); if(((i_is32>>i_regmap[hr])&1)) { #ifdef DESTRUCTIVE_WRITEBACK emit_sarimm(hr,31,hr); emit_storereg(i_regmap[hr]|64,hr); #else emit_sarimm(hr,31,HOST_TEMPREG); emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); #endif } }else{ if(!((i_is32>>(i_regmap[hr]&63))&1)) { emit_storereg(i_regmap[hr],hr); } } } } } } } } #ifndef DESTRUCTIVE_WRITEBACK // Sign-extend to 64 bits and write out upper half of a register // This is useful where we have a 32-bit value in a register, and want to // keep it in a 32-bit register, but can't guarantee that it won't be read // as a 64-bit value later. static void wb_sx(signed char pre[],signed char entry[],uint64_t dirty,uint64_t is32_pre,uint64_t is32,uint64_t u,uint64_t uu) { if(is32_pre==is32) return; int hr,reg; for(hr=0;hr=0) { if((dirty>>hr)&1) { if( ((is32_pre&~is32&~uu)>>reg)&1 ) { emit_sarimm(hr,31,HOST_TEMPREG); emit_storereg(reg|64,HOST_TEMPREG); } } } //} } } } static void wb_valid(signed char pre[],signed char entry[],u_int dirty_pre,u_int dirty,uint64_t is32_pre,uint64_t u,uint64_t uu) { //if(dirty_pre==dirty) return; int hr,reg; for(hr=0;hr>(reg&63))&1) { if(((reg&63)>0)&&((reg&63)>hr)&1) { if(reg<64) { emit_storereg(reg,hr); if( ((is32_pre&~uu)>>reg)&1 ) { emit_sarimm(hr,31,HOST_TEMPREG); emit_storereg(reg|64,HOST_TEMPREG); } } else { emit_storereg(reg,hr); } } } } } } } #endif // Write out a single register static void wb_register(signed char r,signed char regmap[],uint64_t dirty,uint64_t is32) { int hr; for(hr=0;hr>hr)&1) { if(regmap[hr]<64) { emit_storereg(r,hr); if((is32>>regmap[hr])&1) { emit_sarimm(hr,31,hr); emit_storereg(r|64,hr); } }else{ emit_storereg(r|64,hr); } } } } } } // Store dirty registers prior to branch static void store_regs_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) { if(internal_branch(i_is32,addr)) { int t=(addr-start)>>2; int hr; for(hr=0;hr0)&&((i_regmap[hr]&63)>hr)&1) || (((i_is32&~regs[t].was32&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1)) { if((i_dirty>>hr)&1) { if(i_regmap[hr]<64) { if(!((unneeded_reg[t]>>i_regmap[hr])&1)) { emit_storereg(i_regmap[hr],hr); if(((i_is32>>i_regmap[hr])&1) && !((unneeded_reg_upper[t]>>i_regmap[hr])&1)) { #ifdef DESTRUCTIVE_WRITEBACK emit_sarimm(hr,31,hr); emit_storereg(i_regmap[hr]|64,hr); #else emit_sarimm(hr,31,HOST_TEMPREG); emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); #endif } } }else{ if(!((i_is32>>(i_regmap[hr]&63))&1) && !((unneeded_reg_upper[t]>>(i_regmap[hr]&63))&1)) { emit_storereg(i_regmap[hr],hr); } } } } } } } } else { // Branch out of this block, write out all dirty regs wb_dirtys(i_regmap,i_is32,i_dirty); } } // Load all needed registers for branch target static void load_regs_bt(signed char i_regmap[],uint64_t i_is32,uint64_t i_dirty,int addr) { //if(addr>=start && addr<(start+slen*4)) if(internal_branch(i_is32,addr)) { int t=(addr-start)>>2; int hr; // Store the cycle count before loading something else if(i_regmap[HOST_CCREG]!=CCREG) { assert(i_regmap[HOST_CCREG]==-1); } if(regs[t].regmap_entry[HOST_CCREG]!=CCREG) { emit_storereg(CCREG,HOST_CCREG); } // Load 32-bit regs for(hr=0;hr=0&®s[t].regmap_entry[hr]>hr)&1) && ((i_dirty>>hr)&1) && (((i_is32&~unneeded_reg_upper[t])>>i_regmap[hr])&1) ) || (((i_is32&~regs[t].was32&~unneeded_reg_upper[t])>>(i_regmap[hr]&63))&1)) { #else if(i_regmap[hr]!=regs[t].regmap_entry[hr] ) { #endif if(regs[t].regmap_entry[hr]==0) { emit_zeroreg(hr); } else if(regs[t].regmap_entry[hr]!=CCREG) { emit_loadreg(regs[t].regmap_entry[hr],hr); } } } } //Load 64-bit regs for(hr=0;hr=64&®s[t].regmap_entry[hr]>(regs[t].regmap_entry[hr]&63))&1) { int lr=get_reg(regs[t].regmap_entry,regs[t].regmap_entry[hr]-64); if(lr<0) { emit_loadreg(regs[t].regmap_entry[hr],hr); } else { emit_sarimm(lr,31,hr); } } else { emit_loadreg(regs[t].regmap_entry[hr],hr); } } else if((i_is32>>(regs[t].regmap_entry[hr]&63))&1) { int lr=get_reg(regs[t].regmap_entry,regs[t].regmap_entry[hr]-64); if(lr<0) { emit_loadreg(regs[t].regmap_entry[hr],hr); } else { emit_sarimm(lr,31,hr); } } } } } } // Load the specified registers // This only loads the registers given as arguments because // we don't want to load things that will be overwritten static void load_regs(signed char entry[],signed char regmap[],int is32,int rs1,int rs2) { int hr; // Load 32-bit regs for(hr=0;hr=0) { if(entry[hr]!=regmap[hr]) { if(regmap[hr]==rs1||regmap[hr]==rs2) { if(regmap[hr]==0) { emit_zeroreg(hr); } else { emit_loadreg(regmap[hr],hr); } } } } } //Load 64-bit regs for(hr=0;hr=0) { if(entry[hr]!=regmap[hr]) { if(regmap[hr]-64==rs1||regmap[hr]-64==rs2) { assert(regmap[hr]!=64); if((is32>>(regmap[hr]&63))&1) { int lr=get_reg(regmap,regmap[hr]-64); if(lr>=0) emit_sarimm(lr,31,hr); else emit_loadreg(regmap[hr],hr); } else { emit_loadreg(regmap[hr],hr); } } } } } } // Load registers with known constants static void load_consts(signed char pre[],signed char regmap[],int is32,int i) { int hr; // Load 32-bit regs for(hr=0;hr=0) { //if(entry[hr]!=regmap[hr]) { if(i==0||!((regs[i-1].isconst>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) { if(((regs[i].isconst>>hr)&1)&®map[hr]<64&®map[hr]>0) { int value; if(get_final_value(hr,i,&value)) { if(value==0) { emit_zeroreg(hr); } else { emit_movimm(value,hr); } } } } } } // Load 64-bit regs for(hr=0;hr=0) { //if(entry[hr]!=regmap[hr]) { if(i==0||!((regs[i-1].isconst>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) { if(((regs[i].isconst>>hr)&1)&®map[hr]>64) { if((is32>>(regmap[hr]&63))&1) { int lr=get_reg(regmap,regmap[hr]-64); assert(lr>=0); emit_sarimm(lr,31,hr); } else { int value; if(get_final_value(hr,i,&value)) { if(value==0) { emit_zeroreg(hr); } else { emit_movimm(value,hr); } } } } } } } } static void load_all_consts(signed char regmap[],int is32,u_int dirty,u_int isconst,int i) { int hr; // Load 32-bit regs for(hr=0;hr=0&&((dirty>>hr)&1)) { if(((isconst>>hr)&1)&®map[hr]<64&®map[hr]>0) { int value=constmap[i][hr]; if(value==0) { emit_zeroreg(hr); } else { emit_movimm(value,hr); } } } } // Load 64-bit regs for(hr=0;hr=0&&((dirty>>hr)&1)) { if(((isconst>>hr)&1)&®map[hr]>64) { if((is32>>(regmap[hr]&63))&1) { int lr=get_reg(regmap,regmap[hr]-64); assert(lr>=0); emit_sarimm(lr,31,hr); } else { int value=constmap[i][hr]; if(value==0) { emit_zeroreg(hr); } else { emit_movimm(value,hr); } } } } } } // Load all registers (except cycle count) static void load_all_regs(signed char i_regmap[]) { int hr; for(hr=0;hr0 && (i_regmap[hr]&63)=0) { if(i_regmap[hr]==0) { emit_zeroreg(hr); } else if(i_regmap[hr]>0 && (i_regmap[hr]&63)=0&®s[t].regmap_entry[hr]=64&®s[t].regmap_entry[hr]>(regs[t].regmap_entry[hr]&63))&1) { int lr=get_reg(regs[t].regmap_entry,regs[t].regmap_entry[hr]-64); if(lr<0) { emit_loadreg(regs[t].regmap_entry[hr],hr); } else { emit_sarimm(lr,31,hr); } } else { emit_loadreg(regs[t].regmap_entry[hr],hr); } } } } // Load registers prior to the start of a loop // so that they are not loaded within the loop static void loop_preload(signed char pre[],signed char entry[]) { int hr; for(hr=0;hr=0) { if(get_reg(pre,entry[hr])<0) { assem_debug("loop preload:"); //DebugMessage(M64MSG_VERBOSE, "loop preload: %d",hr); if(entry[hr]==0) { emit_zeroreg(hr); } else if(entry[hr]regmap,agr); if(ra<0) ra=get_reg(i_regs->regmap,-1); assert(ra>=0); } if(itype[i]==LOADLR) { ra=get_reg(i_regs->regmap,FTEMP); } if(itype[i]==STORE||itype[i]==STORELR) { ra=get_reg(i_regs->regmap,agr); if(ra<0) ra=get_reg(i_regs->regmap,-1); } if(itype[i]==C1LS) { if (opcode[i]==0x31||opcode[i]==0x35) // LWC1/LDC1 ra=get_reg(i_regs->regmap,FTEMP); else { // SWC1/SDC1 ra=get_reg(i_regs->regmap,agr); if(ra<0) ra=get_reg(i_regs->regmap,-1); } } int rs=get_reg(i_regs->regmap,rs1[i]); int rm=get_reg(i_regs->regmap,TLREG); if(ra>=0) { int offset=imm[i]; int c=(i_regs->wasconst>>rs)&1; if(rs1[i]==0) { // Using r0 as a base address /*if(rm>=0) { if(!entry||entry[rm]!=mgr) { generate_map_const(offset,rm); } // else did it in the previous cycle }*/ if(!entry||entry[ra]!=agr) { emit_movimm(offset,ra); } // else did it in the previous cycle } else if(rs<0) { if(!entry||entry[ra]!=rs1[i]) emit_loadreg(rs1[i],ra); //if(!entry||entry[ra]!=rs1[i]) // DebugMessage(M64MSG_VERBOSE, "poor load scheduling!"); } else if(c) { if(rm>=0) { if(!entry||entry[rm]!=mgr) { if(itype[i]==STORE||itype[i]==STORELR||opcode[i]==0x39||opcode[i]==0x3D) { // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if((unsigned int)(constmap[i][rs]+offset)>=0xC0000000 || (unsigned int)(constmap[i][rs]+offset)<0x80800000 ) generate_map_const(constmap[i][rs]+offset,rm); }else{ if((signed int)(constmap[i][rs]+offset)>=(signed int)0xC0000000) generate_map_const(constmap[i][rs]+offset,rm); } } } if(!entry||entry[ra]!=agr) { int load=0; #ifndef INTERPRET_LOAD load|=(itype[i]==LOAD); #endif #ifndef INTERPRET_C1LS load|=(opcode[i]==0x31||opcode[i]==0x35); #endif #ifndef INTERPRET_LOADLR load|=(opcode[i]==0x22||opcode[i]==0x26||opcode[i]==0x1a||opcode[i]==0x1b); #endif #ifdef HOST_IMM_ADDR32 // on x86 when source reg is constant // LB/LBU/LH/LHU/LW/LWU/LD/LWC1/LDC1 doesn't need address generation when not using tlb // SDL/SDR/SB/SH/SW/SD/SWC1/SDC1 always need address generation // ROREG not required if(!load||(using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000)) #endif #if defined(RAM_OFFSET) && !defined(NATIVE_64) // on arm address generation is always required // When LB/LBU/LH/LHU/LW/LWU/LD/LWC1/LDC1 loading from rdram, add rdram address to load address to avoid loading ROREG // ROREG only required for SDL/SDR/SB/SH/SW/SD/SWC1/SDC1 and when not loading from rdram if(load&&(signed int)constmap[i][rs]+offset<(signed int)0x80800000) emit_movimm(constmap[i][rs]+offset+(intptr_t)g_dev.rdram.dram-(intptr_t)0x80000000,ra); else #endif // on arm64 and x64 when source reg is constant // address generation is always required // ROREG is always required emit_movimm(constmap[i][rs]+offset,ra); } // else did it in the previous cycle } if(offset&&!c&&rs1[i]) { if(rs>=0) { emit_addimm(rs,offset,ra); }else{ emit_addimm(ra,offset,ra); } } } } // Preload constants for next instruction if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) { int agr,ra; #if (NEW_DYNAREC!=NEW_DYNAREC_X86) && (NEW_DYNAREC!=NEW_DYNAREC_X64) // Mapper entry agr=MGEN1+((i+1)&1); ra=get_reg(i_regs->regmap,agr); if(ra>=0) { int rs=get_reg(regs[i+1].regmap,rs1[i+1]); int offset=imm[i+1]; int c=(regs[i+1].wasconst>>rs)&1; if(c) { if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if((unsigned int)(constmap[i+1][rs]+offset)>=0xC0000000 || (unsigned int)(constmap[i+1][rs]+offset)<0x80800000 ) generate_map_const(constmap[i+1][rs]+offset,ra); }else{ if((signed int)(constmap[i+1][rs]+offset)>=(signed int)0xC0000000) generate_map_const(constmap[i+1][rs]+offset,ra); } } /*else if(rs1[i]==0) { generate_map_const(offset,ra); }*/ } #endif // Actual address agr=AGEN1+((i+1)&1); ra=get_reg(i_regs->regmap,agr); if(ra>=0) { int rs=get_reg(regs[i+1].regmap,rs1[i+1]); int offset=imm[i+1]; int c=(regs[i+1].wasconst>>rs)&1; if(c) { int load=0; #ifndef INTERPRET_LOAD load|=(itype[i+1]==LOAD); #endif #ifndef INTERPRET_C1LS load|=(opcode[i+1]==0x31||opcode[i+1]==0x35); #endif #ifndef INTERPRET_LOADLR load|=(opcode[i+1]==0x22||opcode[i+1]==0x26||opcode[i+1]==0x1a||opcode[i+1]==0x1b); #endif #ifdef HOST_IMM_ADDR32 if(!load||(using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000)) #endif #if defined(RAM_OFFSET) && !defined(NATIVE_64) if(load&&(signed int)constmap[i+1][rs]+offset<(signed int)0x80800000) emit_movimm(constmap[i+1][rs]+offset+(intptr_t)g_dev.rdram.dram-(intptr_t)0x80000000,ra); else #endif emit_movimm(constmap[i+1][rs]+offset,ra); } else if(rs1[i+1]==0) { // Using r0 as a base address emit_movimm(offset,ra); } } } } static void emit_extjump(intptr_t addr, int target) { emit_extjump2(addr, target, (intptr_t)dyna_linker); } static void emit_extjump_ds(intptr_t addr, int target) { emit_extjump2(addr, target, (intptr_t)dyna_linker_ds); } static void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert) { int count; intptr_t jaddr; intptr_t idle=0; if(itype[i]==RJUMP) { *adj=0; } //if(ba[i]>=start && ba[i]<(start+slen*4)) if(internal_branch(branch_regs[i].is32,ba[i])) { int t=(ba[i]-start)>>2; if(is_ds[t]) *adj=-1; // Branch into delay slot adds an extra cycle else *adj=ccadj[t]; } else { *adj=0; } count=ccadj[i]; if(taken==TAKEN && i==(ba[i]-start)>>2 && source[i+1]==0) { // Idle loop idle=(intptr_t)out; emit_test(HOST_CCREG,HOST_CCREG); #if NEW_DYNAREC >= NEW_DYNAREC_ARM emit_cmovs_imm(0,HOST_CCREG); #else emit_cmovs(&const_zero,HOST_CCREG); #endif emit_addimm(HOST_CCREG,CLOCK_DIVIDER*2,HOST_CCREG); jaddr=(intptr_t)out; emit_jmp(0); } else if(*adj==0||invert) { if(g_dev.r4300.cp0.count_per_op_denom_pot) { count += (1 << g_dev.r4300.cp0.count_per_op_denom_pot) - 1; count >>= g_dev.r4300.cp0.count_per_op_denom_pot; } emit_addimm_and_set_flags(CLOCK_DIVIDER*(count+2),HOST_CCREG); jaddr=(intptr_t)out; emit_jns(0); } else { emit_cmpimm(HOST_CCREG,-(int)CLOCK_DIVIDER*(count+2)); jaddr=(intptr_t)out; emit_jns(0); } add_stub(CC_STUB,jaddr,idle?idle:(intptr_t)out,(*adj==0||invert||idle)?0:(count+2),i,addr,taken,0); } /**** Stubs ****/ static void do_ccstub(int n) { literal_pool(256); assem_debug("do_ccstub %x",start+stubs[n][4]*4); set_jump_target(stubs[n][1],(intptr_t)out); int i=stubs[n][4]; if(stubs[n][6]==NULLDS) { // Delay slot instruction is nullified ("likely" branch) wb_dirtys(regs[i].regmap,regs[i].is32,regs[i].dirty); } else if(stubs[n][6]!=TAKEN) { wb_dirtys(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty); } else { if(internal_branch(branch_regs[i].is32,ba[i])) wb_needed_dirtys(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); } if(stubs[n][5]!=-1) { // Save PC as return address emit_movimm(stubs[n][5],0); emit_writeword(0,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pcaddr); } else { // Return address depends on which way the branch goes if(itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { int s1l=get_reg(branch_regs[i].regmap,rs1[i]); int s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); int s2l=get_reg(branch_regs[i].regmap,rs2[i]); int s2h=get_reg(branch_regs[i].regmap,rs2[i]|64); if(rs1[i]==0) { s1l=s2l;s1h=s2h; s2l=s2h=-1; } else if(rs2[i]==0) { s2l=s2h=-1; } if((branch_regs[i].is32>>rs1[i])&(branch_regs[i].is32>>rs2[i])&1) { s1h=s2h=-1; } assert(s1l>=0); #ifdef DESTRUCTIVE_WRITEBACK if(rs1[i]) { if((branch_regs[i].dirty>>s1l)&(branch_regs[i].is32>>rs1[i])&1) emit_loadreg(rs1[i],s1l); } else { if((branch_regs[i].dirty>>s1l)&(branch_regs[i].is32>>rs2[i])&1) emit_loadreg(rs2[i],s1l); } if(s2l>=0) if((branch_regs[i].dirty>>s2l)&(branch_regs[i].is32>>rs2[i])&1) emit_loadreg(rs2[i],s2l); #endif int hr=0; int addr,alt,ntaddr; while(hr=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmov2imm_e_ne_compact(ba[i],start+i*4+8,addr); } else #endif { emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); if(s1h>=0) { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); emit_cmovne_reg(alt,addr); } if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmovne_reg(alt,addr); } } if((opcode[i]&0x2f)==5) // BNE { #ifdef HAVE_CMOV_IMM if(s1h<0) { if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmov2imm_e_ne_compact(start+i*4+8,ba[i],addr); } else #endif { emit_mov2imm_compact(start+i*4+8,addr,ba[i],alt); if(s1h>=0) { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); emit_cmovne_reg(alt,addr); } if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmovne_reg(alt,addr); } } if((opcode[i]&0x2f)==6) // BLEZ { //emit_movimm(ba[i],alt); //emit_movimm(start+i*4+8,addr); emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); emit_cmpimm(s1l,1); if(s1h>=0) emit_mov(addr,ntaddr); emit_cmovl_reg(alt,addr); if(s1h>=0) { emit_test(s1h,s1h); emit_cmovne_reg(ntaddr,addr); emit_cmovs_reg(alt,addr); } } if((opcode[i]&0x2f)==7) // BGTZ { //emit_movimm(ba[i],addr); //emit_movimm(start+i*4+8,ntaddr); emit_mov2imm_compact(ba[i],addr,start+i*4+8,ntaddr); emit_cmpimm(s1l,1); if(s1h>=0) emit_mov(addr,alt); emit_cmovl_reg(ntaddr,addr); if(s1h>=0) { emit_test(s1h,s1h); emit_cmovne_reg(alt,addr); emit_cmovs_reg(ntaddr,addr); } } if((opcode[i]==1)&&(opcode2[i]&0x2D)==0) // BLTZ { //emit_movimm(ba[i],alt); //emit_movimm(start+i*4+8,addr); emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); if(s1h>=0) emit_test(s1h,s1h); else emit_test(s1l,s1l); emit_cmovs_reg(alt,addr); } if((opcode[i]==1)&&(opcode2[i]&0x2D)==1) // BGEZ { //emit_movimm(ba[i],addr); //emit_movimm(start+i*4+8,alt); emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); if(s1h>=0) emit_test(s1h,s1h); else emit_test(s1l,s1l); emit_cmovs_reg(alt,addr); } if(opcode[i]==0x11 && opcode2[i]==0x08 ) { if(source[i]&0x10000) // BC1T { //emit_movimm(ba[i],alt); //emit_movimm(start+i*4+8,addr); emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); emit_testimm(s1l,0x800000); emit_cmovne_reg(alt,addr); } else // BC1F { //emit_movimm(ba[i],addr); //emit_movimm(start+i*4+8,alt); emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); emit_testimm(s1l,0x800000); emit_cmovne_reg(alt,addr); } } emit_writeword(addr,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pcaddr); } else if(itype[i]==RJUMP) { int r=get_reg(branch_regs[i].regmap,rs1[i]); if((rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])&&(rs1[i]!=0)) { r=get_reg(branch_regs[i].regmap,RTEMP); } emit_writeword(r,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pcaddr); } else {DebugMessage(M64MSG_ERROR, "Unknown branch type in do_ccstub");exit(1);} } // Update cycle count assert(branch_regs[i].regmap[HOST_CCREG]==CCREG||branch_regs[i].regmap[HOST_CCREG]==-1); if(stubs[n][3]) emit_addimm(HOST_CCREG,CLOCK_DIVIDER*stubs[n][3],HOST_CCREG); emit_call((intptr_t)cc_interrupt); if(stubs[n][3]) emit_addimm(HOST_CCREG,-(int)CLOCK_DIVIDER*stubs[n][3],HOST_CCREG); if(stubs[n][6]==TAKEN) { if(internal_branch(branch_regs[i].is32,ba[i])) load_needed_regs(branch_regs[i].regmap,regs[(ba[i]-start)>>2].regmap_entry); else if(itype[i]==RJUMP) { int r=get_reg(branch_regs[i].regmap,rs1[i]); if((rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])&&(rs1[i]!=0)) { r=get_reg(branch_regs[i].regmap,RTEMP); } #if NEW_DYNAREC==NEW_DYNAREC_ARM64 if(r==18) { // x18 is used for trampoline jumps, move it to another register (x0) emit_mov(r,0); r=0; stubs[n][2]=jump_vaddr_reg[0]; } #endif emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.pcaddr,r); } }else if(stubs[n][6]==NOTTAKEN) { if(iregmap_entry,i_regs->was32,i_regs->wasdirty); if(get_reg(i_regs->regmap,CCREG)<0) { emit_loadreg(CCREG,HOST_CCREG); } emit_movimm(start+(i*4)+ds,0); // Get PC emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... emit_jmp((intptr_t)fp_exception); } static void do_readstub(int n) { assem_debug("do_readstub %x",start+stubs[n][3]*4); literal_pool(256); set_jump_target(stubs[n][1],(intptr_t)out); int type=stubs[n][0]; int i=stubs[n][3]; int addr=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u_int reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int rth,rt; if(itype[i]==C1LS) { rth=get_reg(i_regmap,FTEMP|64); rt=get_reg(i_regmap,FTEMP); }else{ rth=get_reg(i_regmap,rt1[i]|64); rt=get_reg(i_regmap,rt1[i]); } assert(addr>=0); emit_writeword(addr,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.address); intptr_t ftable=0; if(type==LOADB_STUB||type==LOADBU_STUB) ftable=(intptr_t)read_byte_new; else if(type==LOADH_STUB||type==LOADHU_STUB) ftable=(intptr_t)read_hword_new; else if(type==LOADW_STUB||type==LOADWU_STUB) ftable=(intptr_t)read_word_new; else if(type==LOADD_STUB) ftable=(intptr_t)read_dword_new; else if(type==LOADWL_STUB) { assert(rt>=0); ftable=(intptr_t)LWL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==LOADWR_STUB) { assert(rt>=0); ftable=(intptr_t)LWR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==LOADDL_STUB) { assert(rt>=0); assert(rth>=0); ftable=(intptr_t)LDL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(rth,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } else if(type==LOADDR_STUB) { assert(rt>=0); assert(rth>=0); ftable=(intptr_t)LDR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(rth,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } int cc=get_reg(i_regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); int ds=i_regs!=®s[i]; #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(CLOCK_DIVIDER*(stubs[n][6]+1)); emit_pushimm((start+(i+1)*4)+ds); emit_call((intptr_t)ftable); emit_addimm(ESP,8,ESP); #else emit_movimm((start+(i+1)*4)+ds,ARG1_REG); emit_movimm(CLOCK_DIVIDER*(stubs[n][6]+1),ARG2_REG); emit_call((intptr_t)ftable); #endif restore_regs(reglist); emit_cmpmem_imm((intptr_t)&g_dev.r4300.new_dynarec_hot_state.pending_exception,0); intptr_t jaddr=(intptr_t)out; emit_jeq(0); if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,regs[i].wasconst,i); wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); emit_jmp((intptr_t)&do_interrupt); set_jump_target(jaddr,(intptr_t)out); if(rt>=0) { if(type==LOADB_STUB) emit_movsbl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADBU_STUB) emit_movzbl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADH_STUB) emit_movswl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADHU_STUB) emit_movzwl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADW_STUB||type==LOADWU_STUB||type==LOADWL_STUB||type==LOADWR_STUB) { emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); if(type==LOADWU_STUB) emit_zeroreg(rth); } else if(type==LOADD_STUB||type==LOADDL_STUB||type==LOADDR_STUB) { emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); if(rth>=0) emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword+4,rth); } } emit_jmp(stubs[n][2]); // return address } static void inline_readstub(int type, int i, u_int addr_const, char addr, struct regstat *i_regs, int target, int adj, u_int reglist) { assem_debug("inline_readstub"); int rth=get_reg(i_regs->regmap,target|64); int rt=get_reg(i_regs->regmap,target); #if NEW_DYNAREC <= NEW_DYNAREC_X64 if(addr_const) emit_writeword_imm(addr_const,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.address); else #endif { assert(addr>=0); emit_writeword(addr,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.address); } intptr_t ftable=0; if(type==LOADB_STUB||type==LOADBU_STUB) ftable=(intptr_t)read_byte_new; else if(type==LOADH_STUB||type==LOADHU_STUB) ftable=(intptr_t)read_hword_new; else if(type==LOADW_STUB||type==LOADWU_STUB) ftable=(intptr_t)read_word_new; else if(type==LOADD_STUB) ftable=(intptr_t)read_dword_new; else if(type==LOADWL_STUB) { assert(rt>=0); ftable=(intptr_t)LWL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==LOADWR_STUB) { assert(rt>=0); ftable=(intptr_t)LWR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==LOADDL_STUB) { assert(rt>=0); assert(rth>=0); ftable=(intptr_t)LDL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(rth,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } else if(type==LOADDR_STUB) { assert(rt>=0); assert(rth>=0); ftable=(intptr_t)LDR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(rth,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } int cc=get_reg(i_regs->regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); int ds=i_regs!=®s[i]; #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(CLOCK_DIVIDER*(adj+1)); emit_pushimm((start+(i+1)*4)+ds); emit_call((intptr_t)ftable); emit_addimm(ESP,8,ESP); #else emit_movimm((start+(i+1)*4)+ds,ARG1_REG); emit_movimm(CLOCK_DIVIDER*(adj+1),ARG2_REG); emit_call((intptr_t)ftable); #endif restore_regs(reglist); if((signed int)addr_const>=(signed int)0xC0000000) { // Theoretically we can have a pagefault here, if the TLB has never // been enabled and the address is outside the range 80000000..BFFFFFFF // Write out the registers so the pagefault can be handled. This is // a very rare case and likely represents a bug. emit_cmpmem_imm((intptr_t)&g_dev.r4300.new_dynarec_hot_state.pending_exception,0); intptr_t jaddr=(intptr_t)out; emit_jeq(0); if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,regs[i].wasconst,i); wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); emit_jmp((intptr_t)&do_interrupt); set_jump_target(jaddr,(intptr_t)out); } if(rt>=0) { if(type==LOADB_STUB) emit_movsbl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADBU_STUB) emit_movzbl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADH_STUB) emit_movswl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADHU_STUB) emit_movzwl((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); else if(type==LOADW_STUB||type==LOADWU_STUB||type==LOADWL_STUB||type==LOADWR_STUB) { emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); if(type==LOADWU_STUB) emit_zeroreg(rth); } else if(type==LOADD_STUB||type==LOADDL_STUB||type==LOADDR_STUB) { emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword,rt); if(rth>=0) emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword+4,rth); } } } static void do_writestub(int n) { assem_debug("do_writestub %x",start+stubs[n][3]*4); literal_pool(256); set_jump_target(stubs[n][1],(intptr_t)out); int type=stubs[n][0]; int i=stubs[n][3]; int addr=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u_int reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int rth,rt,r; if(itype[i]==C1LS) { rth=get_reg(i_regmap,FTEMP|64); rt=get_reg(i_regmap,r=FTEMP); }else{ rth=get_reg(i_regmap,rs2[i]|64); rt=get_reg(i_regmap,r=rs2[i]); } assert(addr>=0); assert(rt>=0); emit_writeword(addr,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.address); intptr_t ftable=0; if(type==STOREB_STUB){ ftable=(intptr_t)write_byte_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREH_STUB){ ftable=(intptr_t)write_hword_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREW_STUB){ ftable=(intptr_t)write_word_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STORED_STUB){ ftable=(intptr_t)write_dword_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(r?rth:rt,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } else if(type==STOREWL_STUB){ ftable=(intptr_t)SWL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREWR_STUB){ ftable=(intptr_t)SWR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREDL_STUB){ ftable=(intptr_t)SDL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(r?rth:rt,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } else if(type==STOREDR_STUB){ ftable=(intptr_t)SDR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(r?rth:rt,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } int cc=get_reg(i_regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); int ds=i_regs!=®s[i]; #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(CLOCK_DIVIDER*(stubs[n][6]+1)); emit_pushimm((start+(i+1)*4)+ds); emit_call((intptr_t)ftable); emit_addimm(ESP,8,ESP); #else emit_movimm((start+(i+1)*4)+ds,ARG1_REG); emit_movimm(CLOCK_DIVIDER*(stubs[n][6]+1),ARG2_REG); emit_call((intptr_t)ftable); #endif restore_regs(reglist); emit_cmpmem_imm((intptr_t)&g_dev.r4300.new_dynarec_hot_state.pending_exception,0); intptr_t jaddr=(intptr_t)out; emit_jeq(0); if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,regs[i].wasconst,i); wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); emit_jmp((intptr_t)&do_interrupt); set_jump_target(jaddr,(intptr_t)out); if(cc>=0) { emit_loadreg(CCREG,cc); } emit_jmp(stubs[n][2]); // return address } static void inline_writestub(int type, int i, u_int addr_const, char addr, struct regstat *i_regs, int target, int adj, u_int reglist) { assem_debug("inline_writestub"); int rth=get_reg(i_regs->regmap,target|64); int rt=get_reg(i_regs->regmap,target); assert(rt>=0); #if NEW_DYNAREC <= NEW_DYNAREC_X64 if(addr_const) emit_writeword_imm(addr_const,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.address); else #endif { assert(addr>=0); emit_writeword(addr,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.address); } intptr_t ftable=0; if(type==STOREB_STUB){ ftable=(intptr_t)write_byte_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREH_STUB){ ftable=(intptr_t)write_hword_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREW_STUB){ ftable=(intptr_t)write_word_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STORED_STUB){ ftable=(intptr_t)write_dword_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(target?rth:rt,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } else if(type==STOREWL_STUB){ ftable=(intptr_t)SWL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREWR_STUB){ ftable=(intptr_t)SWR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword); } else if(type==STOREDL_STUB){ ftable=(intptr_t)SDL_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(target?rth:rt,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } else if(type==STOREDR_STUB){ ftable=(intptr_t)SDR_new; emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword); emit_writeword(target?rth:rt,((intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword)+4); } int cc=get_reg(i_regs->regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); int ds=i_regs!=®s[i]; #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(CLOCK_DIVIDER*(adj+1)); emit_pushimm((start+(i+1)*4)+ds); emit_call((intptr_t)ftable); emit_addimm(ESP,8,ESP); #else emit_movimm((start+(i+1)*4)+ds,ARG1_REG); emit_movimm(CLOCK_DIVIDER*(adj+1),ARG2_REG); emit_call((intptr_t)ftable); #endif restore_regs(reglist); if(((signed int)addr_const>=(signed int)0xC0000000)||((addr_const>>16)==0xa430)||((addr_const>>16)==0x8430)) { // Theoretically we can have a pagefault here, if the TLB has never // been enabled and the address is outside the range 80000000..BFFFFFFF // Write out the registers so the pagefault can be handled. This is // a very rare case and likely represents a bug. emit_cmpmem_imm((intptr_t)&g_dev.r4300.new_dynarec_hot_state.pending_exception,0); intptr_t jaddr=(intptr_t)out; emit_jeq(0); if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,regs[i].wasconst,i); wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); emit_jmp((intptr_t)&do_interrupt); set_jump_target(jaddr,(intptr_t)out); } if(cc>=0) { emit_loadreg(CCREG,cc); } } /**** Assemble ****/ static void cop0_assemble(int i,struct regstat *i_regs) { u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,rt1[i]); char copr=(source[i]>>11)&0x1f; if(t>=0) { reglist&=~(1<regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); //Always update the count even if it's only necessary when (copr==CP0_COUNT_REG||copr==CP0_RANDOM_REG) #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(CLOCK_DIVIDER*ccadj[i]); emit_pushimm(copr); emit_call((intptr_t)MFC0_new); emit_addimm(ESP,8,ESP); #else emit_movimm(copr,ARG1_REG); emit_movimm(CLOCK_DIVIDER*ccadj[i],ARG2_REG); emit_call((intptr_t)MFC0_new); #endif restore_regs(reglist); emit_readword((uintptr_t)&g_dev.r4300.new_dynarec_hot_state.rt,t); } } } else if(opcode2[i]==4) // MTC0 { signed char s=get_reg(i_regs->regmap,rs1[i]); char copr=(source[i]>>11)&0x1f; assert(s>=0); emit_writeword(s,(uintptr_t)&g_dev.r4300.new_dynarec_hot_state.rt); int cc=get_reg(i_regs->regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); // Always update the count even if it's only necessary when (copr==CP0_COUNT_REG||copr==CP0_COMPARE_REG||copr==CP0_STATUS_REG) // Always update the pcaddr even if it's only necessary when (copr==CP0_COUNT_REG||copr==CP0_STATUS_REG) #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(start+i*4); emit_pushimm(CLOCK_DIVIDER*(ccadj[i]+(copr==CP0_STATUS_REG))); emit_pushimm(copr); emit_call((intptr_t)MTC0_new); emit_addimm(ESP,12,ESP); #else emit_movimm(copr,ARG1_REG); emit_movimm(CLOCK_DIVIDER*(ccadj[i]+(copr==CP0_STATUS_REG)),ARG2_REG); emit_movimm(start+i*4,ARG3_REG); emit_call((intptr_t)MTC0_new); #endif restore_regs(reglist); if(copr==CP0_COUNT_REG||copr==CP0_STATUS_REG) { assert(!is_delayslot); emit_cmpmem_imm((intptr_t)&g_dev.r4300.new_dynarec_hot_state.pending_exception,0); intptr_t jaddr=(intptr_t)out; emit_jeq(0); load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty,regs[i].wasconst,i); wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); emit_jmp((intptr_t)&do_interrupt); set_jump_target(jaddr,(intptr_t)out); } if(copr==CP0_COUNT_REG||copr==CP0_COMPARE_REG||copr==CP0_STATUS_REG){ if(cc>=0) { emit_loadreg(CCREG,cc); } } cop1_usable=0; } else { assert(opcode2[i]==0x10); if((source[i]&0x3f)==0x08) // TLBP { save_regs(reglist); emit_call((intptr_t)cached_interp_TLBP); restore_regs(reglist); } else if((source[i]&0x3f)==0x01) // TLBR { save_regs(reglist); emit_call((intptr_t)cached_interp_TLBR); restore_regs(reglist); } else if((source[i]&0x3f)==0x02) { // TLBWI assert(!is_delayslot); int cc=get_reg(i_regs->regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(CLOCK_DIVIDER*ccadj[i]); emit_pushimm(start+i*4); emit_call((intptr_t)TLBWI_new); emit_addimm(ESP,8,ESP); #else emit_movimm(start+i*4,ARG1_REG); emit_movimm(CLOCK_DIVIDER*ccadj[i],ARG2_REG); emit_call((intptr_t)TLBWI_new); #endif restore_regs(reglist); } else if((source[i]&0x3f)==0x06) { // TLBWR assert(!is_delayslot); int cc=get_reg(i_regs->regmap,CCREG); if(cc>=0) { emit_storereg(CCREG,cc); } save_regs(reglist); #if NEW_DYNAREC == NEW_DYNAREC_X86 emit_pushimm(CLOCK_DIVIDER*ccadj[i]); emit_pushimm(start+i*4); emit_call((intptr_t)TLBWR_new); emit_addimm(ESP,8,ESP); #else emit_movimm(start+i*4,ARG1_REG); emit_movimm(CLOCK_DIVIDER*ccadj[i],ARG2_REG); emit_call((intptr_t)TLBWR_new); #endif restore_regs(reglist); } else if((source[i]&0x3f)==0x18) // ERET { assert(!is_delayslot); int count=ccadj[i]; if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*count,HOST_CCREG); emit_jmp((intptr_t)jump_eret); } } } static void cop1_assemble(int i,struct regstat *i_regs) { // Check cop1 unusable if(!cop1_usable) { signed char rs=get_reg(i_regs->regmap,CSREG); assert(rs>=0); emit_testimm(rs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,rs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } if (opcode2[i]==0) { // MFC1 signed char tl=get_reg(i_regs->regmap,rt1[i]); if(tl>=0) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],tl); emit_readword_indexed(0,tl,tl); } } else if (opcode2[i]==1) { // DMFC1 signed char tl=get_reg(i_regs->regmap,rt1[i]); signed char th=get_reg(i_regs->regmap,rt1[i]|64); if(tl>=0) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],tl); if(th>=0) emit_readword_indexed(4,tl,th); emit_readword_indexed(0,tl,tl); } } else if (opcode2[i]==4) { // MTC1 signed char sl=get_reg(i_regs->regmap,rs1[i]); signed char temp=get_reg(i_regs->regmap,-1); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_writeword_indexed(sl,0,temp); } else if (opcode2[i]==5) { // DMTC1 signed char sl=get_reg(i_regs->regmap,rs1[i]); signed char sh=rs1[i]>0?get_reg(i_regs->regmap,rs1[i]|64):sl; signed char temp=get_reg(i_regs->regmap,-1); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_writeword_indexed(sh,4,temp); emit_writeword_indexed(sl,0,temp); } else if (opcode2[i]==2) // CFC1 { signed char tl=get_reg(i_regs->regmap,rt1[i]); signed char fs=get_reg(i_regs->regmap,FSREG); if(tl>=0) { u_int copr=(source[i]>>11)&0x1f; if(copr==0) emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr0,tl); if(copr==31) { if(fs>=0) emit_mov(fs,tl); else emit_loadreg(FSREG,tl); } } } else if (opcode2[i]==6) // CTC1 { signed char sl=get_reg(i_regs->regmap,rs1[i]); signed char fs=get_reg(i_regs->regmap,FSREG); signed char temp=get_reg(i_regs->regmap,-1); u_int copr=(source[i]>>11)&0x1f; assert(sl>=0); if(copr==31) { if(fs>=0) emit_mov(sl,fs); else emit_storereg(FSREG,sl); set_rounding_mode(sl,temp); } } } static void alu_assemble(int i,struct regstat *i_regs) { if(opcode2[i]>=0x20&&opcode2[i]<=0x23) { // ADD/ADDU/SUB/SUBU if(rt1[i]) { signed char s1,s2,t; t=get_reg(i_regs->regmap,rt1[i]); if(t>=0) { s1=get_reg(i_regs->regmap,rs1[i]); s2=get_reg(i_regs->regmap,rs2[i]); if(rs1[i]&&rs2[i]) { assert(s1>=0); assert(s2>=0); if(opcode2[i]&2) emit_sub(s1,s2,t); else emit_add(s1,s2,t); } else if(rs1[i]) { if(s1>=0) emit_mov(s1,t); else emit_loadreg(rs1[i],t); } else if(rs2[i]) { if(s2>=0) { if(opcode2[i]&2) emit_neg(s2,t); else emit_mov(s2,t); } else { emit_loadreg(rs2[i],t); if(opcode2[i]&2) emit_neg(t,t); } } else emit_zeroreg(t); } } } if(opcode2[i]>=0x2c&&opcode2[i]<=0x2f) { // DADD/DADDU/DSUB/DSUBU if(rt1[i]) { signed char s1l,s2l,s1h,s2h,tl,th; tl=get_reg(i_regs->regmap,rt1[i]); th=get_reg(i_regs->regmap,rt1[i]|64); if(tl>=0) { s1l=get_reg(i_regs->regmap,rs1[i]); s2l=get_reg(i_regs->regmap,rs2[i]); s1h=get_reg(i_regs->regmap,rs1[i]|64); s2h=get_reg(i_regs->regmap,rs2[i]|64); if(rs1[i]&&rs2[i]) { assert(s1l>=0); assert(s2l>=0); if(th>=0) { #ifdef INVERTED_CARRY if(opcode2[i]&2) emit_sub64_32(s1l,s1h,s2l,s2h,tl,th); #else if(opcode2[i]&2) { emit_subs(s1l,s2l,tl); emit_sbc(s1h,s2h,th); } #endif else { emit_adds(s1l,s2l,tl); emit_adc(s1h,s2h,th); } } else { if(opcode2[i]&2) emit_subs(s1l,s2l,tl); else emit_adds(s1l,s2l,tl); } } else if(rs1[i]) { if(s1l>=0) emit_mov(s1l,tl); else emit_loadreg(rs1[i],tl); if(th>=0) { if(s1h>=0) emit_mov(s1h,th); else emit_loadreg(rs1[i]|64,th); } } else if(rs2[i]) { if(s2l>=0) { if(opcode2[i]&2) emit_negs(s2l,tl); else emit_mov(s2l,tl); } else { emit_loadreg(rs2[i],tl); if(opcode2[i]&2) emit_negs(tl,tl); } if(th>=0) { #ifdef INVERTED_CARRY if(s2h>=0) emit_mov(s2h,th); else emit_loadreg(rs2[i]|64,th); if(opcode2[i]&2) { emit_adcimm(-1,th); // x86 has inverted carry flag emit_not(th,th); } #else if(opcode2[i]&2) { if(s2h>=0) emit_rscimm(s2h,0,th); else { emit_loadreg(rs2[i]|64,th); emit_rscimm(th,0,th); } }else{ if(s2h>=0) emit_mov(s2h,th); else emit_loadreg(rs2[i]|64,th); } #endif } } else { emit_zeroreg(tl); if(th>=0) emit_zeroreg(th); } } } } if(opcode2[i]==0x2a||opcode2[i]==0x2b) { // SLT/SLTU if(rt1[i]) { signed char s1l,s1h,s2l,s2h,t; if(!((i_regs->was32>>rs1[i])&(i_regs->was32>>rs2[i])&1)) { t=get_reg(i_regs->regmap,rt1[i]); //assert(t>=0); if(t>=0) { s1l=get_reg(i_regs->regmap,rs1[i]); s1h=get_reg(i_regs->regmap,rs1[i]|64); s2l=get_reg(i_regs->regmap,rs2[i]); s2h=get_reg(i_regs->regmap,rs2[i]|64); if(rs2[i]==0) // rx=0); if(opcode2[i]==0x2a) // SLT emit_shrimm(s1h,31,t); else // SLTU (unsigned can not be less than zero) emit_zeroreg(t); } else if(rs1[i]==0) // r0=0); if(opcode2[i]==0x2a) // SLT emit_set_gz64_32(s2h,s2l,t); else // SLTU (set if not zero) emit_set_nz64_32(s2h,s2l,t); } else { assert(s1l>=0);assert(s1h>=0); assert(s2l>=0);assert(s2h>=0); if(opcode2[i]==0x2a) // SLT emit_set_if_less64_32(s1h,s1l,s2h,s2l,t); else // SLTU emit_set_if_carry64_32(s1h,s1l,s2h,s2l,t); } } } else { t=get_reg(i_regs->regmap,rt1[i]); //assert(t>=0); if(t>=0) { s1l=get_reg(i_regs->regmap,rs1[i]); s2l=get_reg(i_regs->regmap,rs2[i]); if(rs2[i]==0) // rx=0); if(opcode2[i]==0x2a) // SLT emit_shrimm(s1l,31,t); else // SLTU (unsigned can not be less than zero) emit_zeroreg(t); } else if(rs1[i]==0) // r0=0); if(opcode2[i]==0x2a) // SLT emit_set_gz32(s2l,t); else // SLTU (set if not zero) emit_set_nz32(s2l,t); } else{ assert(s1l>=0);assert(s2l>=0); if(opcode2[i]==0x2a) // SLT emit_set_if_less32(s1l,s2l,t); else // SLTU emit_set_if_carry32(s1l,s2l,t); } } } } } if(opcode2[i]>=0x24&&opcode2[i]<=0x27) { // AND/OR/XOR/NOR if(rt1[i]) { signed char s1l,s1h,s2l,s2h,th,tl; tl=get_reg(i_regs->regmap,rt1[i]); th=get_reg(i_regs->regmap,rt1[i]|64); if(!((i_regs->was32>>rs1[i])&(i_regs->was32>>rs2[i])&1)&&th>=0) { assert(tl>=0); if(tl>=0) { s1l=get_reg(i_regs->regmap,rs1[i]); s1h=get_reg(i_regs->regmap,rs1[i]|64); s2l=get_reg(i_regs->regmap,rs2[i]); s2h=get_reg(i_regs->regmap,rs2[i]|64); if(rs1[i]&&rs2[i]) { assert(s1l>=0);assert(s1h>=0); assert(s2l>=0);assert(s2h>=0); if(opcode2[i]==0x24) { // AND emit_and(s1l,s2l,tl); emit_and(s1h,s2h,th); } else if(opcode2[i]==0x25) { // OR emit_or(s1l,s2l,tl); emit_or(s1h,s2h,th); } else if(opcode2[i]==0x26) { // XOR emit_xor(s1l,s2l,tl); emit_xor(s1h,s2h,th); } else if(opcode2[i]==0x27) { // NOR emit_or(s1l,s2l,tl); emit_or(s1h,s2h,th); emit_not(tl,tl); emit_not(th,th); } } else { if(opcode2[i]==0x24) { // AND emit_zeroreg(tl); emit_zeroreg(th); } else if(opcode2[i]==0x25||opcode2[i]==0x26) { // OR/XOR if(rs1[i]){ if(s1l>=0) emit_mov(s1l,tl); else emit_loadreg(rs1[i],tl); if(s1h>=0) emit_mov(s1h,th); else emit_loadreg(rs1[i]|64,th); } else if(rs2[i]){ if(s2l>=0) emit_mov(s2l,tl); else emit_loadreg(rs2[i],tl); if(s2h>=0) emit_mov(s2h,th); else emit_loadreg(rs2[i]|64,th); } else{ emit_zeroreg(tl); emit_zeroreg(th); } } else if(opcode2[i]==0x27) { // NOR if(rs1[i]){ if(s1l>=0) emit_not(s1l,tl); else{ emit_loadreg(rs1[i],tl); emit_not(tl,tl); } if(s1h>=0) emit_not(s1h,th); else{ emit_loadreg(rs1[i]|64,th); emit_not(th,th); } } else if(rs2[i]){ if(s2l>=0) emit_not(s2l,tl); else{ emit_loadreg(rs2[i],tl); emit_not(tl,tl); } if(s2h>=0) emit_not(s2h,th); else{ emit_loadreg(rs2[i]|64,th); emit_not(th,th); } } else { emit_movimm(-1,tl); emit_movimm(-1,th); } } } } } else { // 32 bit if(tl>=0) { s1l=get_reg(i_regs->regmap,rs1[i]); s2l=get_reg(i_regs->regmap,rs2[i]); if(rs1[i]&&rs2[i]) { assert(s1l>=0); assert(s2l>=0); if(opcode2[i]==0x24) { // AND emit_and(s1l,s2l,tl); } else if(opcode2[i]==0x25) { // OR emit_or(s1l,s2l,tl); } else if(opcode2[i]==0x26) { // XOR emit_xor(s1l,s2l,tl); } else if(opcode2[i]==0x27) { // NOR emit_or(s1l,s2l,tl); emit_not(tl,tl); } } else { if(opcode2[i]==0x24) { // AND emit_zeroreg(tl); } else if(opcode2[i]==0x25||opcode2[i]==0x26) { // OR/XOR if(rs1[i]){ if(s1l>=0) emit_mov(s1l,tl); else emit_loadreg(rs1[i],tl); // CHECK: regmap_entry? } else if(rs2[i]){ if(s2l>=0) emit_mov(s2l,tl); else emit_loadreg(rs2[i],tl); // CHECK: regmap_entry? } else emit_zeroreg(tl); } else if(opcode2[i]==0x27) { // NOR if(rs1[i]){ if(s1l>=0) emit_not(s1l,tl); else { emit_loadreg(rs1[i],tl); emit_not(tl,tl); } } else if(rs2[i]){ if(s2l>=0) emit_not(s2l,tl); else { emit_loadreg(rs2[i],tl); emit_not(tl,tl); } } else emit_movimm(-1,tl); } } } } } } } static void imm16_assemble(int i,struct regstat *i_regs) { if (opcode[i]==0x0f) { // LUI if(rt1[i]) { signed char t; t=get_reg(i_regs->regmap,rt1[i]); //assert(t>=0); if(t>=0) { if(!((i_regs->isconst>>t)&1)) emit_movimm(imm[i]<<16,t); } } } if(opcode[i]==0x08||opcode[i]==0x09) { // ADDI/ADDIU if(rt1[i]) { signed char s,t; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); if(rs1[i]) { //assert(t>=0); //assert(s>=0); if(t>=0) { if(!((i_regs->isconst>>t)&1)) { if(s<0) { if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); emit_addimm(t,imm[i],t); }else{ if(!((i_regs->wasconst>>s)&1)) emit_addimm(s,imm[i],t); else emit_movimm(constmap[i][s]+imm[i],t); } } } } else { if(t>=0) { if(!((i_regs->isconst>>t)&1)) emit_movimm(imm[i],t); } } } } if(opcode[i]==0x18||opcode[i]==0x19) { // DADDI/DADDIU if(rt1[i]) { signed char sh,sl,th,tl; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); if(tl>=0) { if(rs1[i]) { assert(sh>=0); assert(sl>=0); if(th>=0) { emit_addimm64_32(sh,sl,imm[i],th,tl); } else { emit_addimm(sl,imm[i],tl); } } else { emit_movimm(imm[i],tl); if(th>=0) emit_movimm(((signed int)imm[i])>>31,th); } } } } else if(opcode[i]==0x0a||opcode[i]==0x0b) { // SLTI/SLTIU if(rt1[i]) { //assert(rs1[i]!=0); // r0 might be valid, but it's probably a bug signed char sh,sl,t; t=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); //assert(t>=0); if(t>=0) { if(rs1[i]>0) { if(sh<0) assert((i_regs->was32>>rs1[i])&1); if(sh<0||((i_regs->was32>>rs1[i])&1)) { if(opcode[i]==0x0a) { // SLTI if(sl<0) { if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); emit_slti32(t,imm[i],t); }else{ emit_slti32(sl,imm[i],t); } } else { // SLTIU if(sl<0) { if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); emit_sltiu32(t,imm[i],t); }else{ emit_sltiu32(sl,imm[i],t); } } }else{ // 64-bit assert(sl>=0); if(opcode[i]==0x0a) // SLTI emit_slti64_32(sh,sl,imm[i],t); else // SLTIU emit_sltiu64_32(sh,sl,imm[i],t); } }else{ // SLTI(U) with r0 is just stupid, // nonetheless examples can be found if(opcode[i]==0x0a) // SLTI if(0=0x0c&&opcode[i]<=0x0e) { // ANDI/ORI/XORI if(rt1[i]) { signed char sh,sl,th,tl; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); if(tl>=0 && !((i_regs->isconst>>tl)&1)) { if(opcode[i]==0x0c) //ANDI { if(rs1[i]) { if(sl<0) { if(i_regs->regmap_entry[tl]!=rs1[i]) emit_loadreg(rs1[i],tl); emit_andimm(tl,imm[i],tl); }else{ if(!((i_regs->wasconst>>sl)&1)) emit_andimm(sl,imm[i],tl); else emit_movimm(constmap[i][sl]&imm[i],tl); } } else emit_zeroreg(tl); if(th>=0) emit_zeroreg(th); } else { if(rs1[i]) { if(sl<0) { if(i_regs->regmap_entry[tl]!=rs1[i]) emit_loadreg(rs1[i],tl); } if(th>=0) { if(sh<0) { emit_loadreg(rs1[i]|64,th); }else{ emit_mov(sh,th); } } if(opcode[i]==0x0d) { //ORI if(sl<0) { emit_orimm(tl,imm[i],tl); }else{ if(!((i_regs->wasconst>>sl)&1)) emit_orimm(sl,imm[i],tl); else emit_movimm((int)(constmap[i][sl]|imm[i]),tl); } } if(opcode[i]==0x0e) { //XORI if(sl<0) { emit_xorimm(tl,imm[i],tl); }else{ if(!((i_regs->wasconst>>sl)&1)) emit_xorimm(sl,imm[i],tl); else emit_movimm((int)(constmap[i][sl]^imm[i]),tl); } } } else { emit_movimm(imm[i],tl); if(th>=0) emit_zeroreg(th); } } } } } } static void shiftimm_assemble(int i,struct regstat *i_regs) { if(opcode2[i]<=0x3) // SLL/SRL/SRA { if(rt1[i]) { signed char s,t; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); //assert(t>=0); if(t>=0){ if(rs1[i]==0) { emit_zeroreg(t); } else { if(s<0&&i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); if(imm[i]) { if(opcode2[i]==0) // SLL { emit_shlimm(s<0?t:s,imm[i],t); } if(opcode2[i]==2) // SRL { emit_shrimm(s<0?t:s,imm[i],t); } if(opcode2[i]==3) // SRA { emit_sarimm(s<0?t:s,imm[i],t); } }else{ // Shift by zero if(s>=0 && s!=t) emit_mov(s,t); } } } //emit_storereg(rt1[i],t); //DEBUG } } if(opcode2[i]>=0x38&&opcode2[i]<=0x3b) // DSLL/DSRL/DSRA { if(rt1[i]) { signed char sh,sl,th,tl; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); if(tl>=0) { if(rs1[i]==0) { emit_zeroreg(tl); if(th>=0) emit_zeroreg(th); } else { assert(sl>=0); assert(sh>=0); if(imm[i]) { if(opcode2[i]==0x38) // DSLL { if(th>=0) emit_shldimm(sh,sl,imm[i],th); emit_shlimm(sl,imm[i],tl); } if(opcode2[i]==0x3a) // DSRL { emit_shrdimm(sl,sh,imm[i],tl); if(th>=0) emit_shrimm(sh,imm[i],th); } if(opcode2[i]==0x3b) // DSRA { emit_shrdimm(sl,sh,imm[i],tl); if(th>=0) emit_sarimm(sh,imm[i],th); } }else{ // Shift by zero if(sl!=tl) emit_mov(sl,tl); if(th>=0&&sh!=th) emit_mov(sh,th); } } } } } if(opcode2[i]==0x3c) // DSLL32 { if(rt1[i]) { signed char sl,tl,th; tl=get_reg(i_regs->regmap,rt1[i]); th=get_reg(i_regs->regmap,rt1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); if(th>=0||tl>=0){ assert(tl>=0); assert(th>=0); assert(sl>=0); emit_mov(sl,th); emit_zeroreg(tl); if(imm[i]>32) { emit_shlimm(th,imm[i]&31,th); } } } } if(opcode2[i]==0x3e) // DSRL32 { if(rt1[i]) { signed char sh,tl,th; tl=get_reg(i_regs->regmap,rt1[i]); th=get_reg(i_regs->regmap,rt1[i]|64); sh=get_reg(i_regs->regmap,rs1[i]|64); if(tl>=0){ assert(sh>=0); emit_mov(sh,tl); if(th>=0) emit_zeroreg(th); if(imm[i]>32) { emit_shrimm(tl,imm[i]&31,tl); } } } } if(opcode2[i]==0x3f) // DSRA32 { if(rt1[i]) { signed char sh,tl; tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); if(tl>=0){ assert(sh>=0); emit_mov(sh,tl); if(imm[i]>32) { emit_sarimm(tl,imm[i]&31,tl); } } } } } #ifndef shift_assemble void shift_assemble(int i,struct regstat *i_regs) { DebugMessage(M64MSG_ERROR, "Need shift_assemble for this architecture."); exit(1); } #endif static void load_assemble(int i,struct regstat *i_regs) { signed char s,th,tl,addr,map=-1,cache=-1; int offset,type=0,memtarget=0,c=0; intptr_t jaddr=0; u_int hr,reglist=0; int agr=AGEN1+(i&1); th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0) { c=(i_regs->wasconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } int temp=get_reg(i_regs->regmap,agr); if(temp<0) temp=get_reg(i_regs->regmap,-1); assert(temp>=0); if(tl<0) tl=temp; if(offset||s<0||c) addr=temp; else addr=s; assert(tl>=0); // Even if the load is a NOP, we must check for pagefaults and I/O int dummy=(rt1[i]==0)||(tl!=get_reg(i_regs->regmap,rt1[i])); // ignore loads to r0 and unneeded reg switch(opcode[i]) { case 0x20: type=LOADB_STUB; break; case 0x21: type=LOADH_STUB; break; case 0x23: type=LOADW_STUB; break; case 0x24: type=LOADBU_STUB; break; case 0x25: type=LOADHU_STUB; break; case 0x27: type=LOADWU_STUB; break; case 0x37: type=LOADD_STUB; break; } #ifndef INTERPRET_LOAD if(!using_tlb) { if(!c) { //#define R29_HACK 1 #ifdef R29_HACK // Strmnnrmn's speed hack if(rs1[i]!=29||start<0x80001000||start>=0x80800000) #endif { emit_cmpimm(addr,0x800000); jaddr=(intptr_t)out; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK // Hint to branch predictor that the branch is unlikely to be taken if(rs1[i]>=28) emit_jno_unlikely(0); else #endif emit_jno(0); } } #ifdef RAM_OFFSET #ifndef NATIVE_64 if(!c&&!dummy) #else if((!c||memtarget)&&!dummy) #endif { map=get_reg(i_regs->regmap,ROREG); if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); } #endif }else{ // using tlb int x=0; if (opcode[i]==0x20||opcode[i]==0x24) x=3; // LB/LBU if (opcode[i]==0x21||opcode[i]==0x25) x=2; // LH/LHU map=get_reg(i_regs->regmap,TLREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<=0); #ifdef HOST_IMM_ADDR32 if(c) emit_readword_tlb(constmap[i][s]+offset,map,tl); else #endif emit_readword_indexed_tlb(0,addr,map,tl); emit_zeroreg(th); } else if (opcode[i]==0x37) { // LD #ifdef HOST_IMM_ADDR32 if(c) emit_readdword_tlb(constmap[i][s]+offset,map,th,tl); else #endif emit_readdword_indexed_tlb(0,addr,map,th,tl); } } if(jaddr) { add_stub(type,jaddr,(intptr_t)out,i,addr,(intptr_t)i_regs,ccadj[i],reglist); } else if(c&&!memtarget) { inline_readstub(type,i,constmap[i][s]+offset,addr,i_regs,rt1[i],ccadj[i],reglist); } #else inline_readstub(type,i,c?(constmap[i][s]+offset):0,addr,i_regs,rt1[i],ccadj[i],reglist); #endif } #ifndef loadlr_assemble static void loadlr_assemble(int i,struct regstat *i_regs) { DebugMessage(M64MSG_ERROR, "Need loadlr_assemble for this architecture."); exit(1); } #endif static void store_assemble(int i,struct regstat *i_regs) { signed char s,th,tl,real_addr,addr,temp,map=-1,cache=-1; int offset,type=0,memtarget=0,c=0; intptr_t jaddr=0; u_int hr,reglist=0; int agr=AGEN1+(i&1); th=get_reg(i_regs->regmap,rs2[i]|64); tl=get_reg(i_regs->regmap,rs2[i]); s=get_reg(i_regs->regmap,rs1[i]); temp=get_reg(i_regs->regmap,agr); if(temp<0) temp=get_reg(i_regs->regmap,-1); offset=imm[i]; if(s>=0) { c=(i_regs->wasconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } assert(tl>=0); assert(temp>=0); for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0x80800000) #endif emit_cmpimm(addr,0x800000); #ifdef R29_HACK if(rs1[i]!=29||start<0x80001000||start>=0x80800000) #endif { jaddr=(intptr_t)out; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK // Hint to branch predictor that the branch is unlikely to be taken if(rs1[i]>=28) emit_jno_unlikely(0); else #endif emit_jno(0); } #ifdef DESTRUCTIVE_SHIFT if(s==addr) emit_mov(s,temp); #endif } #ifdef RAM_OFFSET if(!c||memtarget) { map=get_reg(i_regs->regmap,ROREG); if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); } #endif }else{ // using tlb int x=0; if (opcode[i]==0x28) x=3; // SB if (opcode[i]==0x29) x=2; // SH map=get_reg(i_regs->regmap,TLREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<=0); emit_writedword_indexed_tlb(th,tl,0,addr,map); }else{ // Store zero emit_writedword_indexed_tlb(tl,tl,0,addr,map); } } if(!using_tlb) { #ifdef DESTRUCTIVE_SHIFT // The x86 shift operation is 'destructive'; it overwrites the // source register, so we need to make a copy first and use that. addr=temp; #endif #if defined(HOST_IMM8) || defined(NEED_INVC_PTR) int ir=get_reg(i_regs->regmap,INVCP); assert(ir>=0); emit_cmpmem_indexedsr12_reg(ir,addr,1); #else emit_cmpmem_indexedsr12_imm((intptr_t)g_dev.r4300.cached_interp.invalid_code,addr,1); #endif #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) emit_callne(invalidate_addr_reg[addr]); #else intptr_t jaddr2=(intptr_t)out; emit_jne(0); add_stub(INVCODE_STUB,jaddr2,(intptr_t)out,reglist|(1<regmap,rs2[i]|64); tl=get_reg(i_regs->regmap,rs2[i]); s=get_reg(i_regs->regmap,rs1[i]); temp=get_reg(i_regs->regmap,agr); if(temp<0) temp=get_reg(i_regs->regmap,-1); offset=imm[i]; if(s>=0) { c=(i_regs->isconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } assert(tl>=0); assert(temp>=0); for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,FTEMP); if(!rs2[i]) temp2=th=tl; } switch(opcode[i]) { case 0x2A: type=STOREWL_STUB; break; case 0x2E: type=STOREWR_STUB; break; case 0x2C: type=STOREDL_STUB; break; case 0x2D: type=STOREDR_STUB; break; } #ifndef INTERPRET_STORELR if(!using_tlb) { if(!c) { emit_cmpimm(addr,0x800000); jaddr=(intptr_t)out; emit_jno(0); #ifdef DESTRUCTIVE_SHIFT if(s==addr) emit_mov(s,temp); #endif } #ifdef RAM_OFFSET if(!c||memtarget) { map=get_reg(i_regs->regmap,ROREG); if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); } #endif }else{ // using tlb map=get_reg(i_regs->regmap,TLREG); int cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<= NEW_DYNAREC_ARM assert(map>=0); emit_addsl2(addr,map,map); addr=map; map=-1; #endif if(!c) { emit_testimm(real_addr,2); case2=(intptr_t)out; emit_jne(0); emit_testimm(real_addr,1); case1=(intptr_t)out; emit_jne(0); } if(!c||((constmap[i][s]+offset)&3)==0) { if (opcode[i]==0x2A) { // SWL emit_writeword_indexed_tlb(tl,0,addr,map); } else if (opcode[i]==0x2E) { // SWR emit_writebyte_indexed_tlb(tl,3,addr,map); } else if (opcode[i]==0x2C) { // SDL emit_writeword_indexed_tlb(th,0,addr,map); if(rs2[i]) emit_mov(tl,temp2); } else if (opcode[i]==0x2D) { // SDR emit_writebyte_indexed_tlb(tl,3,addr,map); if(rs2[i]) emit_shldimm(th,tl,24,temp2); } } if(!c) { done0=(intptr_t)out; emit_jmp(0); set_jump_target(case1,(intptr_t)out); } if(!c||((constmap[i][s]+offset)&3)==1) { if (opcode[i]==0x2A) { // SWL // Write 3 msb into three least significant bytes if(rs2[i]) emit_rorimm(tl,8,tl); emit_writehword_indexed_tlb(tl,-1,addr,map); if(rs2[i]) emit_rorimm(tl,16,tl); emit_writebyte_indexed_tlb(tl,1,addr,map); if(rs2[i]) emit_rorimm(tl,8,tl); } else if (opcode[i]==0x2E) { // SWR // Write two lsb into two most significant bytes emit_writehword_indexed_tlb(tl,1,addr,map); } else if (opcode[i]==0x2C) { // SDL if(rs2[i]) emit_shrdimm(tl,th,8,temp2); // Write 3 msb into three least significant bytes if(rs2[i]) emit_rorimm(th,8,th); emit_writehword_indexed_tlb(th,-1,addr,map); if(rs2[i]) emit_rorimm(th,16,th); emit_writebyte_indexed_tlb(th,1,addr,map); if(rs2[i]) emit_rorimm(th,8,th); } else if (opcode[i]==0x2D) { // SDR if(rs2[i]) emit_shldimm(th,tl,16,temp2); // Write two lsb into two most significant bytes emit_writehword_indexed_tlb(tl,1,addr,map); } } if(!c) { done1=(intptr_t)out; emit_jmp(0); set_jump_target(case2,(intptr_t)out); emit_testimm(real_addr,1); case3=(intptr_t)out; emit_jne(0); } if(!c||((constmap[i][s]+offset)&3)==2) { if (opcode[i]==0x2A) { // SWL // Write two msb into two least significant bytes if(rs2[i]) emit_rorimm(tl,16,tl); emit_writehword_indexed_tlb(tl,-2,addr,map); if(rs2[i]) emit_rorimm(tl,16,tl); } else if (opcode[i]==0x2E) { // SWR // Write 3 lsb into three most significant bytes emit_writebyte_indexed_tlb(tl,-1,addr,map); if(rs2[i]) emit_rorimm(tl,8,tl); emit_writehword_indexed_tlb(tl,0,addr,map); if(rs2[i]) emit_rorimm(tl,24,tl); } else if (opcode[i]==0x2C) { // SDL if(rs2[i]) emit_shrdimm(tl,th,16,temp2); // Write two msb into two least significant bytes if(rs2[i]) emit_rorimm(th,16,th); emit_writehword_indexed_tlb(th,-2,addr,map); if(rs2[i]) emit_rorimm(th,16,th); } else if (opcode[i]==0x2D) { // SDR if(rs2[i]) emit_shldimm(th,tl,8,temp2); // Write 3 lsb into three most significant bytes emit_writebyte_indexed_tlb(tl,-1,addr,map); if(rs2[i]) emit_rorimm(tl,8,tl); emit_writehword_indexed_tlb(tl,0,addr,map); if(rs2[i]) emit_rorimm(tl,24,tl); } } if(!c) { done2=(intptr_t)out; emit_jmp(0); set_jump_target(case3,(intptr_t)out); } if(!c||((constmap[i][s]+offset)&3)==3) { if (opcode[i]==0x2A) { // SWL // Write msb into least significant byte if(rs2[i]) emit_rorimm(tl,24,tl); emit_writebyte_indexed_tlb(tl,-3,addr,map); if(rs2[i]) emit_rorimm(tl,8,tl); } else if (opcode[i]==0x2E) { // SWR // Write entire word emit_writeword_indexed_tlb(tl,-3,addr,map); } else if (opcode[i]==0x2C) { // SDL if(rs2[i]) emit_shrdimm(tl,th,24,temp2); // Write msb into least significant byte if(rs2[i]) emit_rorimm(th,24,th); emit_writebyte_indexed_tlb(th,-3,addr,map); if(rs2[i]) emit_rorimm(th,8,th); } else if (opcode[i]==0x2D) { // SDR if(rs2[i]) emit_mov(th,temp2); // Write entire word emit_writeword_indexed_tlb(tl,-3,addr,map); } } if(!c) { set_jump_target(done0,(intptr_t)out); set_jump_target(done1,(intptr_t)out); set_jump_target(done2,(intptr_t)out); } signed char temp3=(addr==s)?temp:addr; if (opcode[i]==0x2C) { // SDL if(!c) { emit_testimm(real_addr,4); done0=(intptr_t)out; emit_jne(0); } if(!c||((constmap[i][s]+offset)&4)==0) { #if NEW_DYNAREC == NEW_DYNAREC_ARM64 emit_andimm64(addr,~3,temp3); #else emit_andimm(addr,~3,temp3); #endif emit_writeword_indexed_tlb(temp2,4,temp3,map); } } else if (opcode[i]==0x2D) { // SDR if(!c) { emit_testimm(real_addr,4); done0=(intptr_t)out; emit_jeq(0); } if(!c||((constmap[i][s]+offset)&4)!=0) { #if NEW_DYNAREC == NEW_DYNAREC_ARM64 emit_andimm64(addr,~3,temp3); #else emit_andimm(addr,~3,temp3); #endif emit_writeword_indexed_tlb(temp2,-4,temp3,map); } } if(!c) set_jump_target(done0,(intptr_t)out); if(!using_tlb) { #if NEW_DYNAREC >= NEW_DYNAREC_ARM // Restore ram offset if allocated map=get_reg(i_regs->regmap,ROREG); if(map>=0) emit_loadreg(ROREG,map); #endif #ifdef DESTRUCTIVE_SHIFT // The x86 shift operation is 'destructive'; it overwrites the // source register, so we need to make a copy first and use that. addr=temp; #endif #if defined(HOST_IMM8) || defined(NEED_INVC_PTR) int ir=get_reg(i_regs->regmap,INVCP); assert(ir>=0); emit_cmpmem_indexedsr12_reg(ir,addr,1); #else emit_cmpmem_indexedsr12_imm((intptr_t)g_dev.r4300.cached_interp.invalid_code,addr,1); #endif #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) emit_callne(invalidate_addr_reg[addr]); #else intptr_t jaddr2=(intptr_t)out; emit_jne(0); add_stub(INVCODE_STUB,jaddr2,(intptr_t)out,reglist|(1<regmap,FTEMP|64); tl=get_reg(i_regs->regmap,FTEMP); s=get_reg(i_regs->regmap,rs1[i]); temp=get_reg(i_regs->regmap,agr); if(temp<0) temp=get_reg(i_regs->regmap,-1); offset=imm[i]; assert(tl>=0); assert(rs1[i]>0); assert(temp>=0); for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0) { c=(i_regs->wasconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } if(offset||s<0||c) addr=ar; else addr=s; real_addr=addr; switch(opcode[i]) { case 0x31: type=LOADW_STUB; break; case 0x35: type=LOADD_STUB; break; case 0x39: type=STOREW_STUB; break; case 0x3D: type=STORED_STUB; break; } // Check cop1 unusable if(!cop1_usable) { signed char rs=get_reg(i_regs->regmap,CSREG); assert(rs>=0); emit_testimm(rs,CP0_STATUS_CU1); jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,rs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } if (opcode[i]==0x39) { // SWC1 (get float address) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],tl); emit_readword_indexed(0,tl,tl); } else if (opcode[i]==0x3D) { // SDC1 (get double address) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],tl); emit_readword_indexed(4,tl,th); emit_readword_indexed(0,tl,tl); } #ifndef INTERPRET_C1LS // Generate address + offset if(!using_tlb) { if(!c) { emit_cmpimm(addr,0x800000); jaddr2=(intptr_t)out; emit_jno(0); #ifdef DESTRUCTIVE_SHIFT if (opcode[i]==0x39||opcode[i]==0x3D) { // SWC1/SDC1 if(s==addr) emit_mov(s,temp); } #endif } #ifdef RAM_OFFSET #ifndef NATIVE_64 if ((!c&&(opcode[i]==0x31||opcode[i]==0x35))||((!c||memtarget)&&(opcode[i]==0x39||opcode[i]==0x3D))) #else if(!c||memtarget) #endif { map=get_reg(i_regs->regmap,ROREG); if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); } #endif } else { map=get_reg(i_regs->regmap,TLREG); int cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<=0); #ifdef HOST_IMM_ADDR32 if(c) emit_readdword_tlb(constmap[i][s]+offset,map,th,tl); else #endif emit_readdword_indexed_tlb(0,addr,map,th,tl); } else if (opcode[i]==0x39) { // SWC1 emit_writeword_indexed_tlb(tl,0,addr,map); } else if (opcode[i]==0x3D) { // SDC1 assert(th>=0); emit_writedword_indexed_tlb(th,tl,0,addr,map); } if(!using_tlb) { if (opcode[i]==0x39||opcode[i]==0x3D) { // SWC1/SDC1 #ifdef DESTRUCTIVE_SHIFT addr=temp; #endif #if defined(HOST_IMM8) || defined(NEED_INVC_PTR) int ir=get_reg(i_regs->regmap,INVCP); assert(ir>=0); emit_cmpmem_indexedsr12_reg(ir,addr,1); #else emit_cmpmem_indexedsr12_imm((intptr_t)g_dev.r4300.cached_interp.invalid_code,addr,1); #endif #if defined(HAVE_CONDITIONAL_CALL) && !defined(DESTRUCTIVE_SHIFT) emit_callne(invalidate_addr_reg[addr]); #else intptr_t jaddr3=(intptr_t)out; emit_jne(0); add_stub(INVCODE_STUB,jaddr3,(intptr_t)out,reglist|(1<>16)&0x1f],temp); emit_writeword_indexed(tl,0,temp); } else if (opcode[i]==0x35) { // LDC1 (write double) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],temp); emit_writeword_indexed(th,4,temp); emit_writeword_indexed(tl,0,temp); } } #ifndef multdiv_assemble void multdiv_assemble(int i,struct regstat *i_regs) { DebugMessage(M64MSG_ERROR, "Need multdiv_assemble for this architecture."); exit(1); } #endif static void mov_assemble(int i,struct regstat *i_regs) { //if(opcode2[i]==0x10||opcode2[i]==0x12) { // MFHI/MFLO //if(opcode2[i]==0x11||opcode2[i]==0x13) { // MTHI/MTLO if(rt1[i]) { signed char sh,sl,th,tl; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); //assert(tl>=0); if(tl>=0) { sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); if(sl>=0) emit_mov(sl,tl); else emit_loadreg(rs1[i],tl); if(th>=0) { if(sh>=0) emit_mov(sh,th); else emit_loadreg(rs1[i]|64,th); } } } } #ifndef fconv_assemble void fconv_assemble(int i,struct regstat *i_regs) { DebugMessage(M64MSG_ERROR, "Need fconv_assemble for this architecture."); exit(1); } #endif #if 0 static void float_assemble(int i,struct regstat *i_regs) { DebugMessage(M64MSG_ERROR, "Need float_assemble for this architecture."); exit(1); } #endif static void syscall_assemble(int i,struct regstat *i_regs) { signed char ccreg=get_reg(i_regs->regmap,CCREG); assert(ccreg==HOST_CCREG); assert(!is_delayslot); emit_movimm(start+i*4,0); // Get PC emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... emit_jmp((intptr_t)jump_syscall); } static void ds_assemble(int i,struct regstat *i_regs) { is_delayslot=1; switch(itype[i]) { case ALU: alu_assemble(i,i_regs);break; case IMM16: imm16_assemble(i,i_regs);break; case SHIFT: shift_assemble(i,i_regs);break; case SHIFTIMM: shiftimm_assemble(i,i_regs);break; case LOAD: load_assemble(i,i_regs);break; case LOADLR: loadlr_assemble(i,i_regs);break; case STORE: store_assemble(i,i_regs);break; case STORELR: storelr_assemble(i,i_regs);break; case COP0: cop0_assemble(i,i_regs);break; case COP1: cop1_assemble(i,i_regs);break; case C1LS: c1ls_assemble(i,i_regs);break; case FCONV: fconv_assemble(i,i_regs);break; case FLOAT: float_assemble(i,i_regs);break; case FCOMP: fcomp_assemble(i,i_regs);break; case MULTDIV: multdiv_assemble(i,i_regs);break; case MOV: mov_assemble(i,i_regs);break; case SYSCALL: case SPAN: case UJUMP: case RJUMP: case CJUMP: case SJUMP: case FJUMP: DebugMessage(M64MSG_VERBOSE, "Jump in the delay slot. This is probably a bug."); } is_delayslot=0; } // Used when a branch jumps into the delay slot of another branch static void ds_assemble_entry(int i) { int t=(ba[i]-start)>>2; if(!instr_addr[t]) instr_addr[t]=(uintptr_t)out; assem_debug("Assemble delay slot at %x",ba[i]); assem_debug("<->"); if(regs[t].regmap_entry[HOST_CCREG]==CCREG&®s[t].regmap[HOST_CCREG]!=CCREG) wb_register(CCREG,regs[t].regmap_entry,regs[t].wasdirty,regs[t].was32); load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,rs1[t],rs2[t]); address_generation(t,®s[t],regs[t].regmap_entry); if(itype[t]==LOAD||itype[t]==LOADLR||itype[t]==STORE||itype[t]==STORELR||itype[t]==C1LS) load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,MMREG,ROREG); if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39) load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,INVCP,INVCP); cop1_usable=0; is_delayslot=0; int cc=ccadj[t]; ccadj[t]=-1; switch(itype[t]) { case ALU: alu_assemble(t,®s[t]);break; case IMM16: imm16_assemble(t,®s[t]);break; case SHIFT: shift_assemble(t,®s[t]);break; case SHIFTIMM: shiftimm_assemble(t,®s[t]);break; case LOAD: load_assemble(t,®s[t]);break; case LOADLR: loadlr_assemble(t,®s[t]);break; case STORE: store_assemble(t,®s[t]);break; case STORELR: storelr_assemble(t,®s[t]);break; case COP0: cop0_assemble(t,®s[t]);break; case COP1: cop1_assemble(t,®s[t]);break; case C1LS: c1ls_assemble(t,®s[t]);break; case FCONV: fconv_assemble(t,®s[t]);break; case FLOAT: float_assemble(t,®s[t]);break; case FCOMP: fcomp_assemble(t,®s[t]);break; case MULTDIV: multdiv_assemble(t,®s[t]);break; case MOV: mov_assemble(t,®s[t]);break; case SYSCALL: case SPAN: case UJUMP: case RJUMP: case CJUMP: case SJUMP: case FJUMP: DebugMessage(M64MSG_VERBOSE, "Jump in the delay slot. This is probably a bug."); } store_regs_bt(regs[t].regmap,regs[t].is32,regs[t].dirty,ba[i]+4); load_regs_bt(regs[t].regmap,regs[t].is32,regs[t].dirty,ba[i]+4); if(internal_branch(regs[t].is32,ba[i]+4)) assem_debug("branch: internal"); else assem_debug("branch: external"); assert(internal_branch(regs[t].is32,ba[i]+4)); add_to_linker((intptr_t)out,ba[i]+4,internal_branch(regs[t].is32,ba[i]+4)); emit_jmp(0); ccadj[t]=cc; } static void ujump_assemble(int i,struct regstat *i_regs) { #ifdef REG_PREFETCH signed char *i_regmap=i_regs->regmap; #endif if(i==(ba[i]-start)>>2) assem_debug("idle loop"); address_generation(i+1,i_regs,regs[i].regmap_entry); if((rt1[i]==31)&&(rt1[i+1]==31||rs1[i+1]==31||rs2[i+1]==31)) { signed char rt=get_reg(branch_regs[i].regmap,31); assert(get_reg(i_regs->regmap,31)==rt); emit_movimm(start+i*4+8,rt); // PC into link register } #ifdef REG_PREFETCH int temp=get_reg(branch_regs[i].regmap,PTEMP); if(rt1[i]==31&&temp>=0) { int return_address=start+i*4+8; if(get_reg(branch_regs[i].regmap,31)>0) if(i_regmap[temp]==PTEMP) emit_movimm((intptr_t)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif ds_assemble(i+1,i_regs); uint64_t bc_unneeded=branch_regs[i].u; uint64_t bc_unneeded_upper=branch_regs[i].uu; bc_unneeded|=1|(1LL<=0); return_address=start+i*4+8; if(rt>=0) { #ifdef USE_MINI_HT if(internal_branch(branch_regs[i].is32,return_address)) { int temp=-1; //x86 doesn't need a temp reg #ifdef HOST_TEMPREG if(temp<0) temp=HOST_TEMPREG; #endif do_miniht_insert(return_address,rt,temp); } else #endif { #ifdef REG_PREFETCH if(temp>=0) { if(i_regmap[temp]!=PTEMP) emit_movimm((intptr_t)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif emit_movimm(return_address,rt); // PC into link register #ifdef IMM_PREFETCH emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); #endif } } } int cc,adj; cc=get_reg(branch_regs[i].regmap,CCREG); assert(cc==HOST_CCREG); store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); #ifdef REG_PREFETCH if(rt1[i]==31&&temp>=0) emit_prefetchreg(temp); #endif do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); if(i!=(ba[i]-start)>>2 || source[i+1]!=0) { if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(internal_branch(branch_regs[i].is32,ba[i])) assem_debug("branch: internal"); else assem_debug("branch: external"); if(internal_branch(branch_regs[i].is32,ba[i])&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],internal_branch(branch_regs[i].is32,ba[i])); emit_jmp(0); } } } static void rjump_assemble(int i,struct regstat *i_regs) { #ifdef REG_PREFETCH signed char *i_regmap=i_regs->regmap; #endif int temp; int rs,cc; rs=get_reg(branch_regs[i].regmap,rs1[i]); assert(rs>=0); if((rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])&&(rs1[i]!=0)) { // Delay slot abuse, make a copy of the branch address register temp=get_reg(branch_regs[i].regmap,RTEMP); assert(temp>=0); assert(regs[i].regmap[temp]==RTEMP); emit_mov(rs,temp); rs=temp; } address_generation(i+1,i_regs,regs[i].regmap_entry); #ifdef REG_PREFETCH if(rt1[i]==31) { if((temp=get_reg(branch_regs[i].regmap,PTEMP))>=0) { int return_address=start+i*4+8; if(i_regmap[temp]==PTEMP) emit_movimm((intptr_t)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } } #endif #ifdef USE_MINI_HT if(rs1[i]==31) { int rh=get_reg(regs[i].regmap,RHASH); if(rh>=0) do_preload_rhash(rh); } #endif ds_assemble(i+1,i_regs); uint64_t bc_unneeded=branch_regs[i].u; uint64_t bc_unneeded_upper=branch_regs[i].uu; bc_unneeded|=1|(1LL<=0); return_address=start+i*4+8; #ifdef REG_PREFETCH if(temp>=0) { if(i_regmap[temp]!=PTEMP) emit_movimm((intptr_t)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif emit_movimm(return_address,rt); // PC into link register #ifdef IMM_PREFETCH emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); #endif } cc=get_reg(branch_regs[i].regmap,CCREG); assert(cc==HOST_CCREG); #ifdef USE_MINI_HT int rh=get_reg(branch_regs[i].regmap,RHASH); int ht=get_reg(branch_regs[i].regmap,RHTBL); if(rs1[i]==31) { if(regs[i].regmap[rh]!=RHASH) do_preload_rhash(rh); do_preload_rhtbl(ht); do_rhash(rs,rh); } #endif store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,-1); #ifdef DESTRUCTIVE_WRITEBACK if((branch_regs[i].dirty>>rs)&(branch_regs[i].is32>>rs1[i])&1) { if(rs1[i]!=rt1[i+1]&&rs1[i]!=rt2[i+1]) { emit_loadreg(rs1[i],rs); } } #endif #ifdef REG_PREFETCH if(rt1[i]==31&&temp>=0) emit_prefetchreg(temp); #endif #ifdef USE_MINI_HT if(rs1[i]==31) { do_miniht_load(ht,rh); } #endif //do_cc(i,branch_regs[i].regmap,&adj,-1,TAKEN); //if(adj) emit_addimm(cc,2*(ccadj[i]+2-adj),cc); // ??? - Shouldn't happen //assert(adj==0); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); add_stub(CC_STUB,(intptr_t)out,jump_vaddr_reg[rs],0,i,-1,TAKEN,0); emit_jns(0); //load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,-1); #ifdef USE_MINI_HT if(rs1[i]==31) { do_miniht_jump(rs,rh,ht); } else #endif { #if NEW_DYNAREC==NEW_DYNAREC_ARM64 if(rs==18) { // x18 is used for trampoline jumps, move it to another register (x0) emit_mov(rs,0); rs=0; } #endif emit_jmp(jump_vaddr_reg[rs]); } #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(rt1[i]!=31&&iregmap; int cc; int match; match=match_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); assem_debug("match=%d",match); int s1h,s1l,s2h,s2l; int prev_cop1_usable=cop1_usable; int unconditional=0,nop=0; int only32=0; int invert=0; int branch_internal=internal_branch(branch_regs[i].is32,ba[i]); if(i==(ba[i]-start)>>2) assem_debug("idle loop"); if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>2) invert=1; #endif if(ooo[i]) { s1l=get_reg(branch_regs[i].regmap,rs1[i]); s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); s2l=get_reg(branch_regs[i].regmap,rs2[i]); s2h=get_reg(branch_regs[i].regmap,rs2[i]|64); } else { s1l=get_reg(i_regmap,rs1[i]); s1h=get_reg(i_regmap,rs1[i]|64); s2l=get_reg(i_regmap,rs2[i]); s2h=get_reg(i_regmap,rs2[i]|64); } if(rs1[i]==0&&rs2[i]==0) { if(opcode[i]&1) nop=1; else unconditional=1; //assert(opcode[i]!=5); //assert(opcode[i]!=7); //assert(opcode[i]!=0x15); //assert(opcode[i]!=0x17); } else if(rs1[i]==0) { s1l=s2l;s1h=s2h; s2l=s2h=-1; only32=(regs[i].was32>>rs2[i])&1; } else if(rs2[i]==0) { s2l=s2h=-1; only32=(regs[i].was32>>rs1[i])&1; } else { only32=(regs[i].was32>>rs1[i])&(regs[i].was32>>rs2[i])&1; } if(ooo[i]) { // Out of order execution (delay slot first) //DebugMessage(M64MSG_VERBOSE, "OOOE"); address_generation(i+1,i_regs,regs[i].regmap_entry); ds_assemble(i+1,i_regs); int adj; uint64_t bc_unneeded=branch_regs[i].u; uint64_t bc_unneeded_upper=branch_regs[i].uu; bc_unneeded&=~((1LL<>2 || source[i+1]!=0) { if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(((uintptr_t)out)&7) emit_addnop(0); #endif } } else if(nop) { emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,NOTTAKEN,0); } else { intptr_t taken=0,nottaken=0,nottaken1=0; do_cc(i,branch_regs[i].regmap,&adj,-1,0,invert); if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); if(!only32) { assert(s1h>=0); if(opcode[i]==4) // BEQ { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); nottaken1=(intptr_t)out; emit_jne(1); } if(opcode[i]==5) // BNE { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); if(invert) taken=(intptr_t)out; else add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jne(0); } if(opcode[i]==6) // BLEZ { emit_test(s1h,s1h); if(invert) taken=(intptr_t)out; else add_to_linker((intptr_t)out,ba[i],branch_internal); emit_js(0); nottaken1=(intptr_t)out; emit_jne(1); } if(opcode[i]==7) // BGTZ { emit_test(s1h,s1h); nottaken1=(intptr_t)out; emit_js(1); if(invert) taken=(intptr_t)out; else add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jne(0); } } // if(!only32) assert(s1l>=0); if(opcode[i]==4) // BEQ { if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); if(invert){ nottaken=(intptr_t)out; emit_jne(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jeq(0); } } if(opcode[i]==5) // BNE { if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); if(invert){ nottaken=(intptr_t)out; emit_jeq(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jne(0); } } if(opcode[i]==6) // BLEZ { emit_cmpimm(s1l,1); if(invert){ nottaken=(intptr_t)out; if(only32) emit_jge(1); else emit_jae(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); if(only32) emit_jl(0); else emit_jb(0); } } if(opcode[i]==7) // BGTZ { emit_cmpimm(s1l,1); if(invert){ nottaken=(intptr_t)out; if(only32) emit_jl(1); else emit_jb(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); if(only32) emit_jge(0); else emit_jae(0); } } if(invert) { if(taken) set_jump_target(taken,(intptr_t)out); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(match&&(!branch_internal||!is_ds[(ba[i]-start)>>2])) { if(adj) { emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); add_to_linker((intptr_t)out,ba[i],branch_internal); }else{ emit_addnop(13); add_to_linker((intptr_t)out,ba[i],branch_internal*2); } emit_jmp(0); }else #endif { if(adj) emit_addimm(cc,-(int)CLOCK_DIVIDER*adj,cc); store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } } set_jump_target(nottaken,(intptr_t)out); } if(nottaken1) set_jump_target(nottaken1,(intptr_t)out); if(adj) { if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); } } // (!unconditional) } // if(ooo) else { // In-order execution (branch first) //if(likely[i]) DebugMessage(M64MSG_VERBOSE, "IOL"); //else //DebugMessage(M64MSG_VERBOSE, "IOE"); intptr_t taken=0,nottaken=0,nottaken1=0; if(!unconditional&&!nop) { if(!only32) { assert(s1h>=0); if((opcode[i]&0x2f)==4) // BEQ { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); nottaken1=(intptr_t)out; emit_jne(2); } if((opcode[i]&0x2f)==5) // BNE { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); taken=(intptr_t)out; emit_jne(1); } if((opcode[i]&0x2f)==6) // BLEZ { emit_test(s1h,s1h); taken=(intptr_t)out; emit_js(1); nottaken1=(intptr_t)out; emit_jne(2); } if((opcode[i]&0x2f)==7) // BGTZ { emit_test(s1h,s1h); nottaken1=(intptr_t)out; emit_js(2); taken=(intptr_t)out; emit_jne(1); } } // if(!only32) assert(s1l>=0); if((opcode[i]&0x2f)==4) // BEQ { if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_jne(2); } if((opcode[i]&0x2f)==5) // BNE { if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_jeq(2); } if((opcode[i]&0x2f)==6) // BLEZ { emit_cmpimm(s1l,1); nottaken=(intptr_t)out; if(only32) emit_jge(2); else emit_jae(2); } if((opcode[i]&0x2f)==7) // BGTZ { emit_cmpimm(s1l,1); nottaken=(intptr_t)out; if(only32) emit_jl(2); else emit_jb(2); } } // if(!unconditional) int adj; uint64_t ds_unneeded=branch_regs[i].u; uint64_t ds_unneeded_upper=branch_regs[i].uu; ds_unneeded&=~((1LL<>rt1[i+1])&1) ds_unneeded_upper&=~((1LL<>2 || source[i+1]!=0) { assem_debug("cycle count (adj)"); if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } } } // branch not taken cop1_usable=prev_cop1_usable; if(!unconditional) { if(nottaken1) set_jump_target(nottaken1,(intptr_t)out); set_jump_target(nottaken,(intptr_t)out); assem_debug("2:"); if(!likely[i]) { wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32, ds_unneeded,ds_unneeded_upper); load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i+1],rs2[i+1]); address_generation(i+1,&branch_regs[i],0); load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG); ds_assemble(i+1,&branch_regs[i]); } cc=get_reg(branch_regs[i].regmap,CCREG); if(cc==-1&&!likely[i]) { // Cycle count isn't in a register, temporarily load it then write it out emit_loadreg(CCREG,HOST_CCREG); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,NOTTAKEN,0); emit_storereg(CCREG,HOST_CCREG); } else{ cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); } } } } static void sjump_assemble(int i,struct regstat *i_regs) { signed char *i_regmap=i_regs->regmap; int cc; int match; match=match_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); assem_debug("smatch=%d",match); int s1h,s1l; int prev_cop1_usable=cop1_usable; int unconditional=0,nevertaken=0; int only32=0; int invert=0; int branch_internal=internal_branch(branch_regs[i].is32,ba[i]); if(i==(ba[i]-start)>>2) assem_debug("idle loop"); if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>2) invert=1; #endif //if(opcode2[i]>=0x10) return; // FIXME (BxxZAL) assert(opcode2[i]<0x10||rs1[i]==0); // FIXME (BxxZAL) if(ooo[i]) { s1l=get_reg(branch_regs[i].regmap,rs1[i]); s1h=get_reg(branch_regs[i].regmap,rs1[i]|64); } else { s1l=get_reg(i_regmap,rs1[i]); s1h=get_reg(i_regmap,rs1[i]|64); } if(rs1[i]==0) { if(opcode2[i]&1) unconditional=1; else nevertaken=1; // These are never taken (r0 is never less than zero) //assert(opcode2[i]!=0); //assert(opcode2[i]!=2); //assert(opcode2[i]!=0x10); //assert(opcode2[i]!=0x12); } else { only32=(regs[i].was32>>rs1[i])&1; } if(ooo[i]) { // Out of order execution (delay slot first) //DebugMessage(M64MSG_VERBOSE, "OOOE"); address_generation(i+1,i_regs,regs[i].regmap_entry); ds_assemble(i+1,i_regs); int adj; uint64_t bc_unneeded=branch_regs[i].u; uint64_t bc_unneeded_upper=branch_regs[i].uu; bc_unneeded&=~((1LL<=0) { // Save the PC even if the branch is not taken return_address=start+i*4+8; emit_movimm(return_address,rt); // PC into link register #ifdef IMM_PREFETCH if(!nevertaken) emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); #endif } } cc=get_reg(branch_regs[i].regmap,CCREG); assert(cc==HOST_CCREG); if(unconditional) store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); //do_cc(i,branch_regs[i].regmap,&adj,unconditional?ba[i]:-1,unconditional); assem_debug("cycle count (adj)"); if(unconditional) { do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); if(i!=(ba[i]-start)>>2 || source[i+1]!=0) { if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(((uintptr_t)out)&7) emit_addnop(0); #endif } } else if(nevertaken) { emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,NOTTAKEN,0); } else { intptr_t nottaken=0; do_cc(i,branch_regs[i].regmap,&adj,-1,0,invert); if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); if(!only32) { assert(s1h>=0); if(opcode2[i]==0) // BLTZ { emit_test(s1h,s1h); if(invert){ nottaken=(intptr_t)out; emit_jns(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_js(0); } } if(opcode2[i]==1) // BGEZ { emit_test(s1h,s1h); if(invert){ nottaken=(intptr_t)out; emit_js(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jns(0); } } } // if(!only32) else { assert(s1l>=0); if(opcode2[i]==0) // BLTZ { emit_test(s1l,s1l); if(invert){ nottaken=(intptr_t)out; emit_jns(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_js(0); } } if(opcode2[i]==1) // BGEZ { emit_test(s1l,s1l); if(invert){ nottaken=(intptr_t)out; emit_js(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jns(0); } } } // if(!only32) if(invert) { #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(match&&(!branch_internal||!is_ds[(ba[i]-start)>>2])) { if(adj) { emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); add_to_linker((intptr_t)out,ba[i],branch_internal); }else{ emit_addnop(13); add_to_linker((intptr_t)out,ba[i],branch_internal*2); } emit_jmp(0); }else #endif { if(adj) emit_addimm(cc,-(int)CLOCK_DIVIDER*adj,cc); store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } } set_jump_target(nottaken,(intptr_t)out); } if(adj) { if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); } } // (!unconditional) } // if(ooo) else { // In-order execution (branch first) //DebugMessage(M64MSG_VERBOSE, "IOE"); intptr_t nottaken=0; if(!unconditional) { if(!only32) { assert(s1h>=0); if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL { emit_test(s1h,s1h); nottaken=(intptr_t)out; emit_jns(1); } if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL { emit_test(s1h,s1h); nottaken=(intptr_t)out; emit_js(1); } } // if(!only32) else { assert(s1l>=0); if((opcode2[i]&0x1d)==0) // BLTZ/BLTZL { emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_jns(1); } if((opcode2[i]&0x1d)==1) // BGEZ/BGEZL { emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_js(1); } } } // if(!unconditional) int adj; uint64_t ds_unneeded=branch_regs[i].u; uint64_t ds_unneeded_upper=branch_regs[i].uu; ds_unneeded&=~((1LL<>rt1[i+1])&1) ds_unneeded_upper&=~((1LL<>2 || source[i+1]!=0) { assem_debug("cycle count (adj)"); if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } } } // branch not taken cop1_usable=prev_cop1_usable; if(!unconditional) { set_jump_target(nottaken,(intptr_t)out); assem_debug("1:"); if(!likely[i]) { wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32, ds_unneeded,ds_unneeded_upper); load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i+1],rs2[i+1]); address_generation(i+1,&branch_regs[i],0); load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG); ds_assemble(i+1,&branch_regs[i]); } cc=get_reg(branch_regs[i].regmap,CCREG); if(cc==-1&&!likely[i]) { // Cycle count isn't in a register, temporarily load it then write it out emit_loadreg(CCREG,HOST_CCREG); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,NOTTAKEN,0); emit_storereg(CCREG,HOST_CCREG); } else{ cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); } } } } static void fjump_assemble(int i,struct regstat *i_regs) { signed char *i_regmap=i_regs->regmap; int cc; int match; match=match_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); assem_debug("fmatch=%d",match); int fs,cs; intptr_t eaddr; int invert=0; int branch_internal=internal_branch(branch_regs[i].is32,ba[i]); if(i==(ba[i]-start)>>2) assem_debug("idle loop"); if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>2) invert=1; #endif if(ooo[i]) { fs=get_reg(branch_regs[i].regmap,FSREG); address_generation(i+1,i_regs,regs[i].regmap_entry); // Is this okay? } else { fs=get_reg(i_regmap,FSREG); } // Check cop1 unusable if(!cop1_usable) { cs=get_reg(i_regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); eaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,eaddr,(intptr_t)out,i,cs,(intptr_t)i_regs,0,0); cop1_usable=1; } if(ooo[i]) { // Out of order execution (delay slot first) //DebugMessage(M64MSG_VERBOSE, "OOOE"); ds_assemble(i+1,i_regs); int adj; uint64_t bc_unneeded=branch_regs[i].u; uint64_t bc_unneeded_upper=branch_regs[i].uu; bc_unneeded&=~((1LL<=0); emit_testimm(fs,0x800000); if(source[i]&0x10000) // BC1T { if(invert){ nottaken=(intptr_t)out; emit_jeq(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jne(0); } } else // BC1F if(invert){ nottaken=(intptr_t)out; emit_jne(1); }else{ add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jeq(0); } { } } // if(!only32) if(invert) { if(adj) emit_addimm(cc,-(int)CLOCK_DIVIDER*adj,cc); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK else if(match) emit_addnop(13); #endif store_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } set_jump_target(nottaken,(intptr_t)out); } if(adj) { if(!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); } } // (!unconditional) } // if(ooo) else { // In-order execution (branch first) //DebugMessage(M64MSG_VERBOSE, "IOE"); intptr_t nottaken=0; if(1) { if(1) { assert(fs>=0); emit_testimm(fs,0x800000); if(source[i]&0x10000) // BC1T { nottaken=(intptr_t)out; emit_jeq(1); } else // BC1F { nottaken=(intptr_t)out; emit_jne(1); } } } // if(!unconditional) int adj; uint64_t ds_unneeded=branch_regs[i].u; uint64_t ds_unneeded_upper=branch_regs[i].uu; ds_unneeded&=~((1LL<>rt1[i+1])&1) ds_unneeded_upper&=~((1LL<>2 || source[i+1]!=0) { assem_debug("cycle count (adj)"); if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].is32,branch_regs[i].dirty,ba[i]); if(branch_internal) assem_debug("branch: internal"); else assem_debug("branch: external"); if(branch_internal&&is_ds[(ba[i]-start)>>2]) { ds_assemble_entry(i); } else { add_to_linker((intptr_t)out,ba[i],branch_internal); emit_jmp(0); } } // branch not taken if(1) { // <- FIXME (don't need this) set_jump_target(nottaken,(intptr_t)out); assem_debug("1:"); if(!likely[i]) { wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,regs[i].is32, ds_unneeded,ds_unneeded_upper); load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,rs1[i+1],rs2[i+1]); address_generation(i+1,&branch_regs[i],0); load_regs(regs[i].regmap,branch_regs[i].regmap,regs[i].was32,CCREG,CCREG); ds_assemble(i+1,&branch_regs[i]); } cc=get_reg(branch_regs[i].regmap,CCREG); if(cc==-1&&!likely[i]) { // Cycle count isn't in a register, temporarily load it then write it out emit_loadreg(CCREG,HOST_CCREG); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,NOTTAKEN,0); emit_storereg(CCREG,HOST_CCREG); } else{ cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); intptr_t jaddr=(intptr_t)out; emit_jns(0); add_stub(CC_STUB,jaddr,(intptr_t)out,0,i,start+i*4+8,likely[i]?NULLDS:NOTTAKEN,0); } } } } static void pagespan_assemble(int i,struct regstat *i_regs) { int s1l=get_reg(i_regs->regmap,rs1[i]); int s1h=get_reg(i_regs->regmap,rs1[i]|64); int s2l=get_reg(i_regs->regmap,rs2[i]); int s2h=get_reg(i_regs->regmap,rs2[i]|64); intptr_t taken=0; intptr_t nottaken=0; intptr_t nottaken1=0; int unconditional=0; assert(!(i==(ba[i]-start)>>2 && source[i+1]==0)); //FIXME: Idle loop if(rs1[i]==0) { s1l=s2l;s1h=s2h; s2l=s2h=-1; } else if(rs2[i]==0) { s2l=s2h=-1; } if((i_regs->is32>>rs1[i])&(i_regs->is32>>rs2[i])&1) { s1h=s2h=-1; } int hr=0; int addr,alt,ntaddr; if(i_regs->regmap[HOST_BTREG]<0) {addr=HOST_BTREG;} else { while(hrregmap[hr]&63)!=rs1[i] && (i_regs->regmap[hr]&63)!=rs2[i] ) { addr=hr++;break; } hr++; } } while(hrregmap[hr]&63)!=rs1[i] && (i_regs->regmap[hr]&63)!=rs2[i] ) { alt=hr++;break; } hr++; } if((opcode[i]&0x2E)==6) // BLEZ/BGTZ needs another register { while(hrregmap[hr]&63)!=rs1[i] && (i_regs->regmap[hr]&63)!=rs2[i] ) { ntaddr=hr;break; } hr++; } } assert(hrregmap,31); emit_movimm(start+i*4+8,rt); unconditional=1; } if(opcode[i]==0&&(opcode2[i]&0x3E)==8) // JR/JALR { emit_mov(s1l,addr); if(opcode2[i]==9) // JALR { int rt=get_reg(i_regs->regmap,rt1[i]); emit_movimm(start+i*4+8,rt); } } if((opcode[i]&0x3f)==4) // BEQ { if(rs1[i]==rs2[i]) { unconditional=1; } else #ifdef HAVE_CMOV_IMM if(s1h<0) { if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmov2imm_e_ne_compact(ba[i],start+i*4+8,addr); } else #endif { assert(s1l>=0); emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); if(s1h>=0) { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); emit_cmovne_reg(alt,addr); } if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmovne_reg(alt,addr); } } if((opcode[i]&0x3f)==5) // BNE { #ifdef HAVE_CMOV_IMM if(s1h<0) { if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmov2imm_e_ne_compact(start+i*4+8,ba[i],addr); } else #endif { assert(s1l>=0); emit_mov2imm_compact(start+i*4+8,addr,ba[i],alt); if(s1h>=0) { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); emit_cmovne_reg(alt,addr); } if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); emit_cmovne_reg(alt,addr); } } if((opcode[i]&0x3f)==0x14) // BEQL { if(s1h>=0) { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); nottaken1=(intptr_t)out; emit_jne(0); } if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_jne(0); } if((opcode[i]&0x3f)==0x15) // BNEL { if(s1h>=0) { if(s2h>=0) emit_cmp(s1h,s2h); else emit_test(s1h,s1h); taken=(intptr_t)out; emit_jne(0); } if(s2l>=0) emit_cmp(s1l,s2l); else emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_jeq(0); if(taken) set_jump_target(taken,(intptr_t)out); } if((opcode[i]&0x3f)==6) // BLEZ { emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); emit_cmpimm(s1l,1); if(s1h>=0) emit_mov(addr,ntaddr); emit_cmovl_reg(alt,addr); if(s1h>=0) { emit_test(s1h,s1h); emit_cmovne_reg(ntaddr,addr); emit_cmovs_reg(alt,addr); } } if((opcode[i]&0x3f)==7) // BGTZ { emit_mov2imm_compact(ba[i],addr,start+i*4+8,ntaddr); emit_cmpimm(s1l,1); if(s1h>=0) emit_mov(addr,alt); emit_cmovl_reg(ntaddr,addr); if(s1h>=0) { emit_test(s1h,s1h); emit_cmovne_reg(alt,addr); emit_cmovs_reg(ntaddr,addr); } } if((opcode[i]&0x3f)==0x16) // BLEZL { if(s1h>=0) { emit_test(s1h,s1h); taken=(intptr_t)out; emit_js(0); nottaken1=(intptr_t)out; emit_jne(0); } emit_cmpimm(s1l,1); nottaken=(intptr_t)out; if(s1h>=0) emit_jae(0); else emit_jge(0); if(taken) set_jump_target(taken,(intptr_t)out); } if((opcode[i]&0x3f)==0x17) // BGTZL { if(s1h>=0) { emit_test(s1h,s1h); nottaken1=(intptr_t)out; emit_js(0); taken=(intptr_t)out; emit_jne(0); } emit_cmpimm(s1l,1); nottaken=(intptr_t)out; if(s1h>=0) emit_jb(0); else emit_jl(0); if(taken) set_jump_target(taken,(intptr_t)out); } if((opcode[i]==1)&&(opcode2[i]==0)) // BLTZ { emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); if(s1h>=0) emit_test(s1h,s1h); else emit_test(s1l,s1l); emit_cmovs_reg(alt,addr); } if((opcode[i]==1)&&(opcode2[i]==1)) // BGEZ { emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); if(s1h>=0) emit_test(s1h,s1h); else emit_test(s1l,s1l); emit_cmovs_reg(alt,addr); } if((opcode[i]==1)&&(opcode2[i]==2)) // BLTZL { if(s1h>=0) emit_test(s1h,s1h); else emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_jns(0); } if((opcode[i]==1)&&(opcode2[i]==3)) // BGEZL { if(s1h>=0) emit_test(s1h,s1h); else emit_test(s1l,s1l); nottaken=(intptr_t)out; emit_js(0); } if(opcode[i]==0x11 && opcode2[i]==0x08 ) { // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,cs,(intptr_t)i_regs,0,0); cop1_usable=1; } if((source[i]&0x30000)==0) // BC1F { emit_mov2imm_compact(ba[i],addr,start+i*4+8,alt); emit_testimm(s1l,0x800000); emit_cmovne_reg(alt,addr); } if((source[i]&0x30000)==0x10000) // BC1T { emit_mov2imm_compact(ba[i],alt,start+i*4+8,addr); emit_testimm(s1l,0x800000); emit_cmovne_reg(alt,addr); } if((source[i]&0x30000)==0x20000) // BC1FL { emit_testimm(s1l,0x800000); nottaken=(intptr_t)out; emit_jne(0); } if((source[i]&0x30000)==0x30000) // BC1TL { emit_testimm(s1l,0x800000); nottaken=(intptr_t)out; emit_jeq(0); } } assert(i_regs->regmap[HOST_CCREG]==CCREG); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i]+1),HOST_CCREG); wb_dirtys(regs[i].regmap,regs[i].is32,regs[i].dirty); if(likely[i]||unconditional) { emit_movimm(ba[i],HOST_BTREG); } else if(addr!=HOST_BTREG) { emit_mov(addr,HOST_BTREG); } void *branch_addr=out; emit_jmp(0); int target_addr=start+i*4+5; void *stub=out; void *compiled_target_addr=check_addr(target_addr); emit_extjump_ds((intptr_t)branch_addr,target_addr); #ifndef DISABLE_BLOCK_LINKING if(compiled_target_addr) { set_jump_target((intptr_t)branch_addr,(intptr_t)compiled_target_addr); add_link(target_addr,stub); } else #endif set_jump_target((intptr_t)branch_addr,(intptr_t)stub); if(likely[i]) { // Not-taken path if(nottaken1) set_jump_target((intptr_t)nottaken1,(intptr_t)out); set_jump_target((intptr_t)nottaken,(intptr_t)out); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i]+2),HOST_CCREG); wb_dirtys(regs[i].regmap,regs[i].is32,regs[i].dirty); emit_test(HOST_CCREG,HOST_CCREG); intptr_t jaddr=(intptr_t)out; emit_js(0); emit_movimm(start+i*4+8,0); emit_writeword(0,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pcaddr); emit_call((intptr_t)cc_interrupt); set_jump_target((intptr_t)jaddr,(intptr_t)out); void *branch_addr=out; emit_jmp(0); int target_addr=start+i*4+8; void *stub=out; void *compiled_target_addr=check_addr(target_addr); emit_extjump_ds((intptr_t)branch_addr,target_addr); #ifndef DISABLE_BLOCK_LINKING if(compiled_target_addr) { set_jump_target((intptr_t)branch_addr,(intptr_t)compiled_target_addr); add_link(target_addr,stub); } else #endif set_jump_target((intptr_t)branch_addr,(intptr_t)stub); } } // Assemble the delay slot for the above static void pagespan_ds(void) { assem_debug("initial delay slot:"); u_int vaddr=start+1; u_int page=(0x80000000^vaddr)>>12; u_int vpage=page; if(page>262143&&g_dev.r4300.cp0.tlb.LUT_r[vaddr>>12]) page=(g_dev.r4300.cp0.tlb.LUT_r[page^0x80000]^0x80000000)>>12; if(page>2048) page=2048+(page&2047); if(vpage>262143&&g_dev.r4300.cp0.tlb.LUT_r[vaddr>>12]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead if(vpage>2048) vpage=2048+(vpage&2047); struct ll_entry *head=ll_add(jump_dirty+vpage,vaddr,(void *)out,NULL,start,copy,slen*4); dirty_entry_count++; do_dirty_stub_ds(head); head->clean_addr=(void *)out; (void)ll_add(jump_in+page,vaddr,(void *)out,(void *)out,start,copy,slen*4); assert(regs[0].regmap_entry[HOST_CCREG]==CCREG); emit_addimm(HOST_CCREG,CLOCK_DIVIDER,HOST_CCREG); if(regs[0].regmap[HOST_CCREG]!=CCREG) wb_register(CCREG,regs[0].regmap_entry,regs[0].wasdirty,regs[0].was32); if(regs[0].regmap[HOST_BTREG]!=BTREG) emit_writeword(HOST_BTREG,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.branch_target); load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,rs1[0],rs2[0]); address_generation(0,®s[0],regs[0].regmap_entry); if(itype[0]==LOAD||itype[0]==LOADLR||itype[0]==STORE||itype[0]==STORELR||itype[0]==C1LS) load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,MMREG,ROREG); if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39) load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,INVCP,INVCP); cop1_usable=0; is_delayslot=0; switch(itype[0]) { case ALU: alu_assemble(0,®s[0]);break; case IMM16: imm16_assemble(0,®s[0]);break; case SHIFT: shift_assemble(0,®s[0]);break; case SHIFTIMM: shiftimm_assemble(0,®s[0]);break; case LOAD: load_assemble(0,®s[0]);break; case LOADLR: loadlr_assemble(0,®s[0]);break; case STORE: store_assemble(0,®s[0]);break; case STORELR: storelr_assemble(0,®s[0]);break; case COP0: cop0_assemble(0,®s[0]);break; case COP1: cop1_assemble(0,®s[0]);break; case C1LS: c1ls_assemble(0,®s[0]);break; case FCONV: fconv_assemble(0,®s[0]);break; case FLOAT: float_assemble(0,®s[0]);break; case FCOMP: fcomp_assemble(0,®s[0]);break; case MULTDIV: multdiv_assemble(0,®s[0]);break; case MOV: mov_assemble(0,®s[0]);break; case SYSCALL: case SPAN: case UJUMP: case RJUMP: case CJUMP: case SJUMP: case FJUMP: DebugMessage(M64MSG_VERBOSE, "Jump in the delay slot. This is probably a bug."); } int btaddr=get_reg(regs[0].regmap,BTREG); if(btaddr<0) { btaddr=get_reg(regs[0].regmap,-1); emit_readword((intptr_t)&g_dev.r4300.new_dynarec_hot_state.branch_target,btaddr); } assert(btaddr!=HOST_CCREG); if(regs[0].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_test(HOST_CCREG,HOST_CCREG); intptr_t jaddr=(intptr_t)out; emit_js(0); wb_dirtys(regs[0].regmap,regs[0].is32,regs[0].dirty); emit_writeword(btaddr,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pcaddr); emit_call((intptr_t)cc_interrupt); load_all_regs(regs[0].regmap); set_jump_target((intptr_t)jaddr,(intptr_t)out); #ifdef HOST_IMM8 emit_movimm(start+4,HOST_TEMPREG); emit_cmp(btaddr,HOST_TEMPREG); #else emit_cmpimm(btaddr,start+4); #endif intptr_t branch=(intptr_t)out; emit_jeq(0); store_regs_bt(regs[0].regmap,regs[0].is32,regs[0].dirty,-1); #if NEW_DYNAREC==NEW_DYNAREC_ARM64 if(btaddr==18) { // x18 is used for trampoline jumps, move it to another register (x0) emit_mov(btaddr,0); btaddr=0; } #endif emit_jmp(jump_vaddr_reg[btaddr]); set_jump_target(branch,(intptr_t)out); store_regs_bt(regs[0].regmap,regs[0].is32,regs[0].dirty,start+4); load_regs_bt(regs[0].regmap,regs[0].is32,regs[0].dirty,start+4); } /**** Recompiler ****/ void new_dynarec_init(void) { DebugMessage(M64MSG_INFO, "Init new dynarec"); #if defined(RECOMPILER_DEBUG) && !defined(RECOMP_DBG) recomp_dbg_init(); #endif #if !defined(RECOMP_DBG) #if NEW_DYNAREC == NEW_DYNAREC_ARM64 #define FIXED_CACHE_ADDR 1 // Put the dynarec cache at extra_memory address #define DYNAMIC_CACHE_ADDR 2 // Put the dynarec cache at random address #define DOUBLE_CACHE_ADDR 3 // Put the dynarec cache at random address with RW address != RX address // Default to fixed cache address #define CACHE_ADDR FIXED_CACHE_ADDR #if CACHE_ADDR==DOUBLE_CACHE_ADDR #include #include #include int fd = shm_open("/new_dynarec", O_RDWR | O_CREAT | O_EXCL, 0600); assert(fd!=-1); shm_unlink("/new_dynarec"); ftruncate(fd, 1<>2; for(n=526336;n<1048576;n++) // 0x80800000 .. 0xFFFFFFFF g_dev.r4300.new_dynarec_hot_state.memory_map[n]=(uintptr_t)-1; tlb_speed_hacks(); arch_init(); } void new_dynarec_cleanup(void) { #if defined(RECOMPILER_DEBUG) && !defined(RECOMP_DBG) recomp_dbg_cleanup(); #endif int n; for(n=0;n<4096;n++) ll_clear(jump_in+n); for(n=0;n<4096;n++) ll_clear(jump_out+n); for(n=0;n<4096;n++) ll_clear(jump_dirty+n); assert(copy_size==0); #if !defined(RECOMP_DBG) #if defined(WIN32) VirtualFree(base_addr, 0, MEM_RELEASE); #elif NEW_DYNAREC == NEW_DYNAREC_ARM64 && CACHE_ADDR!=FIXED_CACHE_ADDR if (munmap (base_addr_rx, 1< %x", (int)addr, (intptr_t)out); #if COUNT_NOTCOMPILEDS notcompiledCount++; DebugMessage(M64MSG_VERBOSE, "notcompiledCount=%i", notcompiledCount ); #endif start = (u_int)addr&~3; //assert(((u_int)addr&1)==0); if ((int)addr >= 0xa0000000 && (int)addr < 0xa07fffff) { source = (u_int *)((uintptr_t)g_dev.rdram.dram+start-0xa0000000); pagelimit = 0xa07fffff; } else if ((int)addr >= 0xa4000000 && (int)addr < 0xa4001000) { source = (u_int *)((uintptr_t)g_dev.sp.mem+start-0xa4000000); pagelimit = 0xa4001000; } else if ((int)addr >= 0x80000000 && (int)addr < 0x80800000) { source = (u_int *)((uintptr_t)g_dev.rdram.dram+start-(uintptr_t)0x80000000); pagelimit = 0x80800000; } else if ((signed int)addr >= (signed int)0xC0000000) { //DebugMessage(M64MSG_VERBOSE, "addr=%x mm=%x",(u_int)addr,(g_dev.r4300.new_dynarec_hot_state.memory_map[start>>12]<<2)); //if(g_dev.r4300.cp0.tlb.LUT_r[start>>12]) //source = (u_int *)(((intptr_t)g_dev.rdram.dram)+(g_dev.r4300.cp0.tlb.LUT_r[start>>12]&0xFFFFF000)+(((int)addr)&0xFFF)-(intptr_t)0x80000000); if((intptr_t)g_dev.r4300.new_dynarec_hot_state.memory_map[start>>12]>=0) { source = (u_int *)((uintptr_t)(start+(uintptr_t)(g_dev.r4300.new_dynarec_hot_state.memory_map[start>>12]<<2))); pagelimit=(start+4096)&0xFFFFF000; intptr_t map=g_dev.r4300.new_dynarec_hot_state.memory_map[start>>12]; int i; for(i=0;i<5;i++) { //DebugMessage(M64MSG_VERBOSE, "start: %x next: %x",map,g_dev.r4300.new_dynarec_hot_state.memory_map[pagelimit>>12]); if((map&~WRITE_PROTECT)==(g_dev.r4300.new_dynarec_hot_state.memory_map[pagelimit>>12]&~WRITE_PROTECT)) pagelimit+=4096; } assem_debug("pagelimit=%x",pagelimit); assem_debug("mapping=%x (%x)",g_dev.r4300.new_dynarec_hot_state.memory_map[start>>12],(uintptr_t)(g_dev.r4300.new_dynarec_hot_state.memory_map[start>>12]<<2)+start); } else { assem_debug("Compile at unmapped memory address: %x ", (int)addr); //assem_debug("start: %x next: %x",g_dev.r4300.new_dynarec_hot_state.memory_map[start>>12],g_dev.r4300.new_dynarec_hot_state.memory_map[(start+4096)>>12]); return 1; // Caller will invoke exception handler } //DebugMessage(M64MSG_VERBOSE, "source= %x",(intptr_t)source); } else { //DebugMessage(M64MSG_VERBOSE, "Compile at bogus memory address: %x ", (int)addr); DebugMessage(M64MSG_ERROR, "Compile at bogus memory address: %x", (int)addr); exit(1); } /* Pass 1: disassemble */ /* Pass 2: register dependencies, branch targets */ /* Pass 3: register allocation */ /* Pass 4: branch dependencies */ /* Pass 5: pre-alloc */ /* Pass 6: optimize clean/dirty state */ /* Pass 7: flag 32-bit registers */ /* Pass 8: assembly */ /* Pass 9: linker */ /* Pass 10: garbage collection / free memory */ int i,j; int done=0; unsigned int type,op,op2; //DebugMessage(M64MSG_VERBOSE, "addr = %x source = %x %x", addr,source,source[0]); /* Pass 1 disassembly */ for(i=0;!done;i++) { bt[i]=0;likely[i]=0;ooo[i]=0;op2=0; minimum_free_regs[i]=0; opcode[i]=op=source[i]>>26; switch(op) { case 0x00: assem_strcpy(insn[i],"special"); type=NI; op2=source[i]&0x3f; switch(op2) { case 0x00: assem_strcpy(insn[i],"SLL"); type=SHIFTIMM; break; case 0x02: assem_strcpy(insn[i],"SRL"); type=SHIFTIMM; break; case 0x03: assem_strcpy(insn[i],"SRA"); type=SHIFTIMM; break; case 0x04: assem_strcpy(insn[i],"SLLV"); type=SHIFT; break; case 0x06: assem_strcpy(insn[i],"SRLV"); type=SHIFT; break; case 0x07: assem_strcpy(insn[i],"SRAV"); type=SHIFT; break; case 0x08: assem_strcpy(insn[i],"JR"); type=RJUMP; break; case 0x09: assem_strcpy(insn[i],"JALR"); type=RJUMP; break; case 0x0C: assem_strcpy(insn[i],"SYSCALL"); type=SYSCALL; break; case 0x0D: assem_strcpy(insn[i],"BREAK"); type=OTHER; break; case 0x0F: assem_strcpy(insn[i],"SYNC"); type=OTHER; break; case 0x10: assem_strcpy(insn[i],"MFHI"); type=MOV; break; case 0x11: assem_strcpy(insn[i],"MTHI"); type=MOV; break; case 0x12: assem_strcpy(insn[i],"MFLO"); type=MOV; break; case 0x13: assem_strcpy(insn[i],"MTLO"); type=MOV; break; case 0x14: assem_strcpy(insn[i],"DSLLV"); type=SHIFT; break; case 0x16: assem_strcpy(insn[i],"DSRLV"); type=SHIFT; break; case 0x17: assem_strcpy(insn[i],"DSRAV"); type=SHIFT; break; case 0x18: assem_strcpy(insn[i],"MULT"); type=MULTDIV; break; case 0x19: assem_strcpy(insn[i],"MULTU"); type=MULTDIV; break; case 0x1A: assem_strcpy(insn[i],"DIV"); type=MULTDIV; break; case 0x1B: assem_strcpy(insn[i],"DIVU"); type=MULTDIV; break; case 0x1C: assem_strcpy(insn[i],"DMULT"); type=MULTDIV; break; case 0x1D: assem_strcpy(insn[i],"DMULTU"); type=MULTDIV; break; case 0x1E: assem_strcpy(insn[i],"DDIV"); type=MULTDIV; break; case 0x1F: assem_strcpy(insn[i],"DDIVU"); type=MULTDIV; break; case 0x20: assem_strcpy(insn[i],"ADD"); type=ALU; break; case 0x21: assem_strcpy(insn[i],"ADDU"); type=ALU; break; case 0x22: assem_strcpy(insn[i],"SUB"); type=ALU; break; case 0x23: assem_strcpy(insn[i],"SUBU"); type=ALU; break; case 0x24: assem_strcpy(insn[i],"AND"); type=ALU; break; case 0x25: assem_strcpy(insn[i],"OR"); type=ALU; break; case 0x26: assem_strcpy(insn[i],"XOR"); type=ALU; break; case 0x27: assem_strcpy(insn[i],"NOR"); type=ALU; break; case 0x2A: assem_strcpy(insn[i],"SLT"); type=ALU; break; case 0x2B: assem_strcpy(insn[i],"SLTU"); type=ALU; break; case 0x2C: assem_strcpy(insn[i],"DADD"); type=ALU; break; case 0x2D: assem_strcpy(insn[i],"DADDU"); type=ALU; break; case 0x2E: assem_strcpy(insn[i],"DSUB"); type=ALU; break; case 0x2F: assem_strcpy(insn[i],"DSUBU"); type=ALU; break; case 0x30: assem_strcpy(insn[i],"TGE"); type=NI; break; case 0x31: assem_strcpy(insn[i],"TGEU"); type=NI; break; case 0x32: assem_strcpy(insn[i],"TLT"); type=NI; break; case 0x33: assem_strcpy(insn[i],"TLTU"); type=NI; break; case 0x34: assem_strcpy(insn[i],"TEQ"); type=NI; break; case 0x36: assem_strcpy(insn[i],"TNE"); type=NI; break; case 0x38: assem_strcpy(insn[i],"DSLL"); type=SHIFTIMM; break; case 0x3A: assem_strcpy(insn[i],"DSRL"); type=SHIFTIMM; break; case 0x3B: assem_strcpy(insn[i],"DSRA"); type=SHIFTIMM; break; case 0x3C: assem_strcpy(insn[i],"DSLL32"); type=SHIFTIMM; break; case 0x3E: assem_strcpy(insn[i],"DSRL32"); type=SHIFTIMM; break; case 0x3F: assem_strcpy(insn[i],"DSRA32"); type=SHIFTIMM; break; } break; case 0x01: assem_strcpy(insn[i],"regimm"); type=NI; op2=(source[i]>>16)&0x1f; switch(op2) { case 0x00: assem_strcpy(insn[i],"BLTZ"); type=SJUMP; break; case 0x01: assem_strcpy(insn[i],"BGEZ"); type=SJUMP; break; case 0x02: assem_strcpy(insn[i],"BLTZL"); type=SJUMP; break; case 0x03: assem_strcpy(insn[i],"BGEZL"); type=SJUMP; break; case 0x08: assem_strcpy(insn[i],"TGEI"); type=NI; break; case 0x09: assem_strcpy(insn[i],"TGEIU"); type=NI; break; case 0x0A: assem_strcpy(insn[i],"TLTI"); type=NI; break; case 0x0B: assem_strcpy(insn[i],"TLTIU"); type=NI; break; case 0x0C: assem_strcpy(insn[i],"TEQI"); type=NI; break; case 0x0E: assem_strcpy(insn[i],"TNEI"); type=NI; break; case 0x10: assem_strcpy(insn[i],"BLTZAL"); type=SJUMP; break; case 0x11: assem_strcpy(insn[i],"BGEZAL"); type=SJUMP; break; case 0x12: assem_strcpy(insn[i],"BLTZALL"); type=SJUMP; break; case 0x13: assem_strcpy(insn[i],"BGEZALL"); type=SJUMP; break; } break; case 0x02: assem_strcpy(insn[i],"J"); type=UJUMP; break; case 0x03: assem_strcpy(insn[i],"JAL"); type=UJUMP; break; case 0x04: assem_strcpy(insn[i],"BEQ"); type=CJUMP; break; case 0x05: assem_strcpy(insn[i],"BNE"); type=CJUMP; break; case 0x06: assem_strcpy(insn[i],"BLEZ"); type=CJUMP; break; case 0x07: assem_strcpy(insn[i],"BGTZ"); type=CJUMP; break; case 0x08: assem_strcpy(insn[i],"ADDI"); type=IMM16; break; case 0x09: assem_strcpy(insn[i],"ADDIU"); type=IMM16; break; case 0x0A: assem_strcpy(insn[i],"SLTI"); type=IMM16; break; case 0x0B: assem_strcpy(insn[i],"SLTIU"); type=IMM16; break; case 0x0C: assem_strcpy(insn[i],"ANDI"); type=IMM16; break; case 0x0D: assem_strcpy(insn[i],"ORI"); type=IMM16; break; case 0x0E: assem_strcpy(insn[i],"XORI"); type=IMM16; break; case 0x0F: assem_strcpy(insn[i],"LUI"); type=IMM16; break; case 0x10: assem_strcpy(insn[i],"cop0"); type=NI; op2=(source[i]>>21)&0x1f; switch(op2) { case 0x00: assem_strcpy(insn[i],"MFC0"); type=COP0; break; case 0x04: assem_strcpy(insn[i],"MTC0"); type=COP0; break; case 0x10: assem_strcpy(insn[i],"tlb"); type=NI; switch(source[i]&0x3f) { case 0x01: assem_strcpy(insn[i],"TLBR"); type=COP0; break; case 0x02: assem_strcpy(insn[i],"TLBWI"); type=COP0; break; case 0x06: assem_strcpy(insn[i],"TLBWR"); type=COP0; break; case 0x08: assem_strcpy(insn[i],"TLBP"); type=COP0; break; case 0x18: assem_strcpy(insn[i],"ERET"); type=COP0; break; } } break; case 0x11: assem_strcpy(insn[i],"cop1"); type=NI; op2=(source[i]>>21)&0x1f; switch(op2) { case 0x00: assem_strcpy(insn[i],"MFC1"); type=COP1; break; case 0x01: assem_strcpy(insn[i],"DMFC1"); type=COP1; break; case 0x02: assem_strcpy(insn[i],"CFC1"); type=COP1; break; case 0x04: assem_strcpy(insn[i],"MTC1"); type=COP1; break; case 0x05: assem_strcpy(insn[i],"DMTC1"); type=COP1; break; case 0x06: assem_strcpy(insn[i],"CTC1"); type=COP1; break; case 0x08: assem_strcpy(insn[i],"BC1"); type=FJUMP; switch((source[i]>>16)&0x3) { case 0x00: assem_strcpy(insn[i],"BC1F"); break; case 0x01: assem_strcpy(insn[i],"BC1T"); break; case 0x02: assem_strcpy(insn[i],"BC1FL"); break; case 0x03: assem_strcpy(insn[i],"BC1TL"); break; } break; case 0x10: assem_strcpy(insn[i],"C1.S"); type=NI; switch(source[i]&0x3f) { case 0x00: assem_strcpy(insn[i],"ADD.S"); type=FLOAT; break; case 0x01: assem_strcpy(insn[i],"SUB.S"); type=FLOAT; break; case 0x02: assem_strcpy(insn[i],"MUL.S"); type=FLOAT; break; case 0x03: assem_strcpy(insn[i],"DIV.S"); type=FLOAT; break; case 0x04: assem_strcpy(insn[i],"SQRT.S"); type=FLOAT; break; case 0x05: assem_strcpy(insn[i],"ABS.S"); type=FLOAT; break; case 0x06: assem_strcpy(insn[i],"MOV.S"); type=FLOAT; break; case 0x07: assem_strcpy(insn[i],"NEG.S"); type=FLOAT; break; case 0x08: assem_strcpy(insn[i],"ROUND.L.S"); type=FCONV; break; case 0x09: assem_strcpy(insn[i],"TRUNC.L.S"); type=FCONV; break; case 0x0A: assem_strcpy(insn[i],"CEIL.L.S"); type=FCONV; break; case 0x0B: assem_strcpy(insn[i],"FLOOR.L.S"); type=FCONV; break; case 0x0C: assem_strcpy(insn[i],"ROUND.W.S"); type=FCONV; break; case 0x0D: assem_strcpy(insn[i],"TRUNC.W.S"); type=FCONV; break; case 0x0E: assem_strcpy(insn[i],"CEIL.W.S"); type=FCONV; break; case 0x0F: assem_strcpy(insn[i],"FLOOR.W.S"); type=FCONV; break; case 0x21: assem_strcpy(insn[i],"CVT.D.S"); type=FCONV; break; case 0x24: assem_strcpy(insn[i],"CVT.W.S"); type=FCONV; break; case 0x25: assem_strcpy(insn[i],"CVT.L.S"); type=FCONV; break; case 0x30: assem_strcpy(insn[i],"C.F.S"); type=FCOMP; break; case 0x31: assem_strcpy(insn[i],"C.UN.S"); type=FCOMP; break; case 0x32: assem_strcpy(insn[i],"C.EQ.S"); type=FCOMP; break; case 0x33: assem_strcpy(insn[i],"C.UEQ.S"); type=FCOMP; break; case 0x34: assem_strcpy(insn[i],"C.OLT.S"); type=FCOMP; break; case 0x35: assem_strcpy(insn[i],"C.ULT.S"); type=FCOMP; break; case 0x36: assem_strcpy(insn[i],"C.OLE.S"); type=FCOMP; break; case 0x37: assem_strcpy(insn[i],"C.ULE.S"); type=FCOMP; break; case 0x38: assem_strcpy(insn[i],"C.SF.S"); type=FCOMP; break; case 0x39: assem_strcpy(insn[i],"C.NGLE.S"); type=FCOMP; break; case 0x3A: assem_strcpy(insn[i],"C.SEQ.S"); type=FCOMP; break; case 0x3B: assem_strcpy(insn[i],"C.NGL.S"); type=FCOMP; break; case 0x3C: assem_strcpy(insn[i],"C.LT.S"); type=FCOMP; break; case 0x3D: assem_strcpy(insn[i],"C.NGE.S"); type=FCOMP; break; case 0x3E: assem_strcpy(insn[i],"C.LE.S"); type=FCOMP; break; case 0x3F: assem_strcpy(insn[i],"C.NGT.S"); type=FCOMP; break; } break; case 0x11: assem_strcpy(insn[i],"C1.D"); type=NI; switch(source[i]&0x3f) { case 0x00: assem_strcpy(insn[i],"ADD.D"); type=FLOAT; break; case 0x01: assem_strcpy(insn[i],"SUB.D"); type=FLOAT; break; case 0x02: assem_strcpy(insn[i],"MUL.D"); type=FLOAT; break; case 0x03: assem_strcpy(insn[i],"DIV.D"); type=FLOAT; break; case 0x04: assem_strcpy(insn[i],"SQRT.D"); type=FLOAT; break; case 0x05: assem_strcpy(insn[i],"ABS.D"); type=FLOAT; break; case 0x06: assem_strcpy(insn[i],"MOV.D"); type=FLOAT; break; case 0x07: assem_strcpy(insn[i],"NEG.D"); type=FLOAT; break; case 0x08: assem_strcpy(insn[i],"ROUND.L.D"); type=FCONV; break; case 0x09: assem_strcpy(insn[i],"TRUNC.L.D"); type=FCONV; break; case 0x0A: assem_strcpy(insn[i],"CEIL.L.D"); type=FCONV; break; case 0x0B: assem_strcpy(insn[i],"FLOOR.L.D"); type=FCONV; break; case 0x0C: assem_strcpy(insn[i],"ROUND.W.D"); type=FCONV; break; case 0x0D: assem_strcpy(insn[i],"TRUNC.W.D"); type=FCONV; break; case 0x0E: assem_strcpy(insn[i],"CEIL.W.D"); type=FCONV; break; case 0x0F: assem_strcpy(insn[i],"FLOOR.W.D"); type=FCONV; break; case 0x20: assem_strcpy(insn[i],"CVT.S.D"); type=FCONV; break; case 0x24: assem_strcpy(insn[i],"CVT.W.D"); type=FCONV; break; case 0x25: assem_strcpy(insn[i],"CVT.L.D"); type=FCONV; break; case 0x30: assem_strcpy(insn[i],"C.F.D"); type=FCOMP; break; case 0x31: assem_strcpy(insn[i],"C.UN.D"); type=FCOMP; break; case 0x32: assem_strcpy(insn[i],"C.EQ.D"); type=FCOMP; break; case 0x33: assem_strcpy(insn[i],"C.UEQ.D"); type=FCOMP; break; case 0x34: assem_strcpy(insn[i],"C.OLT.D"); type=FCOMP; break; case 0x35: assem_strcpy(insn[i],"C.ULT.D"); type=FCOMP; break; case 0x36: assem_strcpy(insn[i],"C.OLE.D"); type=FCOMP; break; case 0x37: assem_strcpy(insn[i],"C.ULE.D"); type=FCOMP; break; case 0x38: assem_strcpy(insn[i],"C.SF.D"); type=FCOMP; break; case 0x39: assem_strcpy(insn[i],"C.NGLE.D"); type=FCOMP; break; case 0x3A: assem_strcpy(insn[i],"C.SEQ.D"); type=FCOMP; break; case 0x3B: assem_strcpy(insn[i],"C.NGL.D"); type=FCOMP; break; case 0x3C: assem_strcpy(insn[i],"C.LT.D"); type=FCOMP; break; case 0x3D: assem_strcpy(insn[i],"C.NGE.D"); type=FCOMP; break; case 0x3E: assem_strcpy(insn[i],"C.LE.D"); type=FCOMP; break; case 0x3F: assem_strcpy(insn[i],"C.NGT.D"); type=FCOMP; break; } break; case 0x14: assem_strcpy(insn[i],"C1.W"); type=NI; switch(source[i]&0x3f) { case 0x20: assem_strcpy(insn[i],"CVT.S.W"); type=FCONV; break; case 0x21: assem_strcpy(insn[i],"CVT.D.W"); type=FCONV; break; } break; case 0x15: assem_strcpy(insn[i],"C1.L"); type=NI; switch(source[i]&0x3f) { case 0x20: assem_strcpy(insn[i],"CVT.S.L"); type=FCONV; break; case 0x21: assem_strcpy(insn[i],"CVT.D.L"); type=FCONV; break; } break; } break; case 0x14: assem_strcpy(insn[i],"BEQL"); type=CJUMP; break; case 0x15: assem_strcpy(insn[i],"BNEL"); type=CJUMP; break; case 0x16: assem_strcpy(insn[i],"BLEZL"); type=CJUMP; break; case 0x17: assem_strcpy(insn[i],"BGTZL"); type=CJUMP; break; case 0x18: assem_strcpy(insn[i],"DADDI"); type=IMM16; break; case 0x19: assem_strcpy(insn[i],"DADDIU"); type=IMM16; break; case 0x1A: assem_strcpy(insn[i],"LDL"); type=LOADLR; break; case 0x1B: assem_strcpy(insn[i],"LDR"); type=LOADLR; break; case 0x20: assem_strcpy(insn[i],"LB"); type=LOAD; break; case 0x21: assem_strcpy(insn[i],"LH"); type=LOAD; break; case 0x22: assem_strcpy(insn[i],"LWL"); type=LOADLR; break; case 0x23: assem_strcpy(insn[i],"LW"); type=LOAD; break; case 0x24: assem_strcpy(insn[i],"LBU"); type=LOAD; break; case 0x25: assem_strcpy(insn[i],"LHU"); type=LOAD; break; case 0x26: assem_strcpy(insn[i],"LWR"); type=LOADLR; break; case 0x27: assem_strcpy(insn[i],"LWU"); type=LOAD; break; case 0x28: assem_strcpy(insn[i],"SB"); type=STORE; break; case 0x29: assem_strcpy(insn[i],"SH"); type=STORE; break; case 0x2A: assem_strcpy(insn[i],"SWL"); type=STORELR; break; case 0x2B: assem_strcpy(insn[i],"SW"); type=STORE; break; case 0x2C: assem_strcpy(insn[i],"SDL"); type=STORELR; break; case 0x2D: assem_strcpy(insn[i],"SDR"); type=STORELR; break; case 0x2E: assem_strcpy(insn[i],"SWR"); type=STORELR; break; case 0x2F: assem_strcpy(insn[i],"CACHE"); type=NOP; break; case 0x30: assem_strcpy(insn[i],"LL"); type=NI; break; case 0x31: assem_strcpy(insn[i],"LWC1"); type=C1LS; break; case 0x34: assem_strcpy(insn[i],"LLD"); type=NI; break; case 0x35: assem_strcpy(insn[i],"LDC1"); type=C1LS; break; case 0x37: assem_strcpy(insn[i],"LD"); type=LOAD; break; case 0x38: assem_strcpy(insn[i],"SC"); type=NI; break; case 0x39: assem_strcpy(insn[i],"SWC1"); type=C1LS; break; case 0x3C: assem_strcpy(insn[i],"SCD"); type=NI; break; case 0x3D: assem_strcpy(insn[i],"SDC1"); type=C1LS; break; case 0x3F: assem_strcpy(insn[i],"SD"); type=STORE; break; default: assem_strcpy(insn[i],"???"); type=NI; break; } itype[i]=type; opcode2[i]=op2; /* Get registers/immediates */ lt1[i]=0; us1[i]=0; us2[i]=0; dep1[i]=0; dep2[i]=0; switch(type) { case LOAD: rs1[i]=(source[i]>>21)&0x1f; rs2[i]=0; rt1[i]=(source[i]>>16)&0x1f; rt2[i]=0; imm[i]=(short)source[i]; break; case STORE: case STORELR: rs1[i]=(source[i]>>21)&0x1f; rs2[i]=(source[i]>>16)&0x1f; rt1[i]=0; rt2[i]=0; imm[i]=(short)source[i]; if(op==0x2c||op==0x2d||op==0x3f) us1[i]=rs2[i]; // 64-bit SDL/SDR/SD break; case LOADLR: // LWL/LWR only load part of the register, // therefore the target register must be treated as a source too rs1[i]=(source[i]>>21)&0x1f; rs2[i]=(source[i]>>16)&0x1f; rt1[i]=(source[i]>>16)&0x1f; rt2[i]=0; imm[i]=(short)source[i]; if(op==0x1a||op==0x1b) us1[i]=rs2[i]; // LDR/LDL if(op==0x26) dep1[i]=rt1[i]; // LWR break; case IMM16: if (op==0x0f) rs1[i]=0; // LUI instruction has no source register else rs1[i]=(source[i]>>21)&0x1f; rs2[i]=0; rt1[i]=(source[i]>>16)&0x1f; rt2[i]=0; if(op>=0x0c&&op<=0x0e) { // ANDI/ORI/XORI imm[i]=(unsigned short)source[i]; }else{ imm[i]=(short)source[i]; } if(op==0x18||op==0x19) us1[i]=rs1[i]; // DADDI/DADDIU if(op==0x0a||op==0x0b) us1[i]=rs1[i]; // SLTI/SLTIU if(op==0x0d||op==0x0e) dep1[i]=rs1[i]; // ORI/XORI break; case UJUMP: rs1[i]=0; rs2[i]=0; rt1[i]=0; rt2[i]=0; // The JAL instruction writes to r31. if (op&1) { rt1[i]=31; } rs2[i]=CCREG; break; case RJUMP: rs1[i]=(source[i]>>21)&0x1f; rs2[i]=0; rt1[i]=0; rt2[i]=0; // The JALR instruction writes to rd. if (op2&1) { rt1[i]=(source[i]>>11)&0x1f; } rs2[i]=CCREG; break; case CJUMP: rs1[i]=(source[i]>>21)&0x1f; rs2[i]=(source[i]>>16)&0x1f; rt1[i]=0; rt2[i]=0; if(op&2) { // BGTZ/BLEZ rs2[i]=0; } us1[i]=rs1[i]; us2[i]=rs2[i]; likely[i]=op>>4; break; case SJUMP: rs1[i]=(source[i]>>21)&0x1f; rs2[i]=CCREG; rt1[i]=0; rt2[i]=0; us1[i]=rs1[i]; if(op2&0x10) { // BxxAL rt1[i]=31; // NOTE: If the branch is not taken, r31 is still overwritten } likely[i]=(op2&2)>>1; break; case FJUMP: rs1[i]=FSREG; rs2[i]=CSREG; rt1[i]=0; rt2[i]=0; likely[i]=((source[i])>>17)&1; break; case ALU: rs1[i]=(source[i]>>21)&0x1f; // source rs2[i]=(source[i]>>16)&0x1f; // subtract amount rt1[i]=(source[i]>>11)&0x1f; // destination rt2[i]=0; if(op2==0x2a||op2==0x2b) { // SLT/SLTU us1[i]=rs1[i];us2[i]=rs2[i]; } else if(op2>=0x24&&op2<=0x27) { // AND/OR/XOR/NOR dep1[i]=rs1[i];dep2[i]=rs2[i]; } else if(op2>=0x2c&&op2<=0x2f) { // DADD/DSUB dep1[i]=rs1[i];dep2[i]=rs2[i]; } break; case MULTDIV: rs1[i]=(source[i]>>21)&0x1f; // source rs2[i]=(source[i]>>16)&0x1f; // divisor rt1[i]=HIREG; rt2[i]=LOREG; if (op2>=0x1c&&op2<=0x1f) { // DMULT/DMULTU/DDIV/DDIVU us1[i]=rs1[i];us2[i]=rs2[i]; } break; case MOV: rs1[i]=0; rs2[i]=0; rt1[i]=0; rt2[i]=0; if(op2==0x10) rs1[i]=HIREG; // MFHI if(op2==0x11) rt1[i]=HIREG; // MTHI if(op2==0x12) rs1[i]=LOREG; // MFLO if(op2==0x13) rt1[i]=LOREG; // MTLO if((op2&0x1d)==0x10) rt1[i]=(source[i]>>11)&0x1f; // MFxx if((op2&0x1d)==0x11) rs1[i]=(source[i]>>21)&0x1f; // MTxx dep1[i]=rs1[i]; break; case SHIFT: rs1[i]=(source[i]>>16)&0x1f; // target of shift rs2[i]=(source[i]>>21)&0x1f; // shift amount rt1[i]=(source[i]>>11)&0x1f; // destination rt2[i]=0; // DSLLV/DSRLV/DSRAV are 64-bit if(op2>=0x14&&op2<=0x17) us1[i]=rs1[i]; break; case SHIFTIMM: rs1[i]=(source[i]>>16)&0x1f; rs2[i]=0; rt1[i]=(source[i]>>11)&0x1f; rt2[i]=0; imm[i]=(source[i]>>6)&0x1f; // DSxx32 instructions if(op2>=0x3c) imm[i]|=0x20; // DSLL/DSRL/DSRA/DSRA32/DSRL32 but not DSLL32 require 64-bit source if(op2>=0x38&&op2!=0x3c) us1[i]=rs1[i]; break; case COP0: rs1[i]=0; rs2[i]=0; rt1[i]=0; rt2[i]=0; if(op2==0) rt1[i]=(source[i]>>16)&0x1F; // MFC0 if(op2==4) rs1[i]=(source[i]>>16)&0x1F; // MTC0 if(op2==4&&((source[i]>>11)&0x1f)==12) rt2[i]=CSREG; // Status if(op2==16) if((source[i]&0x3f)==0x18) rs2[i]=CCREG; // ERET break; case COP1: rs1[i]=0; rs2[i]=0; rt1[i]=0; rt2[i]=0; if(op2<3) rt1[i]=(source[i]>>16)&0x1F; // MFC1/DMFC1/CFC1 if(op2>3) rs1[i]=(source[i]>>16)&0x1F; // MTC1/DMTC1/CTC1 if(op2==5) us1[i]=rs1[i]; // DMTC1 rs2[i]=CSREG; break; case C1LS: rs1[i]=(source[i]>>21)&0x1F; rs2[i]=CSREG; rt1[i]=0; rt2[i]=0; imm[i]=(short)source[i]; break; case FLOAT: case FCONV: rs1[i]=0; rs2[i]=CSREG; rt1[i]=0; rt2[i]=0; break; case FCOMP: rs1[i]=FSREG; rs2[i]=CSREG; rt1[i]=FSREG; rt2[i]=0; break; case SYSCALL: rs1[i]=CCREG; rs2[i]=0; rt1[i]=0; rt2[i]=0; break; default: rs1[i]=0; rs2[i]=0; rt1[i]=0; rt2[i]=0; } /* Calculate branch target addresses */ if(type==UJUMP) ba[i]=((start+i*4+4)&0xF0000000)|(((unsigned int)source[i]<<6)>>4); else if(type==CJUMP&&rs1[i]==rs2[i]&&(op&1)) ba[i]=start+i*4+8; // Ignore never taken branch else if(type==SJUMP&&rs1[i]==0&&!(op2&1)) ba[i]=start+i*4+8; // Ignore never taken branch else if(type==CJUMP||type==SJUMP||type==FJUMP) ba[i]=start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14); else ba[i]=-1; /* Is this the end of the block? */ if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP||(source[i-1]>>16)==0x1000)) { if(rt1[i-1]==0) { // Continue past subroutine call (JAL) done=1; // Does the block continue due to a branch? for(j=i-1;j>=0;j--) { if(ba[j]==start+i*4) done=j=0; // Branch into delay slot if(ba[j]==start+i*4+4) done=j=0; if(ba[j]==start+i*4+8) done=j=0; } // Stop if we're compiling junk if(type==UJUMP||type==CJUMP||type==SJUMP||type==RJUMP||type==FJUMP) { done=stop_after_jal=1; itype[i]=NOP; DebugMessage(M64MSG_VERBOSE, "Disabled speculative precompilation"); } } else { if(stop_after_jal) done=1; // Stop on BREAK if((source[i+1]&0xfc00003f)==0x0d) done=1; } // Don't recompile stuff that's already compiled if(check_addr(start+i*4+4)) done=1; // Don't get too close to the limit if(i>MAXBLOCK/2) done=1; } if(i>0&&itype[i]==SYSCALL&&stop_after_jal) done=1; assert(i0); /* Pass 2 - Register dependencies and branch targets */ unneeded_registers(0,slen-1,0); /* Pass 3 - Register allocation */ struct regstat current; // Current register allocations/status current.is32=1; current.dirty=0; current.u=unneeded_reg[0]; current.uu=unneeded_reg_upper[0]; clear_all_regs(current.regmap); alloc_reg(¤t,0,CCREG); dirty_reg(¤t,CCREG); current.isconst=0; current.wasconst=0; int ds=0; int cc=0; int hr; provisional_32bit(); if((u_int)addr&1) { // First instruction is delay slot cc=-1; bt[1]=1; ds=1; unneeded_reg[0]=1; unneeded_reg_upper[0]=1; current.regmap[HOST_BTREG]=BTREG; } for(i=0;i1) { if((opcode[i-2]&0x2f)==0x05) // BNE/BNEL { if(rs1[i-2]==0||rs2[i-2]==0) { if(rs1[i-2]) { current.is32|=1LL<=0) current.regmap[hr]=-1; } if(rs2[i-2]) { current.is32|=1LL<=0) current.regmap[hr]=-1; } } } } // If something jumps here with 64-bit values // then promote those registers to 64 bits if(bt[i]) { uint64_t temp_is32=current.is32; for(j=i-1;j>=0;j--) { if(ba[j]==start+i*4) temp_is32&=branch_regs[j].is32; } for(j=i;j0&&r<64) { if((current.dirty>>hr)&((current.is32&~temp_is32)>>r)&1) { temp_is32|=1LL<=0;j--) { if(ba[j]==start+i*4+4) temp_is32&=branch_regs[j].is32; } for(j=i;j0) { if((current.dirty>>hr)&((current.is32&~temp_is32)>>(r&63))&1) { if(itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP&&itype[i]!=RJUMP&&itype[i]!=FJUMP) { if(rs1[i]!=(r&63)&&rs2[i]!=(r&63)) { //DebugMessage(M64MSG_VERBOSE, "dump %d/r%d",hr,r); current.regmap[hr]=-1; if(get_reg(current.regmap,r|64)>=0) current.regmap[get_reg(current.regmap,r|64)]=-1; } } } } } } } else if(i>16)!=0x1000&&(itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP)) { uint64_t temp_is32=current.is32; for(j=i-1;j>=0;j--) { if(ba[j]==start+i*4+8) temp_is32&=branch_regs[j].is32; } for(j=i;j0) { if((current.dirty>>hr)&((current.is32&~temp_is32)>>(r&63))&1) { if(rs1[i]!=(r&63)&&rs2[i]!=(r&63)&&rs1[i+1]!=(r&63)&&rs2[i+1]!=(r&63)) { //DebugMessage(M64MSG_VERBOSE, "dump %d/r%d",hr,r); current.regmap[hr]=-1; if(get_reg(current.regmap,r|64)>=0) current.regmap[get_reg(current.regmap,r|64)]=-1; } } } } } } #endif if(itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP&&itype[i]!=RJUMP&&itype[i]!=FJUMP) { if(i+1>rt1[i])&1) current.uu&=~((1LL<>rt1[i+1])&1) current.uu&=~((1LL<>rt1[i])&1) current.uu&=~((1LL<=0) { if(r!=regmap_pre[i][hr]) { regs[i].regmap_entry[hr]=-1; } else { if(r<64){ if((current.u>>r)&1) { regs[i].regmap_entry[hr]=-1; regs[i].regmap[hr]=-1; //Don't clear regs in the delay slot as the branch might need them if(!ooo[i-1]) current.regmap[hr]=-1; }else regs[i].regmap_entry[hr]=r; } else { if((current.uu>>(r&63))&1) { regs[i].regmap_entry[hr]=-1; regs[i].regmap[hr]=-1; //Don't clear regs in the delay slot as the branch might need them if(!ooo[i-1]) current.regmap[hr]=-1; }else regs[i].regmap_entry[hr]=r; } } } else { // First instruction expects CCREG to be allocated if(i==0&&hr==HOST_CCREG) regs[i].regmap_entry[hr]=CCREG; else regs[i].regmap_entry[hr]=-1; } } } else { // Not delay slot switch(itype[i]) { case UJUMP: //current.isconst=0; // DEBUG //current.wasconst=0; // DEBUG //regs[i].wasconst=0; // DEBUG clear_const(¤t,rt1[i]); alloc_cc(¤t,i); dirty_reg(¤t,CCREG); if (rt1[i]==31) { alloc_reg(¤t,i,31); dirty_reg(¤t,31); #ifdef REG_PREFETCH alloc_reg(¤t,i,PTEMP); #endif //current.is32|=1LL<>rs1[i])&(current.is32>>rs2[i])&1)) { if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); if(rs2[i]) alloc_reg64(¤t,i,rs2[i]); } if((rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]))|| (rs2[i]&&(rs2[i]==rt1[i+1]||rs2[i]==rt2[i+1]))) { // The delay slot overwrites one of our conditions. // Allocate the branch condition registers instead. current.isconst=0; current.wasconst=0; regs[i].wasconst=0; if(rs1[i]) alloc_reg(¤t,i,rs1[i]); if(rs2[i]) alloc_reg(¤t,i,rs2[i]); if(!((current.is32>>rs1[i])&(current.is32>>rs2[i])&1)) { if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); if(rs2[i]) alloc_reg64(¤t,i,rs2[i]); } } else if((i!=(ba[i]-start)>>2 || source[i+1]!=0)) { ooo[i]=1; delayslot_alloc(¤t,i+1); } } else if((opcode[i]&0x3E)==6) // BLEZ/BGTZ { alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,rs1[i]); if(!(current.is32>>rs1[i]&1)) { alloc_reg64(¤t,i,rs1[i]); } if(rs1[i]&&(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1])) { // The delay slot overwrites one of our conditions. // Allocate the branch condition registers instead. current.isconst=0; current.wasconst=0; regs[i].wasconst=0; if(rs1[i]) alloc_reg(¤t,i,rs1[i]); if(!((current.is32>>rs1[i])&1)) { if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); } } else if((i!=(ba[i]-start)>>2 || source[i+1]!=0)) { ooo[i]=1; delayslot_alloc(¤t,i+1); } } else // Don't alloc the delay slot yet because we might not execute it if((opcode[i]&0x3E)==0x14) // BEQL/BNEL { current.isconst=0; current.wasconst=0; regs[i].wasconst=0; alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,rs1[i]); alloc_reg(¤t,i,rs2[i]); if(!((current.is32>>rs1[i])&(current.is32>>rs2[i])&1)) { alloc_reg64(¤t,i,rs1[i]); alloc_reg64(¤t,i,rs2[i]); } } else if((opcode[i]&0x3E)==0x16) // BLEZL/BGTZL { current.isconst=0; current.wasconst=0; regs[i].wasconst=0; alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,rs1[i]); if(!(current.is32>>rs1[i]&1)) { alloc_reg64(¤t,i,rs1[i]); } } ds=1; //current.isconst=0; break; case SJUMP: //current.isconst=0; //current.wasconst=0; //regs[i].wasconst=0; clear_const(¤t,rs1[i]); clear_const(¤t,rt1[i]); //if((opcode2[i]&0x1E)==0x0) // BLTZ/BGEZ if((opcode2[i]&0x0E)==0x0) // BLTZ/BGEZ { alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,rs1[i]); if(!(current.is32>>rs1[i]&1)) { alloc_reg64(¤t,i,rs1[i]); } if (rt1[i]==31) { // BLTZAL/BGEZAL alloc_reg(¤t,i,31); dirty_reg(¤t,31); assert(rs1[i+1]!=31&&rs2[i+1]!=31); //#ifdef REG_PREFETCH //alloc_reg(¤t,i,PTEMP); //#endif //current.is32|=1LL<>rs1[i])&1)) { if(rs1[i]) alloc_reg64(¤t,i,rs1[i]); } } else if((i!=(ba[i]-start)>>2 || source[i+1]!=0)) { ooo[i]=1; delayslot_alloc(¤t,i+1); } } else // Don't alloc the delay slot yet because we might not execute it if((opcode2[i]&0x1E)==0x2) // BLTZL/BGEZL { current.isconst=0; current.wasconst=0; regs[i].wasconst=0; alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,rs1[i]); if(!(current.is32>>rs1[i]&1)) { alloc_reg64(¤t,i,rs1[i]); } } ds=1; //current.isconst=0; break; case FJUMP: current.isconst=0; current.wasconst=0; regs[i].wasconst=0; if(likely[i]==0) // BC1F/BC1T { // TODO: Theoretically we can run out of registers here on x86. // The delay slot can allocate up to six, and we need to check // CSREG before executing the delay slot. Possibly we can drop // the cycle count and then reload it after checking that the // FPU is in a usable state, or don't do out-of-order execution. alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,FSREG); alloc_reg(¤t,i,CSREG); if(itype[i+1]==FCOMP) { // The delay slot overwrites the branch condition. // Allocate the branch condition registers instead. alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,CSREG); alloc_reg(¤t,i,FSREG); } else if((i!=(ba[i]-start)>>2 || source[i+1]!=0)) { ooo[i]=1; delayslot_alloc(¤t,i+1); alloc_reg(¤t,i+1,CSREG); } } else // Don't alloc the delay slot yet because we might not execute it if(likely[i]) // BC1FL/BC1TL { alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,CSREG); alloc_reg(¤t,i,FSREG); } ds=1; current.isconst=0; break; case IMM16: imm16_alloc(¤t,i); break; case LOAD: case LOADLR: load_alloc(¤t,i); break; case STORE: case STORELR: store_alloc(¤t,i); break; case ALU: alu_alloc(¤t,i); break; case SHIFT: shift_alloc(¤t,i); break; case MULTDIV: multdiv_alloc(¤t,i); break; case SHIFTIMM: shiftimm_alloc(¤t,i); break; case MOV: mov_alloc(¤t,i); break; case COP0: cop0_alloc(¤t,i); break; case COP1: cop1_alloc(¤t,i); break; case C1LS: c1ls_alloc(¤t,i); break; case FCONV: fconv_alloc(¤t,i); break; case FLOAT: float_alloc(¤t,i); break; case FCOMP: fcomp_alloc(¤t,i); break; case SYSCALL: syscall_alloc(¤t,i); break; case SPAN: pagespan_alloc(¤t,i); break; } // Make sure the allocator didn't do anything bad for(hr=0;hr=0) { if(r==regmap_pre[i][hr]) { // If it was dirty before, make sure it's still dirty if((regs[i].wasdirty>>hr)&1) { if (!((current.dirty>>hr)&1)) { //FIXME: delayslot_alloc realloc registers removed from cache by jump instruction, thus the missing dirty flag assert(itype[i]==CJUMP); current.dirty|=1LL<>hr)&1)!=0); } } } } // Drop the upper half of registers that have become 32-bit current.uu|=current.is32&((1LL<>rt1[i])&1) current.uu&=~((1LL<>rt1[i+1])&1) current.uu&=~((1LL<=0) { if(r!=regmap_pre[i][hr]) { // TODO: delay slot (?) or=get_reg(regmap_pre[i],r); // Get old mapping for this register if(or<0||(r&63)>=TEMPREG){ regs[i].regmap_entry[hr]=-1; } else { // Just move it to a different register regs[i].regmap_entry[hr]=r; // If it was dirty before, it's still dirty if((regs[i].wasdirty>>or)&1) dirty_reg(¤t,r&63); } } else { // Unneeded if(r==0){ regs[i].regmap_entry[hr]=0; } else if(r<64){ if((current.u>>r)&1) { regs[i].regmap_entry[hr]=-1; //regs[i].regmap[hr]=-1; current.regmap[hr]=-1; }else regs[i].regmap_entry[hr]=r; } else { if((current.uu>>(r&63))&1) { regs[i].regmap_entry[hr]=-1; //regs[i].regmap[hr]=-1; current.regmap[hr]=-1; }else regs[i].regmap_entry[hr]=r; } } } else { // Branches expect CCREG to be allocated at the target if(regmap_pre[i][hr]==CCREG) regs[i].regmap_entry[hr]=CCREG; else regs[i].regmap_entry[hr]=-1; } } memcpy(regs[i].regmap,current.regmap,sizeof(current.regmap)); } /* Branch post-alloc */ if(i>0) { current.was32=current.is32; current.wasdirty=current.dirty; switch(itype[i-1]) { case UJUMP: memcpy(&branch_regs[i-1],¤t,sizeof(current)); branch_regs[i-1].isconst=0; branch_regs[i-1].wasconst=0; branch_regs[i-1].u=branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) current.uu&=~((1LL<>rs1[i-1])&(current.is32>>rs2[i-1])&1)) { if(rs1[i-1]) alloc_reg64(¤t,i-1,rs1[i-1]); if(rs2[i-1]) alloc_reg64(¤t,i-1,rs2[i-1]); } } memcpy(&branch_regs[i-1],¤t,sizeof(current)); branch_regs[i-1].isconst=0; branch_regs[i-1].wasconst=0; memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); } else if((opcode[i-1]&0x3E)==6) // BLEZ/BGTZ { alloc_cc(¤t,i-1); dirty_reg(¤t,CCREG); if(rs1[i-1]==rt1[i]||rs1[i-1]==rt2[i]) { // The delay slot overwrote the branch condition // Delay slot goes after the test (in order) current.u=branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) current.uu&=~((1LL<>rs1[i-1]&1)) { alloc_reg64(¤t,i-1,rs1[i-1]); } } memcpy(&branch_regs[i-1],¤t,sizeof(current)); branch_regs[i-1].isconst=0; branch_regs[i-1].wasconst=0; memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); } else // Alloc the delay slot in case the branch is taken if((opcode[i-1]&0x3E)==0x14) // BEQL/BNEL { memcpy(&branch_regs[i-1],¤t,sizeof(current)); branch_regs[i-1].u=(branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>rt1[i])&1) current.uu&=~((1LL<>rs1[i-1]&1)) { alloc_reg64(¤t,i-1,rs1[i-1]); } } memcpy(&branch_regs[i-1],¤t,sizeof(current)); branch_regs[i-1].isconst=0; branch_regs[i-1].wasconst=0; memcpy(&branch_regs[i-1].regmap_entry,¤t.regmap,sizeof(current.regmap)); memcpy(constmap[i],constmap[i-1],sizeof(current.constmap)); } else // Alloc the delay slot in case the branch is taken if((opcode2[i-1]&0x1E)==2) // BLTZL/BGEZL { memcpy(&branch_regs[i-1],¤t,sizeof(current)); branch_regs[i-1].u=(branch_unneeded_reg[i-1]&~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>rt1[i])&1) branch_regs[i-1].uu&=~((1LL<>16)==0x1000) { if(rt1[i-1]==31) // JAL/JALR { // Subroutine call will return here, don't alloc any registers current.is32=1; current.dirty=0; clear_all_regs(current.regmap); alloc_reg(¤t,i,CCREG); dirty_reg(¤t,CCREG); } else if(i+1=0;j--) { if(ba[j]==start+i*4+4) { memcpy(current.regmap,branch_regs[j].regmap,sizeof(current.regmap)); current.is32=branch_regs[j].is32; current.dirty=branch_regs[j].dirty; break; } } while(j>=0) { if(ba[j]==start+i*4+4) { for(hr=0;hr0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP||itype[i-1]==FJUMP||itype[i]==SYSCALL)) { cc=0; } else { cc++; } flush_dirty_uppers(¤t); if(!is_ds[i]) { regs[i].is32=current.is32; regs[i].dirty=current.dirty; regs[i].isconst=current.isconst; memcpy(constmap[i],current.constmap,sizeof(current.constmap)); } for(hr=0;hr=0) { if(regmap_pre[i][hr]!=regs[i].regmap[hr]) { regs[i].wasconst&=~(1<=0;i--) { int hr=0; if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { if(ba[i]=(start+slen*4)) { // Branch out of this block, don't need anything nr=0LL; } else { // Internal branch // Need whatever matches the target nr=0LL; int t=(ba[i]-start)>>2; for(hr=0;hr=0) { if(regs[i].regmap_entry[hr]==regs[t].regmap_entry[hr]) nr|=1LL<>16)!=0x1000) { if(i=0&&get_reg(regs[i+2].regmap_entry,regmap_pre[i+2][hr])<0) nr&=~(1LL<=0) if(!((nr>>hr)&1)) DebugMessage(M64MSG_VERBOSE, "%x-bogus(%d=%d)",start+i*4,hr,regmap_entry[i+2][hr]); } } } // Don't need stuff which is overwritten //FIXME if(regs[i].regmap[hr]!=regmap_pre[i][hr]) nr&=~(1LL<>dep1[i+1])&1)) { if(dep1[i+1]==(regmap_pre[i][hr]&63)) nr|=1LL<>dep2[i+1])&1)) { if(dep1[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1LL<=0&&get_reg(regs[i+1].regmap_entry,regmap_pre[i+1][hr])<0) nr&=~(1LL<>dep1[i])&1)) { if(dep1[i]==(regmap_pre[i][hr]&63)) nr|=1LL<>dep2[i])&1)) { if(dep2[i]==(regmap_pre[i][hr]&63)) nr|=1LL<0&&!bt[i]&&((regs[i].wasdirty>>hr)&1)) { if((regmap_pre[i][hr]>0&®map_pre[i][hr]<64&&!((unneeded_reg[i]>>regmap_pre[i][hr])&1)) || (regmap_pre[i][hr]>64&&!((unneeded_reg_upper[i]>>(regmap_pre[i][hr]&63))&1)) ) { if(rt1[i-1]==(regmap_pre[i][hr]&63)) nr|=1LL<0&®s[i].regmap_entry[hr]<64&&!((unneeded_reg[i]>>regs[i].regmap_entry[hr])&1)) || (regs[i].regmap_entry[hr]>64&&!((unneeded_reg_upper[i]>>(regs[i].regmap_entry[hr]&63))&1)) ) { if(rt1[i-1]==(regs[i].regmap_entry[hr]&63)) nr|=1LL<>hr)&1)) { if(regs[i].regmap_entry[hr]!=CCREG) regs[i].regmap_entry[hr]=-1; if((regs[i].regmap[hr]&63)!=rs1[i] && (regs[i].regmap[hr]&63)!=rs2[i] && (regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] && (regs[i].regmap[hr]&63)!=PTEMP && (regs[i].regmap[hr]&63)!=CCREG) { if(itype[i]!=RJUMP&&itype[i]!=UJUMP&&(source[i]>>16)!=0x1000) { if(likely[i]) { regs[i].regmap[hr]=-1; regs[i].isconst&=~(1<=0||get_reg(branch_regs[i].regmap,rt1[i+1]|64)>=0) { d1=dep1[i+1]; d2=dep2[i+1]; } if(using_tlb) { if(itype[i+1]==LOAD || itype[i+1]==LOADLR || itype[i+1]==STORE || itype[i+1]==STORELR || itype[i+1]==C1LS ) map=TLREG; } else if(itype[i+1]==STORE || itype[i+1]==STORELR || (opcode[i+1]&0x3b)==0x39) { map=INVCP; } if(itype[i+1]==LOADLR || itype[i+1]==STORELR || itype[i+1]==C1LS ) temp=FTEMP; if((regs[i].regmap[hr]&63)!=rs1[i] && (regs[i].regmap[hr]&63)!=rs2[i] && (regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] && (regs[i].regmap[hr]&63)!=rt1[i+1] && (regs[i].regmap[hr]&63)!=rt2[i+1] && (regs[i].regmap[hr]^64)!=us1[i+1] && (regs[i].regmap[hr]^64)!=us2[i+1] && (regs[i].regmap[hr]^64)!=d1 && (regs[i].regmap[hr]^64)!=d2 && regs[i].regmap[hr]!=rs1[i+1] && regs[i].regmap[hr]!=rs2[i+1] && (regs[i].regmap[hr]&63)!=temp && regs[i].regmap[hr]!=PTEMP && regs[i].regmap[hr]!=RHASH && regs[i].regmap[hr]!=RHTBL && regs[i].regmap[hr]!=RTEMP && regs[i].regmap[hr]!=CCREG && regs[i].regmap[hr]!=map ) { regs[i].regmap[hr]=-1; regs[i].isconst&=~(1<>16)!=0x1000) { if(!likely[i]&&i0) { int d1=0,d2=0,map=-1,temp=-1; if(get_reg(regs[i].regmap,rt1[i]|64)>=0) { d1=dep1[i]; d2=dep2[i]; } if(using_tlb) { if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS ) map=TLREG; } else if(itype[i]==STORE || itype[i]==STORELR || (opcode[i]&0x3b)==0x39) { map=INVCP; } if(itype[i]==LOADLR || itype[i]==STORELR || itype[i]==C1LS ) temp=FTEMP; if((regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] && (regs[i].regmap[hr]^64)!=us1[i] && (regs[i].regmap[hr]^64)!=us2[i] && (regs[i].regmap[hr]^64)!=d1 && (regs[i].regmap[hr]^64)!=d2 && regs[i].regmap[hr]!=rs1[i] && regs[i].regmap[hr]!=rs2[i] && (regs[i].regmap[hr]&63)!=temp && regs[i].regmap[hr]!=map && (itype[i]!=SPAN||regs[i].regmap[hr]!=CCREG)) { if(i>(regs[i].regmap[hr]&63))&1)) { DebugMessage(M64MSG_VERBOSE, "fail: %x (%d %d!=%d)",start+i*4,hr,regmap_pre[i+1][hr],regs[i].regmap[hr]); assert(regmap_pre[i+1][hr]==regs[i].regmap[hr]); } regmap_pre[i+1][hr]=-1; if(regs[i+1].regmap_entry[hr]==CCREG) regs[i+1].regmap_entry[hr]=-1; regs[i+1].wasconst&=~(1<=(start+i*4)) continue; // jump out of this block or forward branch if(itype[i+1]==NOP||itype[i+1]==MOV||itype[i+1]==ALU ||itype[i+1]==SHIFTIMM||itype[i+1]==IMM16||itype[i+1]==LOAD ||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS ||itype[i+1]==SHIFT||itype[i+1]==COP1||itype[i+1]==FLOAT ||itype[i+1]==FCOMP||itype[i+1]==FCONV) { int t=(ba[i]-start)>>2; if(t<=0||(itype[t-1]==UJUMP||itype[t-1]==RJUMP||itype[t-1]==CJUMP||itype[t-1]==SJUMP||itype[t-1]==FJUMP)) continue; // loop_preload can't handle jumps into delay slots if(t>=2&&(itype[t-2]==UJUMP||itype[t-2]==RJUMP)&&rt1[t-2]==31) continue; // call/ret assumes no registers allocated for(hr=0;hr64) { if(!((regs[i].dirty>>hr)&1)) f_regmap[hr]=regs[i].regmap[hr]; else f_regmap[hr]=-1; } else if(regs[i].regmap[hr]>=0) { if(f_regmap[hr]!=regs[i].regmap[hr]) { // dealloc old register int n; for(n=0;n64) { if(!((branch_regs[i].dirty>>hr)&1)) f_regmap[hr]=branch_regs[i].regmap[hr]; else f_regmap[hr]=-1; } else if(branch_regs[i].regmap[hr]>=0) { if(f_regmap[hr]!=branch_regs[i].regmap[hr]) { // dealloc old register int n; for(n=0;nclean transition #ifdef DESTRUCTIVE_WRITEBACK if(t>0) if(get_reg(regmap_pre[t],f_regmap[hr])>=0) if((regs[t].wasdirty>>get_reg(regmap_pre[t],f_regmap[hr]))&1) f_regmap[hr]=-1; #endif // This check is only strictly required in the DESTRUCTIVE_WRITEBACK // case above, however it's always a good idea. We can't hoist the // load if the register was already allocated, so there's no point // wasting time analyzing most of these cases. It only "succeeds" // when the mapping was different and the load can be replaced with // a mov, which is of negligible benefit. So such cases are // skipped below. if(f_regmap[hr]>0) { if(regs[t].regmap[hr]==f_regmap[hr]||(regs[t].regmap_entry[hr]<0&&get_reg(regmap_pre[t],f_regmap[hr])<0)) { int r=f_regmap[hr]; for(j=t;j<=i;j++) { //DebugMessage(M64MSG_VERBOSE, "Test %x -> %x, %x %d/%d",start+i*4,ba[i],start+j*4,hr,r); if(r<34&&((unneeded_reg[j]>>r)&1)) break; if(r>63&&((unneeded_reg_upper[j]>>(r&63))&1)) break; if(r>63) { // NB This can exclude the case where the upper-half // register is lower numbered than the lower-half // register. Not sure if it's worth fixing... if(get_reg(regs[j].regmap,r&63)<0) break; if(get_reg(regs[j].regmap_entry,r&63)<0) break; if(regs[j].is32&(1LL<<(r&63))) break; } if(regs[j].regmap[hr]==f_regmap[hr]&&(f_regmap[hr]&63) %x, %x %d/%d",start+i*4,ba[i],start+j*4,hr,r); int k; if(regs[i].regmap[hr]==-1&&branch_regs[i].regmap[hr]==-1) { if(get_reg(regs[i].regmap,f_regmap[hr])>=0) break; if(get_reg(branch_regs[i].regmap,f_regmap[hr])>=0) break; if(get_reg(regs[i+2].regmap,f_regmap[hr])>=0) break; if(r>63) { if(get_reg(regs[i].regmap,r&63)<0) break; if(get_reg(branch_regs[i].regmap,r&63)<0) break; } k=i; while(k>1&®s[k-1].regmap[hr]==-1) { if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { //DebugMessage(M64MSG_VERBOSE, "no free regs for store %x",start+(k-1)*4); break; } if(get_reg(regs[k-1].regmap,f_regmap[hr])>=0) { //DebugMessage(M64MSG_VERBOSE, "no-match due to different register"); break; } if(itype[k-2]==UJUMP||itype[k-2]==RJUMP||itype[k-2]==CJUMP||itype[k-2]==SJUMP||itype[k-2]==FJUMP) { //DebugMessage(M64MSG_VERBOSE, "no-match due to branch"); break; } // call/ret fast path assumes no registers allocated if(k>2&&(itype[k-3]==UJUMP||itype[k-3]==RJUMP)&&rt1[k-3]==31) { break; } if(r>63) { // NB This can exclude the case where the upper-half // register is lower numbered than the lower-half // register. Not sure if it's worth fixing... if(get_reg(regs[k-1].regmap,r&63)<0) break; if(regs[k-1].is32&(1LL<<(r&63))) break; } k--; } if(i",hr,start+k*4); while(k",hr,start+k*4); break; } assert(regs[i-1].regmap[hr]==f_regmap[hr]); if(regs[i-1].regmap[hr]==f_regmap[hr]&®map_pre[i][hr]==f_regmap[hr]) { //DebugMessage(M64MSG_VERBOSE, "OK fill %x (r%d)",start+i*4,hr); regs[i].regmap_entry[hr]=f_regmap[hr]; regs[i].regmap[hr]=f_regmap[hr]; regs[i].wasdirty&=~(1LL<>16)!=0x1000) { regmap_pre[i+2][hr]=f_regmap[hr]; regs[i+2].wasdirty&=~(1LL<>16)!=0x1000) { regmap_pre[k+2][hr]=f_regmap[hr]; regs[k+2].wasdirty&=~(1LL< %x",start+k*4,start+j*4); } } else { regmap_pre[k+1][hr]=f_regmap[hr]; regs[k+1].wasdirty&=~(1LL<=0) break; if(get_reg(regs[j].regmap,f_regmap[hr])>=0) { //DebugMessage(M64MSG_VERBOSE, "no-match due to different register"); break; } if((regs[j+1].is32&(1LL<<(f_regmap[hr]&63)))!=(regs[j].is32&(1LL<<(f_regmap[hr]&63)))) { //DebugMessage(M64MSG_VERBOSE, "32/64 mismatch %x %d",start+j*4,hr); break; } if(itype[j]==UJUMP||itype[j]==RJUMP||(source[j]>>16)==0x1000) { // Stop on unconditional branch break; } if(itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) { if(branch_regs[j].regmap[hr]>=0) break; if(ooo[j]) { if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1]) break; }else{ if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1]) break; } if(get_reg(branch_regs[j].regmap,f_regmap[hr])>=0) { //DebugMessage(M64MSG_VERBOSE, "no-match due to different register (branch)"); break; } } if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) { //DebugMessage(M64MSG_VERBOSE, "No free regs for store %x",start+j*4); break; } if(f_regmap[hr]>=64) { if(regs[j].is32&(1LL<<(f_regmap[hr]&63))) { break; } else { if(get_reg(regs[j].regmap,f_regmap[hr]&63)<0) { break; } } } } } } } } }else{ // Non branch or undetermined branch target for(hr=0;hr64) { if(!((regs[i].dirty>>hr)&1)) f_regmap[hr]=regs[i].regmap[hr]; } else if(regs[i].regmap[hr]>=0) { if(f_regmap[hr]!=regs[i].regmap[hr]) { // dealloc old register int n; for(n=0;n %x",start+k*4,start+j*4); while(ki&&f_regmap[HOST_CCREG]==CCREG) { //DebugMessage(M64MSG_VERBOSE, "Extend backwards"); int k; k=i; while(regs[k-1].regmap[HOST_CCREG]==-1) { if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { //DebugMessage(M64MSG_VERBOSE, "no free regs for store %x",start+(k-1)*4); break; } k--; } if(regs[k-1].regmap[HOST_CCREG]==CCREG) { //DebugMessage(M64MSG_VERBOSE, "Extend CC, %x ->",start+k*4); while(k<=i) { regs[k].regmap_entry[HOST_CCREG]=CCREG; regs[k].regmap[HOST_CCREG]=CCREG; regmap_pre[k+1][HOST_CCREG]=CCREG; regs[k+1].wasdirty|=1LL<",start+k*4); } } } if(itype[i]!=STORE&&itype[i]!=STORELR&&itype[i]!=C1LS&&itype[i]!=SHIFT&& itype[i]!=NOP&&itype[i]!=MOV&&itype[i]!=ALU&&itype[i]!=SHIFTIMM&& itype[i]!=IMM16&&itype[i]!=LOAD&&itype[i]!=COP1&&itype[i]!=FLOAT&& itype[i]!=FCONV&&itype[i]!=FCOMP) { memcpy(f_regmap,regs[i].regmap,sizeof(f_regmap)); } } } // Cache memory offset or tlb map pointer if a register is available #ifndef HOST_IMM_ADDR32 #ifndef RAM_OFFSET if(using_tlb) #endif { int earliest_available[HOST_REGS]; int loop_start[HOST_REGS]; int score[HOST_REGS]; int end[HOST_REGS]; int reg=using_tlb?MMREG:ROREG; // Init for(hr=0;hr=0) { score[hr]=0;earliest_available[hr]=i+1; loop_start[hr]=MAXBLOCK; } if(itype[i]==UJUMP||itype[i]==RJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { if(branch_regs[i].regmap[hr]>=0) { score[hr]=0;earliest_available[hr]=i+2; loop_start[hr]=MAXBLOCK; } } } // No register allocations after unconditional jumps if(itype[i]==UJUMP||itype[i]==RJUMP||(source[i]>>16)==0x1000) { for(hr=0;hr=0) break; if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) { if(branch_regs[j].regmap[hr]>=0) break; if(ooo[j]) { if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1]) break; }else{ if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1]) break; } } else if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) break; if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==CJUMP||itype[j]==SJUMP||itype[j]==FJUMP) { int t=(ba[j]-start)>>2; if(t=earliest_available[hr]) { if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=31)) { // call/ret assumes no registers allocated // Score a point for hoisting loop invariant if(t>16)==0x1000) { // Stop on unconditional branch break; } else if(itype[j]==LOAD||itype[j]==LOADLR|| itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS) { score[hr]++; end[hr]=j; } } } } // Find highest score and allocate that register int maxscore=0; for(hr=0;hrscore[maxscore]) { maxscore=hr; //DebugMessage(M64MSG_VERBOSE, "highest score: %d %d (%x->%x)",score[hr],hr,start+i*4,start+end[hr]*4); } } } if(score[maxscore]>1) { if(i=0) {DebugMessage(M64MSG_ERROR, "oops: %x %x was %d=%d",loop_start[maxscore]*4+start,j*4+start,maxscore,regs[j].regmap[maxscore]);} assert(regs[j].regmap[maxscore]<0); if(j>loop_start[maxscore]) regs[j].regmap_entry[maxscore]=reg; regs[j].regmap[maxscore]=reg; regs[j].dirty&=~(1LL<>16)!=0x1000) { regmap_pre[j+2][maxscore]=reg; regs[j+2].wasdirty&=~(1LL<>2; if(t==loop_start[maxscore]) { if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=31)) // call/ret assumes no registers allocated regs[t].regmap_entry[maxscore]=reg; } } else { if(j<1||(itype[j-1]!=RJUMP&&itype[j-1]!=UJUMP&&itype[j-1]!=CJUMP&&itype[j-1]!=SJUMP&&itype[j-1]!=FJUMP)) { regmap_pre[j+1][maxscore]=reg; regs[j+1].wasdirty&=~(1LL<=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0&&free_regs>0) { regs[i].regmap[hr]=regs[i+1].regmap[hr]; regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; regs[i].isconst&=~(1<=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0&&free_regs>0) { regs[i].regmap[hr]=regs[i+1].regmap[hr]; regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; regs[i].isconst&=~(1<=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0&&free_regs>0) { regs[i].regmap[hr]=rs1[i+1]; regmap_pre[i+1][hr]=rs1[i+1]; regs[i+1].regmap_entry[hr]=rs1[i+1]; regs[i].isconst&=~(1<=0) { int sr=get_reg(regs[i+1].regmap,rs1[i+1]); if(sr>=0&&((regs[i+1].wasconst>>sr)&1)) { int nr; if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0&&free_regs>0) { regs[i].regmap[hr]=MGEN1+((i+1)&1); regmap_pre[i+1][hr]=MGEN1+((i+1)&1); regs[i+1].regmap_entry[hr]=MGEN1+((i+1)&1); regs[i].isconst&=~(1<=0&&free_regs>0) { // move it to another register regs[i+1].regmap[hr]=-1; regmap_pre[i+2][hr]=-1; regs[i+1].regmap[nr]=TLREG; regmap_pre[i+2][nr]=TLREG; regs[i].regmap[nr]=MGEN1+((i+1)&1); regmap_pre[i+1][nr]=MGEN1+((i+1)&1); regs[i+1].regmap_entry[nr]=MGEN1+((i+1)&1); regs[i].isconst&=~(1<=0); if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0&&free_regs>0) { regs[i].regmap[hr]=rs1[i+1]; regmap_pre[i+1][hr]=rs1[i+1]; regs[i+1].regmap_entry[hr]=rs1[i+1]; regs[i].isconst&=~(1<=0); if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0&&free_regs>0) { regs[i].regmap[hr]=rs1[i+1]; regmap_pre[i+1][hr]=rs1[i+1]; regs[i+1].regmap_entry[hr]=rs1[i+1]; regs[i].isconst&=~(1<=0&&free_regs>0) { // move it to another register regs[i+1].regmap[hr]=-1; regmap_pre[i+2][hr]=-1; regs[i+1].regmap[nr]=FTEMP; regmap_pre[i+2][nr]=FTEMP; regs[i].regmap[nr]=rs1[i+1]; regmap_pre[i+1][nr]=rs1[i+1]; regs[i+1].regmap_entry[nr]=rs1[i+1]; regs[i].isconst&=~(1<=0&®s[i].regmap[hr]<0&&free_regs>0) { int rs=get_reg(regs[i+1].regmap,rs1[i+1]); if(rs>=0&&((regs[i+1].wasconst>>rs)&1)) { regs[i].regmap[hr]=AGEN1+((i+1)&1); regmap_pre[i+1][hr]=AGEN1+((i+1)&1); regs[i+1].regmap_entry[hr]=AGEN1+((i+1)&1); regs[i].isconst&=~(1<=0;i--) { int hr; if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { if(ba[i]=(start+slen*4)) { // Branch out of this block, don't need anything r32=0; } else { // Internal branch // Need whatever matches the target // (and doesn't get overwritten by the delay slot instruction) r32=0; int t=(ba[i]-start)>>2; if(ba[i]>start+i*4) { // Forward branch if(!(requires_32bit[t]&~regs[i].was32)) r32|=requires_32bit[t]&(~(1LL<>16)!=0x1000) { if(i0) { if((regs[i].was32>>us1[i+1])&1) r32|=1LL<0) { if((regs[i].was32>>us2[i+1])&1) r32|=1LL<>dep1[i+1])&1)) { if((regs[i].was32>>dep1[i+1])&1) r32|=1LL<>dep2[i+1])&1)) { if((regs[i].was32>>dep2[i+1])&1) r32|=1LL<0) { if((regs[i].was32>>us1[i])&1) r32|=1LL<0) { if((regs[i].was32>>us2[i])&1) r32|=1LL<>dep1[i])&1)) { if((regs[i].was32>>dep1[i])&1) r32|=1LL<>dep2[i])&1)) { if((regs[i].was32>>dep2[i])&1) r32|=1LL<0&®s[i].regmap_entry[hr]<64) { if((regs[i].was32>>regs[i].regmap_entry[hr])&(regs[i].wasdirty>>hr)&1) { if(!((unneeded_reg_upper[i]>>regs[i].regmap_entry[hr])&1)) requires_32bit[i]|=1LL<>16)!=0x1000)) { wb_sx(regmap_pre[i],regs[i].regmap_entry,regs[i].wasdirty,is32_pre,regs[i].was32, unneeded_reg[i],unneeded_reg_upper[i]); wb_valid(regmap_pre[i],regs[i].regmap_entry,dirty_pre,regs[i].wasdirty,is32_pre, unneeded_reg[i],unneeded_reg_upper[i]); } if((itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP)&&!likely[i]) { is32_pre=branch_regs[i].is32; dirty_pre=branch_regs[i].dirty; }else{ is32_pre=regs[i].is32; dirty_pre=regs[i].dirty; } #endif // write back if(i<2||(itype[i-2]!=UJUMP&&itype[i-2]!=RJUMP&&(source[i-2]>>16)!=0x1000)) { wb_invalidate(regmap_pre[i],regs[i].regmap_entry,regs[i].wasdirty,regs[i].was32, unneeded_reg[i],unneeded_reg_upper[i]); loop_preload(regmap_pre[i],regs[i].regmap_entry); } // branch target entry point instr_addr[i]=(uintptr_t)out; assem_debug("<->"); // load regs if(regs[i].regmap_entry[HOST_CCREG]==CCREG&®s[i].regmap[HOST_CCREG]!=CCREG) wb_register(CCREG,regs[i].regmap_entry,regs[i].wasdirty,regs[i].was32); load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i],rs2[i]); address_generation(i,®s[i],regs[i].regmap_entry); load_consts(regmap_pre[i],regs[i].regmap,regs[i].was32,i); if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { // Load the delay slot registers if necessary if(rs1[i+1]!=rs1[i]&&rs1[i+1]!=rs2[i]) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i+1],rs1[i+1]); if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i]) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs2[i+1],rs2[i+1]); if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP); } else if(i+1>16)==0x1000) literal_pool(1024); else literal_pool_jumpover(256); } } //assert(itype[i-2]==UJUMP||itype[i-2]==RJUMP||(source[i-2]>>16)==0x1000); // If the block did not end with an unconditional branch, // add a jump to the next instruction. if(i>1) { if(itype[i-2]!=UJUMP&&itype[i-2]!=RJUMP&&(source[i-2]>>16)!=0x1000&&itype[i-1]!=SPAN) { assert(itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP&&itype[i-1]!=FJUMP); assert(i==slen); if(itype[i-2]!=CJUMP&&itype[i-2]!=SJUMP&&itype[i-2]!=FJUMP) { store_regs_bt(regs[i-1].regmap,regs[i-1].is32,regs[i-1].dirty,start+i*4); if(regs[i-1].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); } else if(!likely[i-2]) { store_regs_bt(branch_regs[i-2].regmap,branch_regs[i-2].is32,branch_regs[i-2].dirty,start+i*4); assert(branch_regs[i-2].regmap[HOST_CCREG]==CCREG); } else { store_regs_bt(regs[i-2].regmap,regs[i-2].is32,regs[i-2].dirty,start+i*4); assert(regs[i-2].regmap[HOST_CCREG]==CCREG); } add_to_linker((intptr_t)out,start+i*4,0); emit_jmp(0); } } else { assert(i>0); assert(itype[i-1]!=UJUMP&&itype[i-1]!=CJUMP&&itype[i-1]!=SJUMP&&itype[i-1]!=RJUMP&&itype[i-1]!=FJUMP); store_regs_bt(regs[i-1].regmap,regs[i-1].is32,regs[i-1].dirty,start+i*4); if(regs[i-1].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); add_to_linker((intptr_t)out,start+i*4,0); emit_jmp(0); } // TODO: delay slot stubs? // Stubs for(i=0;i %8x",link_addr[i][0],link_addr[i][1]); literal_pool(64); if(!link_addr[i][2]) { void *stub=out; void *addr=check_addr(link_addr[i][1]); emit_extjump(link_addr[i][0],link_addr[i][1]); #ifndef DISABLE_BLOCK_LINKING #if NEW_DYNAREC==NEW_DYNAREC_ARM64 //TODO: Avoid disabling link between blocks for conditional branches u_char *ptr=(u_char *)link_addr[i][0]; if(addr&&((ptr[3]&0xfc)==0x14)) { #else if(addr) { #endif set_jump_target(link_addr[i][0],(intptr_t)addr); add_link(link_addr[i][1],stub); } else #endif set_jump_target(link_addr[i][0],(intptr_t)stub); } else { // Internal branch int target=(link_addr[i][1]-start)>>2; assert(target>=0&&target>1); //#else set_jump_target(link_addr[i][0],instr_addr[target]); //#endif } } // External Branch Targets (jump_in) for(i=0;i>12; u_int vpage=page; if(page>262143&&g_dev.r4300.cp0.tlb.LUT_r[vaddr>>12]) page=(g_dev.r4300.cp0.tlb.LUT_r[page^0x80000]^0x80000000)>>12; if(page>2048) page=2048+(page&2047); if(vpage>262143&&g_dev.r4300.cp0.tlb.LUT_r[vaddr>>12]) vpage&=2047; // jump_dirty uses a hash of the virtual address instead if(vpage>2048) vpage=2048+(vpage&2047); literal_pool(256); //if(!(is32[i]&(~unneeded_reg_upper[i])&~(1LL<clean_addr=(void*)entry_point; head=ll_add(jump_in+page,vaddr,(void *)entry_point,(void *)entry_point,start,copy,slen*4); // If there was an existing entry in the hash table, // replace it with the new address. // Don't add new entries. We'll insert the // ones that actually get used in check_addr(). struct ll_entry **ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]&&ht_bin[0]->vaddr==vaddr) { ht_bin[0]=head; } if(ht_bin[1]&&ht_bin[1]->vaddr==vaddr) { ht_bin[1]=head; } } else { u_int r=requires_32bit[i]|!!(requires_32bit[i]>>32); assem_debug("%8x (%d) <- %8x",instr_addr[i],i,start+i*4); assem_debug("jump_in: %x (restricted - %x)",start+i*4,r); //intptr_t entry_point=(intptr_t)out; ////assem_debug("entry_point: %x",entry_point); //load_regs_entry(i); //if(entry_point==(intptr_t)out) // entry_point=instr_addr[i]; //else // emit_jmp(instr_addr[i]); //struct ll_entry *head=ll_add_32(jump_dirty+vpage,vaddr,r,(void *)entry_point,NULL,start,copy,slen*4); struct ll_entry *head=ll_add_32(jump_dirty+vpage,vaddr,r,(void *)out,NULL,start,copy,slen*4); dirty_entry_count++; intptr_t entry_point=do_dirty_stub(i,head); head->clean_addr=(void*)entry_point; (void)ll_add_32(jump_in+page,vaddr,r,(void *)entry_point,(void *)entry_point,start,copy,slen*4); } } } } // Write out the literal pool if necessary literal_pool(0); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK // Align code if(((uintptr_t)out)&7) emit_addnop(13); #endif assert((uintptr_t)out-beginning= NEW_DYNAREC_ARM intptr_t beginning_rx=((intptr_t)beginning-(intptr_t)base_addr)+(intptr_t)base_addr_rx; intptr_t out_rx=((intptr_t)out-(intptr_t)base_addr)+(intptr_t)base_addr_rx; cache_flush((char *)beginning_rx,(char *)out_rx); #endif // If we're within 256K of the end of the buffer, // start over from the beginning. (Is 256K enough?) if(out > (u_char *)((u_char *)base_addr+(1<>12;i<=(int)((start+slen*4-4)>>12);i++) { g_dev.r4300.cached_interp.invalid_code[i]=0; g_dev.r4300.new_dynarec_hot_state.memory_map[i]|=WRITE_PROTECT; if((signed int)start>=(signed int)0xC0000000) { assert(using_tlb); assert(g_dev.r4300.new_dynarec_hot_state.memory_map[i]!=-1); j=(((uintptr_t)i<<12)+(uintptr_t)(g_dev.r4300.new_dynarec_hot_state.memory_map[i]<<2)-(uintptr_t)g_dev.rdram.dram+(uintptr_t)0x80000000)>>12; g_dev.r4300.cached_interp.invalid_code[j]=0; g_dev.r4300.new_dynarec_hot_state.memory_map[j]|=WRITE_PROTECT; //DebugMessage(M64MSG_VERBOSE, "write protect physical page: %x (virtual %x)",j<<12,start); } } /* Pass 10 - Free memory by expiring oldest blocks */ int end=((((intptr_t)out-(intptr_t)base_addr)>>(TARGET_SIZE_2-16))+16384)&65535; while(expirep!=end) { int shift=TARGET_SIZE_2-3; // Divide into 8 blocks intptr_t base=(intptr_t)base_addr+((expirep>>13)<>11)&3) { case 0: // Clear jump_in and jump_dirty ll_remove_matching_addrs(jump_in+(expirep&2047),base,shift); ll_remove_matching_addrs(jump_dirty+(expirep&2047),base,shift); ll_remove_matching_addrs(jump_in+2048+(expirep&2047),base,shift); ll_remove_matching_addrs(jump_dirty+2048+(expirep&2047),base,shift); break; case 1: // Clear pointers ll_kill_pointers(jump_out[expirep&2047],base,shift); ll_kill_pointers(jump_out[(expirep&2047)+2048],base,shift); break; case 2: // Clear hash table for(i=0;i<32;i++) { struct ll_entry **ht_bin=hash_table[((expirep&2047)<<5)+i]; if(ht_bin[1]&&((((uintptr_t)ht_bin[1]->addr-(uintptr_t)base_addr)>>shift)==((base-(uintptr_t)base_addr)>>shift) || (((uintptr_t)ht_bin[1]->addr-(uintptr_t)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((base-(uintptr_t)base_addr)>>shift))) { inv_debug("EXP: Remove hash %x -> %x\n",ht_bin[1]->vaddr,ht_bin[1]->addr); ht_bin[1]=NULL; } if(ht_bin[0]&&((((uintptr_t)ht_bin[0]->addr-(uintptr_t)base_addr)>>shift)==((base-(uintptr_t)base_addr)>>shift) || (((uintptr_t)ht_bin[0]->addr-(uintptr_t)base_addr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==((base-(uintptr_t)base_addr)>>shift))) { inv_debug("EXP: Remove hash %x -> %x\n",ht_bin[0]->vaddr,ht_bin[0]->addr); ht_bin[0]=ht_bin[1]; ht_bin[1]=NULL; } } break; case 3: // Clear jump_out #if NEW_DYNAREC >= NEW_DYNAREC_ARM if((expirep&2047)==0) do_clear_cache(); #endif ll_remove_matching_addrs(jump_out+(expirep&2047),base,shift); ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base,shift); break; } expirep=(expirep+1)&65535; } return 0; } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/new_dynarec.h000066400000000000000000000067401464506436200252200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - new_dynarec.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_NEW_DYNAREC_H #define M64P_DEVICE_R4300_NEW_DYNAREC_H #include "device/r4300/recomp_types.h" /* for precomp_instr */ #include #include #define NEW_DYNAREC_X86 1 #define NEW_DYNAREC_X64 2 #define NEW_DYNAREC_ARM 3 #define NEW_DYNAREC_ARM64 4 #define WRITE_PROTECT ((uintptr_t)1<<((sizeof(uintptr_t)<<3)-2)) struct r4300_core; /* This struct contains "hot" variables used by the new_dynarec * * For the ARM version, care has been taken to place struct members at offsets within LDR/STR offsets ranges. * TODO: add static_asserts to verify that offsets are within LDR/STR offsets ranges. */ struct new_dynarec_hot_state { #ifdef NEW_DYNAREC /* 0-6: used by dynarec to push/pop caller-saved register (r0-r3, r12) and possibly lr (see invalidate_addr) 7-15: saved_context*/ #if (NEW_DYNAREC == NEW_DYNAREC_ARM64) || (NEW_DYNAREC == NEW_DYNAREC_X64) uint64_t dynarec_local[32]; #else uint32_t dynarec_local[16]; #endif int cycle_count; int pending_exception; int pcaddr; int stop; char* invc_ptr; uint32_t address; uint64_t rdword; uint64_t wdword; uint32_t wword; uint32_t cp1_fcr0; uint32_t cp1_fcr31; int64_t regs[32]; int64_t hi; int64_t lo; uint32_t cp0_regs[32]; uint64_t cp0_latch; float* cp1_regs_simple[32]; double* cp1_regs_double[32]; uint64_t cp2_latch; uint32_t rounding_modes[4]; int branch_target; struct precomp_instr* pc; struct precomp_instr fake_pc; int64_t rs; int64_t rt; int64_t rd; intptr_t ram_offset; uintptr_t mini_ht[32][2]; uintptr_t memory_map[1048576]; #else char dummy; #endif }; extern unsigned int stop_after_jal; extern unsigned int using_tlb; void invalidate_cached_code_new_dynarec(struct r4300_core* r4300, uint32_t address, size_t size); void new_dynarec_init(void); void new_dyna_start(void); void new_dynarec_cleanup(void); #endif /* M64P_DEVICE_R4300_NEW_DYNAREC_H */ mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/recomp_dbg.c000066400000000000000000001462601464506436200250200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - recomp_dbg.c * * Copyright (C) 2009-2018 Gillou68310 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define RECOMP_DBG #if RECOMPILER_DEBUG == 1 //x86 #if NEW_DYNAREC != 1 //x86 #error x86 dynarec debug only available on x86 #endif #elif RECOMPILER_DEBUG == 2 //x64 #if NEW_DYNAREC != 2 //x64 #error x64 dynarec debug only available on x64 #endif #elif RECOMPILER_DEBUG == 3 //ARM #if NEW_DYNAREC != 1 //x86 #error arm dynarec debug only available on x86 #endif #elif RECOMPILER_DEBUG == 4 //ARM64 #if NEW_DYNAREC != 2 //x64 #error arm64 dynarec debug only available on x64 #endif #endif #undef NEW_DYNAREC #define NEW_DYNAREC RECOMPILER_DEBUG /* Rename non-static variables */ #define base_addr recomp_dbg_base_addr #define base_addr_rx recomp_dbg_base_addr_rx #define out recomp_dbg_out #define using_tlb recomp_dbg_using_tlb #define stop_after_jal recomp_dbg_stop_after_jal /* Rename non-static functions */ #define verify_dirty recomp_dbg_verify_dirty #define clean_blocks recomp_dbg_clean_blocks #define get_addr recomp_dbg_get_addr #define get_addr_32 recomp_dbg_get_addr_32 #define get_addr_ht recomp_dbg_get_addr_ht #define invalidate_all_pages recomp_dbg_invalidate_all_pages #define invalidate_block recomp_dbg_invalidate_block #define invalidate_cached_code_new_dynarec recomp_dbg_invalidate_cached_code_new_dynarec #define new_dynarec_cleanup recomp_dbg_new_dynarec_cleanup #define new_dynarec_init recomp_dbg_new_dynarec_init #define new_recompile_block recomp_dbg_new_recompile_block #define ERET_new recomp_dbg_ERET_new #define dynarec_gen_interrupt recomp_dbg_dynarec_gen_interrupt #define SYSCALL_new recomp_dbg_SYSCALL_new #define cop1_unusable recomp_dbg_cop1_unusable #define dynamic_linker recomp_dbg_dynamic_linker #define dynamic_linker_ds recomp_dbg_dynamic_linker_ds #if RECOMPILER_DEBUG == 3 //ARM static void jump_vaddr_r0(void){} static void jump_vaddr_r1(void){} static void jump_vaddr_r2(void){} static void jump_vaddr_r3(void){} static void jump_vaddr_r4(void){} static void jump_vaddr_r5(void){} static void jump_vaddr_r6(void){} static void jump_vaddr_r7(void){} static void jump_vaddr_r8(void){} static void jump_vaddr_r9(void){} static void jump_vaddr_r10(void){} static void jump_vaddr_r12(void){} static void invalidate_addr_r0(void){} static void invalidate_addr_r1(void){} static void invalidate_addr_r2(void){} static void invalidate_addr_r3(void){} static void invalidate_addr_r4(void){} static void invalidate_addr_r5(void){} static void invalidate_addr_r6(void){} static void invalidate_addr_r7(void){} static void invalidate_addr_r8(void){} static void invalidate_addr_r9(void){} static void invalidate_addr_r10(void){} static void invalidate_addr_r12(void){} static void __clear_cache(char* begin, char *end){} #include "arm/arm_cpu_features.h" /* arm_cpu_features.c */ static arm_cpu_features_t arm_cpu_features; static void detect_arm_cpu_features(void){} static void print_arm_cpu_features(void){} #elif RECOMPILER_DEBUG == 4 //ARM64 void jump_vaddr_x0(void){} void jump_vaddr_x1(void){} void jump_vaddr_x2(void){} void jump_vaddr_x3(void){} void jump_vaddr_x4(void){} void jump_vaddr_x5(void){} void jump_vaddr_x6(void){} void jump_vaddr_x7(void){} void jump_vaddr_x8(void){} void jump_vaddr_x9(void){} void jump_vaddr_x10(void){} void jump_vaddr_x11(void){} void jump_vaddr_x12(void){} void jump_vaddr_x13(void){} void jump_vaddr_x14(void){} void jump_vaddr_x15(void){} void jump_vaddr_x16(void){} void jump_vaddr_x17(void){} void jump_vaddr_x19(void){} void jump_vaddr_x21(void){} void jump_vaddr_x22(void){} void jump_vaddr_x23(void){} void jump_vaddr_x24(void){} void jump_vaddr_x25(void){} void jump_vaddr_x26(void){} void jump_vaddr_x27(void){} void jump_vaddr_x28(void){} static void __clear_cache(char* begin, char *end){} #endif static int disasm_block[] = {0xa4000040}; #include "osal/preproc.h" //for ALIGN ALIGN(4096, static char recomp_dbg_extra_memory[33554432]); // Recompile new_dynarec.c with the above redefinitions #include "new_dynarec.c" #include #include #include "osal/files.h" #if RECOMPILER_DEBUG == NEW_DYNAREC_X86 #define ARCHITECTURE CS_ARCH_X86 #define MODE CS_MODE_32 #define INSTRUCTION instr[i].detail->x86 #define CALL_INST 0x38 #define BRANCH_INST 0x10a #define ARCH_NAME "x86" #elif RECOMPILER_DEBUG == NEW_DYNAREC_X64 #define ARCHITECTURE CS_ARCH_X86 #define MODE CS_MODE_64 #define INSTRUCTION instr[i].detail->x86 #define CALL_INST 0x38 #define BRANCH_INST 0x10a #define ARCH_NAME "x64" #elif RECOMPILER_DEBUG == NEW_DYNAREC_ARM #define ARCHITECTURE CS_ARCH_ARM #define MODE CS_MODE_LITTLE_ENDIAN #define INSTRUCTION instr[i].detail->arm #define FP_REGISTER 0x4d #define CALL_INST 0xd #define BRANCH_INST 0x11 #define ARCH_NAME "ARM" #elif RECOMPILER_DEBUG == NEW_DYNAREC_ARM64 #define ARCHITECTURE CS_ARCH_ARM64 #define MODE CS_MODE_LITTLE_ENDIAN #define INSTRUCTION instr[i].detail->arm64 #define FP_REGISTER 0x1 #define CALL_INST 0x15 #define BRANCH_INST 0x10 #define ARCH_NAME "ARM64" #endif typedef struct{ intptr_t addr; int32_t size; char * name; }Variable_t; static Variable_t var[] = { {(intptr_t)NULL /*RDRAM*/, 0, "rdram - 0x80000000"}, {(intptr_t)g_dev.r4300.cached_interp.invalid_code, sizeof(g_dev.r4300.cached_interp.invalid_code), "invalid_code"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.dynarec_local, sizeof(g_dev.r4300.new_dynarec_hot_state.dynarec_local), "dynarec_local"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cycle_count, sizeof(g_dev.r4300.new_dynarec_hot_state.cycle_count), "cycle_count"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pending_exception, sizeof(g_dev.r4300.new_dynarec_hot_state.pending_exception), "pending_exception"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pcaddr, sizeof(g_dev.r4300.new_dynarec_hot_state.pcaddr), "pcaddr"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.stop, sizeof(g_dev.r4300.new_dynarec_hot_state.stop), "r4300_stop"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.invc_ptr, sizeof(g_dev.r4300.new_dynarec_hot_state.invc_ptr), "invc_ptr"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.address, sizeof(g_dev.r4300.new_dynarec_hot_state.address), "mem_address"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.rdword, sizeof(g_dev.r4300.new_dynarec_hot_state.rdword), "mem_rdword"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wdword, sizeof(g_dev.r4300.new_dynarec_hot_state.wdword), "mem_wdword"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.wword, sizeof(g_dev.r4300.new_dynarec_hot_state.wword), "mem_wword"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fcr0, sizeof(g_dev.r4300.new_dynarec_hot_state.fcr0), "cp1_fcr0"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fcr31, sizeof(g_dev.r4300.new_dynarec_hot_state.fcr31), "cp1_fcr31"}, //{(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs, sizeof(g_dev.r4300.new_dynarec_hot_state.regs), "r4300_regs"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[0], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[0]), "r4300_regs[0]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[1], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[1]), "r4300_regs[1]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[2], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[2]), "r4300_regs[2]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[3], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[3]), "r4300_regs[3]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[4], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[4]), "r4300_regs[4]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[5], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[5]), "r4300_regs[5]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[6], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[6]), "r4300_regs[6]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[7], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[7]), "r4300_regs[7]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[8], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[8]), "r4300_regs[8]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[9], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[9]), "r4300_regs[9]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[10], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[10]), "r4300_regs[10]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[11], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[11]), "r4300_regs[11]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[12], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[12]), "r4300_regs[12]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[13], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[13]), "r4300_regs[13]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[14], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[14]), "r4300_regs[14]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[15], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[15]), "r4300_regs[15]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[16], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[16]), "r4300_regs[16]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[17], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[17]), "r4300_regs[17]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[18], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[18]), "r4300_regs[18]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[19], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[19]), "r4300_regs[19]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[20], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[20]), "r4300_regs[20]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[21], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[21]), "r4300_regs[21]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[22], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[22]), "r4300_regs[22]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[23], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[23]), "r4300_regs[23]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[24], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[24]), "r4300_regs[24]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[25], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[25]), "r4300_regs[25]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[26], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[26]), "r4300_regs[26]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[27], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[27]), "r4300_regs[27]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[28], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[28]), "r4300_regs[28]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[29], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[29]), "r4300_regs[29]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[30], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[30]), "r4300_regs[30]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.regs[31], sizeof(g_dev.r4300.new_dynarec_hot_state.regs[31]), "r4300_regs[31]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.hi, sizeof(g_dev.r4300.new_dynarec_hot_state.hi), "r4300_hi"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.lo, sizeof(g_dev.r4300.new_dynarec_hot_state.lo), "r4300_lo"}, //{(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs, sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs), "cp0_regs"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[0], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[0]), "cp0_regs[0]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[1], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[1]), "cp0_regs[1]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[2], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[2]), "cp0_regs[2]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[3], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[3]), "cp0_regs[3]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[4], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[4]), "cp0_regs[4]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[5], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[5]), "cp0_regs[5]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[6], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[6]), "cp0_regs[6]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[7], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[7]), "cp0_regs[7]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[8], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[8]), "cp0_regs[8]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[9], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[9]), "cp0_regs[9]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[10], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[10]), "cp0_regs[10]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[11], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[11]), "cp0_regs[11]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[12], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[12]), "cp0_regs[12]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[13], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[13]), "cp0_regs[13]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[14], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[14]), "cp0_regs[14]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[15], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[15]), "cp0_regs[15]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[16], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[16]), "cp0_regs[16]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[17], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[17]), "cp0_regs[17]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[18], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[18]), "cp0_regs[18]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[19], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[19]), "cp0_regs[19]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[20], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[20]), "cp0_regs[20]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[21], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[21]), "cp0_regs[21]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[22], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[22]), "cp0_regs[22]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[23], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[23]), "cp0_regs[23]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[24], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[24]), "cp0_regs[24]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[25], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[25]), "cp0_regs[25]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[26], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[26]), "cp0_regs[26]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[27], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[27]), "cp0_regs[27]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[28], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[28]), "cp0_regs[28]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[29], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[29]), "cp0_regs[29]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[30], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[30]), "cp0_regs[30]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[31], sizeof(g_dev.r4300.new_dynarec_hot_state.cp0_regs[31]), "cp0_regs[31]"}, //{(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple, sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple), "cp1_regs_simple"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[0], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[0]), "cp1_regs_simple[0]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[1], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[1]), "cp1_regs_simple[1]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[2], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[2]), "cp1_regs_simple[2]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[3], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[3]), "cp1_regs_simple[3]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[4], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[4]), "cp1_regs_simple[4]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[5], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[5]), "cp1_regs_simple[5]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[6], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[6]), "cp1_regs_simple[6]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[7], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[7]), "cp1_regs_simple[7]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[8], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[8]), "cp1_regs_simple[8]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[9], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[9]), "cp1_regs_simple[9]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[10], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[10]), "cp1_regs_simple[10]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[11], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[11]), "cp1_regs_simple[11]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[12], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[12]), "cp1_regs_simple[12]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[13], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[13]), "cp1_regs_simple[13]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[14], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[14]), "cp1_regs_simple[14]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[15], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[15]), "cp1_regs_simple[15]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[16], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[16]), "cp1_regs_simple[16]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[17], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[17]), "cp1_regs_simple[17]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[18], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[18]), "cp1_regs_simple[18]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[19], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[19]), "cp1_regs_simple[19]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[20], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[20]), "cp1_regs_simple[20]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[21], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[21]), "cp1_regs_simple[21]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[22], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[22]), "cp1_regs_simple[22]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[23], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[23]), "cp1_regs_simple[23]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[24], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[24]), "cp1_regs_simple[24]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[25], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[25]), "cp1_regs_simple[25]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[26], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[26]), "cp1_regs_simple[26]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[27], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[27]), "cp1_regs_simple[27]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[28], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[28]), "cp1_regs_simple[28]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[29], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[29]), "cp1_regs_simple[29]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[30], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[30]), "cp1_regs_simple[30]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[31], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[31]), "cp1_regs_simple[31]"}, //{(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double, sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double), "cp1_regs_double"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[0], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[0]), "cp1_regs_double[0]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[1], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[1]), "cp1_regs_double[1]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[2], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[2]), "cp1_regs_double[2]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[3], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[3]), "cp1_regs_double[3]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[4], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[4]), "cp1_regs_double[4]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[5], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[5]), "cp1_regs_double[5]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[6], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[6]), "cp1_regs_double[6]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[7], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[7]), "cp1_regs_double[7]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[8], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[8]), "cp1_regs_double[8]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[9], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[9]), "cp1_regs_double[9]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[10], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[10]), "cp1_regs_double[10]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[11], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[11]), "cp1_regs_double[11]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[12], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[12]), "cp1_regs_double[12]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[13], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[13]), "cp1_regs_double[13]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[14], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[14]), "cp1_regs_double[14]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[15], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[15]), "cp1_regs_double[15]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[16], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[16]), "cp1_regs_double[16]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[17], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[17]), "cp1_regs_double[17]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[18], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[18]), "cp1_regs_double[18]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[19], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[19]), "cp1_regs_double[19]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[20], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[20]), "cp1_regs_double[20]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[21], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[21]), "cp1_regs_double[21]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[22], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[22]), "cp1_regs_double[22]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[23], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[23]), "cp1_regs_double[23]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[24], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[24]), "cp1_regs_double[24]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[25], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[25]), "cp1_regs_double[25]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[26], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[26]), "cp1_regs_double[26]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[27], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[27]), "cp1_regs_double[27]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[28], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[28]), "cp1_regs_double[28]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[29], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[29]), "cp1_regs_double[29]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[30], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[30]), "cp1_regs_double[30]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[31], sizeof(g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[31]), "cp1_regs_double[31]"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.rounding_modes, sizeof(g_dev.r4300.new_dynarec_hot_state.rounding_modes), "rounding_modes"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.branch_target, sizeof(g_dev.r4300.new_dynarec_hot_state.branch_target), "branch_target"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.pc, sizeof(g_dev.r4300.new_dynarec_hot_state.pc), "r4300_pc"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc, /*sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc)*/4, "fake_pc"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.rs, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.rs), "fake_pc.f.r.rs"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.rt, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.rt), "fake_pc.f.r.rt"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.rd, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.rd), "fake_pc.f.r.rd"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.sa, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.sa), "fake_pc.f.r.sa"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.nrd, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.r.nrd), "fake_pc.f.r.nrd"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.i.rs, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.i.rs), "fake_pc.f.i.rs"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.i.rt, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.i.rt), "fake_pc.f.i.rt"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.fake_pc.f.i.immediate, sizeof(g_dev.r4300.new_dynarec_hot_state.fake_pc.f.i.immediate), "fake_pc.f.i.immediate"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.rs, sizeof(g_dev.r4300.new_dynarec_hot_state.rs), "rs"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.rt, sizeof(g_dev.r4300.new_dynarec_hot_state.rt), "rt"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.rd, sizeof(g_dev.r4300.new_dynarec_hot_state.rd), "rd"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.ram_offset, sizeof(g_dev.r4300.new_dynarec_hot_state.ram_offset), "ram_offset"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.mini_ht, sizeof(g_dev.r4300.new_dynarec_hot_state.mini_ht), "mini_ht"}, {(intptr_t)&g_dev.r4300.new_dynarec_hot_state.memory_map, sizeof(g_dev.r4300.new_dynarec_hot_state.memory_map), "memory_map"}, {-1, -1, NULL} }; typedef struct{ intptr_t addr; char * name; }Function_t; static Function_t func[] = { {(intptr_t)MFC0_new, "MFC0"}, {(intptr_t)MTC0_new, "MTC0"}, {(intptr_t)cached_interp_TLBR, "TLBR"}, {(intptr_t)cached_interp_TLBP, "TLBP"}, {(intptr_t)cached_interp_MULT, "MULT"}, {(intptr_t)cached_interp_MULTU, "MULTU"}, {(intptr_t)cached_interp_DIV, "DIV"}, {(intptr_t)cached_interp_DIVU, "DIVU"}, {(intptr_t)cached_interp_DMULT, "DMULT"}, {(intptr_t)cached_interp_DMULTU, "DMULTU"}, {(intptr_t)cached_interp_DDIV, "DDIV"}, {(intptr_t)cached_interp_DDIVU, "DDIVU"}, #if RECOMPILER_DEBUG == NEW_DYNAREC_X86 || RECOMPILER_DEBUG == NEW_DYNAREC_X64 {(intptr_t)jump_vaddr_eax, "jump_vaddr_eax"}, {(intptr_t)jump_vaddr_ecx, "jump_vaddr_ecx"}, {(intptr_t)jump_vaddr_edx, "jump_vaddr_edx"}, {(intptr_t)jump_vaddr_ebx, "jump_vaddr_ebx"}, {(intptr_t)jump_vaddr_ebp, "jump_vaddr_ebp"}, {(intptr_t)jump_vaddr_edi, "jump_vaddr_edi"}, {(intptr_t)invalidate_block_eax, "invalidate_block_eax"}, {(intptr_t)invalidate_block_ecx, "invalidate_block_ecx"}, {(intptr_t)invalidate_block_edx, "invalidate_block_edx"}, {(intptr_t)invalidate_block_ebx, "invalidate_block_ebx"}, {(intptr_t)invalidate_block_ebp, "invalidate_block_ebp"}, {(intptr_t)invalidate_block_esi, "invalidate_block_esi"}, {(intptr_t)invalidate_block_edi, "invalidate_block_edi"}, #elif RECOMPILER_DEBUG == NEW_DYNAREC_ARM {(intptr_t)invalidate_addr, "invalidate_addr"}, {(intptr_t)jump_vaddr_r0, "jump_vaddr_r0"}, {(intptr_t)jump_vaddr_r1, "jump_vaddr_r1"}, {(intptr_t)jump_vaddr_r2, "jump_vaddr_r2"}, {(intptr_t)jump_vaddr_r3, "jump_vaddr_r3"}, {(intptr_t)jump_vaddr_r4, "jump_vaddr_r4"}, {(intptr_t)jump_vaddr_r5, "jump_vaddr_r5"}, {(intptr_t)jump_vaddr_r6, "jump_vaddr_r6"}, {(intptr_t)jump_vaddr_r7, "jump_vaddr_r7"}, {(intptr_t)jump_vaddr_r8, "jump_vaddr_r8"}, {(intptr_t)jump_vaddr_r9, "jump_vaddr_r9"}, {(intptr_t)jump_vaddr_r10, "jump_vaddr_r10"}, {(intptr_t)jump_vaddr_r12, "jump_vaddr_r12"}, {(intptr_t)invalidate_addr_r0," invalidate_addr_r0"}, {(intptr_t)invalidate_addr_r1," invalidate_addr_r1"}, {(intptr_t)invalidate_addr_r2," invalidate_addr_r2"}, {(intptr_t)invalidate_addr_r3," invalidate_addr_r3"}, {(intptr_t)invalidate_addr_r4," invalidate_addr_r4"}, {(intptr_t)invalidate_addr_r5," invalidate_addr_r5"}, {(intptr_t)invalidate_addr_r6," invalidate_addr_r6"}, {(intptr_t)invalidate_addr_r7," invalidate_addr_r7"}, {(intptr_t)invalidate_addr_r8," invalidate_addr_r8"}, {(intptr_t)invalidate_addr_r9," invalidate_addr_r9"}, {(intptr_t)invalidate_addr_r10," invalidate_addr_r10"}, {(intptr_t)invalidate_addr_r12," invalidate_addr_r12"}, #else //ARM64 {(intptr_t)invalidate_addr, "invalidate_addr"}, {(intptr_t)jump_vaddr_x0, "jump_vaddr_x0"}, {(intptr_t)jump_vaddr_x1, "jump_vaddr_x1"}, {(intptr_t)jump_vaddr_x2, "jump_vaddr_x2"}, {(intptr_t)jump_vaddr_x3, "jump_vaddr_x3"}, {(intptr_t)jump_vaddr_x4, "jump_vaddr_x4"}, {(intptr_t)jump_vaddr_x5, "jump_vaddr_x5"}, {(intptr_t)jump_vaddr_x6, "jump_vaddr_x6"}, {(intptr_t)jump_vaddr_x7, "jump_vaddr_x7"}, {(intptr_t)jump_vaddr_x8, "jump_vaddr_x8"}, {(intptr_t)jump_vaddr_x9, "jump_vaddr_x9"}, {(intptr_t)jump_vaddr_x10, "jump_vaddr_x10"}, {(intptr_t)jump_vaddr_x11, "jump_vaddr_x11"}, {(intptr_t)jump_vaddr_x12, "jump_vaddr_x12"}, {(intptr_t)jump_vaddr_x13, "jump_vaddr_x13"}, {(intptr_t)jump_vaddr_x14, "jump_vaddr_x14"}, {(intptr_t)jump_vaddr_x15, "jump_vaddr_x15"}, {(intptr_t)jump_vaddr_x16, "jump_vaddr_x16"}, {(intptr_t)jump_vaddr_x17, "jump_vaddr_x17"}, {(intptr_t)jump_vaddr_x19, "jump_vaddr_x19"}, {(intptr_t)jump_vaddr_x21, "jump_vaddr_x21"}, {(intptr_t)jump_vaddr_x22, "jump_vaddr_x22"}, {(intptr_t)jump_vaddr_x23, "jump_vaddr_x23"}, {(intptr_t)jump_vaddr_x24, "jump_vaddr_x24"}, {(intptr_t)jump_vaddr_x25, "jump_vaddr_x25"}, {(intptr_t)jump_vaddr_x26, "jump_vaddr_x26"}, {(intptr_t)jump_vaddr_x27, "jump_vaddr_x27"}, {(intptr_t)jump_vaddr_x28, "jump_vaddr_x28"}, #endif {(intptr_t)dyna_linker, "dyna_linker"}, {(intptr_t)dyna_linker_ds, "dyna_linker_ds"}, {(intptr_t)TLBWI_new, "TLBWI_new"}, {(intptr_t)TLBWR_new, "TLBWR_new"}, {(intptr_t)verify_code, "verify_code"}, {(intptr_t)cc_interrupt, "cc_interrupt"}, {(intptr_t)fp_exception, "fp_exception"}, {(intptr_t)jump_syscall, "jump_syscall"}, {(intptr_t)jump_eret, "jump_eret"}, {(intptr_t)do_interrupt, "do_interrupt"}, {(intptr_t)read_byte_new, "read_byte_new "}, {(intptr_t)read_hword_new, "read_hword_new"}, {(intptr_t)read_word_new, "read_word_new"}, {(intptr_t)read_dword_new, "read_dword_new"}, {(intptr_t)write_byte_new, "write_byte_new"}, {(intptr_t)write_hword_new, "write_hword_new"}, {(intptr_t)write_word_new, "write_word_new"}, {(intptr_t)write_dword_new, "write_dword_new"}, {(intptr_t)LWL_new, "LWL_new"}, {(intptr_t)LWR_new, "LWR_new"}, {(intptr_t)LDL_new, "LDL_new"}, {(intptr_t)LDR_new, "LDR_new"}, {(intptr_t)SWL_new, "SWL_new"}, {(intptr_t)SWR_new, "SWR_new"}, {(intptr_t)SDL_new, "SDL_new"}, {(intptr_t)SDR_new, "SDR_new"}, {(intptr_t)cvt_s_w, "cvt_s_w"}, {(intptr_t)cvt_d_w, "cvt_d_w"}, {(intptr_t)cvt_s_l, "cvt_s_l"}, {(intptr_t)cvt_d_l, "cvt_d_l"}, {(intptr_t)cvt_w_s, "cvt_w_s"}, {(intptr_t)cvt_w_d, "cvt_w_d"}, {(intptr_t)cvt_l_s, "cvt_l_s"}, {(intptr_t)cvt_l_d, "cvt_l_d"}, {(intptr_t)cvt_d_s, "cvt_d_s"}, {(intptr_t)cvt_s_d, "cvt_s_d"}, {(intptr_t)round_l_s, "round_l_s"}, {(intptr_t)round_w_s, "round_w_s"}, {(intptr_t)trunc_l_s, "trunc_l_s"}, {(intptr_t)trunc_w_s, "trunc_w_s"}, {(intptr_t)ceil_l_s, "ceil_l_s"}, {(intptr_t)ceil_w_s, "ceil_w_s"}, {(intptr_t)floor_l_s, "floor_l_s"}, {(intptr_t)floor_w_s, "floor_w_s"}, {(intptr_t)round_l_d, "round_l_d"}, {(intptr_t)round_w_d, "round_w_d"}, {(intptr_t)trunc_l_d, "trunc_l_d"}, {(intptr_t)trunc_w_d, "trunc_w_d"}, {(intptr_t)ceil_l_d, "ceil_l_d"}, {(intptr_t)ceil_w_d, "ceil_w_d"}, {(intptr_t)floor_l_d, "floor_l_d"}, {(intptr_t)floor_w_d, "floor_w_d"}, {(intptr_t)c_f_s, "c_f_s"}, {(intptr_t)c_un_s, "c_un_s"}, {(intptr_t)c_eq_s, "c_eq_s"}, {(intptr_t)c_ueq_s, "c_ueq_s"}, {(intptr_t)c_olt_s, "c_olt_s"}, {(intptr_t)c_ult_s, "c_ult_s"}, {(intptr_t)c_ole_s, "c_ole_s"}, {(intptr_t)c_ule_s, "c_ule_s"}, {(intptr_t)c_sf_s, "c_sf_s"}, {(intptr_t)c_ngle_s, "c_ngle_s"}, {(intptr_t)c_seq_s, "c_seq_s"}, {(intptr_t)c_ngl_s, "c_ngl_s"}, {(intptr_t)c_lt_s, "c_lt_s"}, {(intptr_t)c_nge_s, "c_nge_s"}, {(intptr_t)c_le_s, "c_le_s"}, {(intptr_t)c_ngt_s, "c_ngt_s"}, {(intptr_t)c_f_d, "c_f_d"}, {(intptr_t)c_un_d, "c_un_d"}, {(intptr_t)c_eq_d, "c_eq_d"}, {(intptr_t)c_ueq_d, "c_ueq_d"}, {(intptr_t)c_olt_d, "c_olt_d"}, {(intptr_t)c_ult_d, "c_ult_d"}, {(intptr_t)c_ole_d, "c_ole_d"}, {(intptr_t)c_ule_d, "c_ule_d"}, {(intptr_t)c_sf_d, "c_sf_d"}, {(intptr_t)c_ngle_d, "c_ngle_d"}, {(intptr_t)c_seq_d, "c_seq_d"}, {(intptr_t)c_ngl_d, "c_ngl_d"}, {(intptr_t)c_lt_d, "c_lt_d"}, {(intptr_t)c_nge_d, "c_nge_d"}, {(intptr_t)c_le_d, "c_le_d"}, {(intptr_t)c_ngt_d, "c_ngt_d"}, {(intptr_t)add_s, "add_s"}, {(intptr_t)sub_s, "sub_s"}, {(intptr_t)mul_s, "mul_s"}, {(intptr_t)div_s, "div_s"}, {(intptr_t)sqrt_s, "sqrt_s"}, {(intptr_t)abs_s, "abs_s"}, {(intptr_t)mov_s, "mov_s"}, {(intptr_t)neg_s, "neg_s"}, {(intptr_t)add_d, "add_d"}, {(intptr_t)sub_d, "sub_d"}, {(intptr_t)mul_d, "mul_d"}, {(intptr_t)div_d, "div_d"}, {(intptr_t)sqrt_d, "sqrt_d"}, {(intptr_t)abs_d, "abs_d"}, {(intptr_t)mov_d, "mov_d"}, {(intptr_t)neg_d, "neg_d"}, {(intptr_t)breakpoint, "breakpoint"}, {-1, NULL} }; static csh handle; static void disassemble(int i, FILE * pFile) { if (bt[i]) fprintf(pFile, "*"); else fprintf(pFile, " "); switch(itype[i]) { case UJUMP: fprintf (pFile, " %x: %s %8x\n",start+i*4,insn[i],ba[i]);break; case CJUMP: fprintf (pFile, " %x: %s r%d,r%d,%8x\n",start+i*4,insn[i],rs1[i],rs2[i],i?start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14):*ba);break; case SJUMP: fprintf (pFile, " %x: %s r%d,%8x\n",start+i*4,insn[i],rs1[i],start+i*4+4+((signed int)((unsigned int)source[i]<<16)>>14));break; case FJUMP: fprintf (pFile, " %x: %s %8x\n",start+i*4,insn[i],ba[i]);break; case RJUMP: if ((opcode2[i]&1)&&rt1[i]!=31) fprintf (pFile, " %x: %s r%d,r%d\n",start+i*4,insn[i],rt1[i],rs1[i]); else fprintf (pFile, " %x: %s r%d\n",start+i*4,insn[i],rs1[i]); break; case SPAN: fprintf (pFile, " %x: %s (pagespan) r%d,r%d,%8x\n",start+i*4,insn[i],rs1[i],rs2[i],ba[i]);break; case IMM16: if(opcode[i]==0xf) //LUI fprintf (pFile, " %x: %s r%d,%4x0000\n",start+i*4,insn[i],rt1[i],imm[i]&0xffff); else fprintf (pFile, " %x: %s r%d,r%d,%d\n",start+i*4,insn[i],rt1[i],rs1[i],imm[i]); break; case LOAD: case LOADLR: fprintf (pFile, " %x: %s r%d,r%d+%x\n",start+i*4,insn[i],rt1[i],rs1[i],imm[i]); break; case STORE: case STORELR: fprintf (pFile, " %x: %s r%d,r%d+%x\n",start+i*4,insn[i],rs2[i],rs1[i],imm[i]); break; case ALU: case SHIFT: fprintf (pFile, " %x: %s r%d,r%d,r%d\n",start+i*4,insn[i],rt1[i],rs1[i],rs2[i]); break; case MULTDIV: fprintf (pFile, " %x: %s r%d,r%d\n",start+i*4,insn[i],rs1[i],rs2[i]); break; case SHIFTIMM: fprintf (pFile, " %x: %s r%d,r%d,%d\n",start+i*4,insn[i],rt1[i],rs1[i],imm[i]); break; case MOV: if((opcode2[i]&0x1d)==0x10) fprintf (pFile, " %x: %s r%d\n",start+i*4,insn[i],rt1[i]); else if((opcode2[i]&0x1d)==0x11) fprintf (pFile, " %x: %s r%d\n",start+i*4,insn[i],rs1[i]); else fprintf (pFile, " %x: %s\n",start+i*4,insn[i]); break; case COP0: if(opcode2[i]==0) fprintf (pFile, " %x: %s r%d,cpr0[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC0 else if(opcode2[i]==4) fprintf (pFile, " %x: %s r%d,cpr0[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC0 else fprintf (pFile, " %x: %s\n",start+i*4,insn[i]); break; case COP1: if(opcode2[i]<3) fprintf (pFile, " %x: %s r%d,cpr1[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC1 else if(opcode2[i]>3) fprintf (pFile, " %x: %s r%d,cpr1[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC1 else fprintf (pFile, " %x: %s",start+i*4,insn[i]); break; case C1LS: fprintf (pFile, " %x: %s cpr1[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]); break; default: //fprintf (pFile, " %s %8x",insn[i],source[i]); fprintf (pFile, " %x: %s\n",start+i*4,insn[i]); } } static void debugging(int i, FILE * pFile) { fprintf(pFile, "/************************/"); fprintf(pFile, "\nU:"); int r; for(r=1;r<=CCREG;r++) { if((unneeded_reg[i]>>r)&1) { if(r==HIREG) fprintf(pFile, " HI"); else if(r==LOREG) fprintf(pFile, " LO"); else fprintf(pFile, " r%d",r); } } fprintf(pFile, "\nUU:"); for(r=1;r<=CCREG;r++) { if(((unneeded_reg_upper[i]&~unneeded_reg[i])>>r)&1) { if(r==HIREG) fprintf(pFile, " HI"); else if(r==LOREG) fprintf(pFile, " LO"); else fprintf(pFile, " r%d",r); } } fprintf(pFile, "\nwas32:"); for(r=0;r<=CCREG;r++) { if((regs[i].was32>>r)&1) { if(r==CCREG) fprintf(pFile, " CC"); else if(r==HIREG) fprintf(pFile, " HI"); else if(r==LOREG) fprintf(pFile, " LO"); else fprintf(pFile, " r%d",r); } } fprintf(pFile, "\nreg_pre:"); for(r=0;r>r)&1) fprintf(pFile, " %s",regname[r]); } } fprintf(pFile, "\nreq32:"); for(r=0;r<=CCREG;r++) { if((requires_32bit[i]>>r)&1) { if(r==CCREG) fprintf(pFile, " CC"); else if(r==HIREG) fprintf(pFile, " HI"); else if(r==LOREG) fprintf(pFile, " LO"); else fprintf(pFile, " r%d",r); } } fprintf(pFile, "\nreg_entry:"); for(r=0;r>r)&1) fprintf(pFile, " %s",regname[r]); } } fprintf(pFile, "\n/*"); fprintf(pFile, "\n"); disassemble(i, pFile); fprintf(pFile, "*/"); fprintf(pFile, "\nreg_map:"); for(r=0;r>r)&1) fprintf(pFile, " %s",regname[r]); } } if(regs[i].isconst) { fprintf(pFile, "\nconstants:"); for(r=0;r>r)&1) fprintf(pFile, " %s=%x ",regname[r],(int)constmap[i][r]); } } } fprintf(pFile, "\nis32:"); for(r=0;r<=CCREG;r++) { if((regs[i].is32>>r)&1) { if(r==CCREG) fprintf(pFile, " CC"); else if(r==HIREG) fprintf(pFile, " HI"); else if(r==LOREG) fprintf(pFile, " LO"); else fprintf(pFile, " r%d",r); } } if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP||itype[i]==FJUMP) { fprintf(pFile, "\nbranch_reg(%d):",i); for(r=0;r>r)&1) fprintf(pFile, " %s",regname[r]); } } fprintf(pFile, "\nbranch_is32:"); for(r=0;r<=CCREG;r++) { if((branch_regs[i].is32>>r)&1) { if(r==CCREG) fprintf(pFile, " CC"); else if(r==HIREG) fprintf(pFile, " HI"); else if(r==LOREG) fprintf(pFile, " LO"); else fprintf(pFile, " r%d",r); } } } fprintf(pFile, "\n/************************/\n\n"); } static void replace_addr(intptr_t real_addr, intptr_t addr, size_t addr_size, Variable_t * var, char * op_str, size_t op_size) { char right[256]; char addr_str[32]; char * ptr = NULL; char * ptr2 = NULL; if(addr_size == 4) sprintf(addr_str, "0x%x", addr); else if(addr_size == 8) sprintf(addr_str, "0x%llx", addr); else assert(0); ptr = strstr(op_str, addr_str); if(ptr == NULL) { sprintf(addr_str, "0x%x", -addr); ptr = strstr(op_str, addr_str); assert(ptr != NULL); assert(*(ptr-2) == '-'); *(ptr-2) = '+'; } ptr2 = strstr(op_str, "rip"); if(ptr2 == NULL) *ptr = '\0'; else *ptr2 = '\0'; memcpy(right, (ptr + strlen(addr_str)), op_size - (ptr - op_str)); /* copy right part after address */ if((real_addr - var->addr) == 0) snprintf(op_str, op_size, "%s%s%s", op_str, var->name, right); else snprintf(op_str, op_size, "%s%s+%d%s", op_str, var->name, (real_addr - var->addr), right); } void recomp_dbg_init(void) { var[0].addr = (uintptr_t)g_dev.rdram.dram - 0x80000000; var[0].size = g_dev.rdram.dram_size; recomp_dbg_base_addr = recomp_dbg_base_addr_rx = (void*)recomp_dbg_extra_memory; /* New dynarec init */ recomp_dbg_out=(u_char *)recomp_dbg_base_addr; for(int n=0;n<65536;n++) hash_table[n][0]=hash_table[n][1]=NULL; copy_size=0; expirep=16384; // Expiry pointer, +2 blocks literalcount=0; arch_init(); /* Capstone init */ if(cs_open(ARCHITECTURE, MODE, &handle) != CS_ERR_OK) return; cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); #if RECOMPILER_DEBUG >= NEW_DYNAREC_ARM FILE * pFile = osal_file_open ("jump_table.txt","w"); uintptr_t * src = (uintptr_t *)((char *)base_addr+(1<>2 == func[j].addr>>2) break; j++; } fprintf(pFile, "0x%" PRIxPTR ": 0x%" PRIxPTR " (%s)\n", (uintptr_t)src, (uintptr_t)*src, func[j].name); src++; } fflush(pFile); fclose(pFile); #endif } void recomp_dbg_cleanup(void) { /* New dynarec cleanup */ for(int n=0;n<4096;n++) ll_clear(jump_in+n); for(int n=0;n<4096;n++) ll_clear(jump_out+n); for(int n=0;n<4096;n++) ll_clear(jump_dirty+n); assert(copy_size==0); /* Capstone cleanup */ if(handle == 0) return; cs_close(&handle); } void recomp_dbg_block(int addr) { uint32_t * beginning; uint32_t * end; cs_insn *instr; size_t count; int32_t size = 0; int32_t sum = 0; char filename[32]; FILE * pFile; /* Copy data from running dynarec */ #undef using_tlb #undef stop_after_jal extern unsigned int stop_after_jal; extern unsigned int using_tlb; recomp_dbg_using_tlb = using_tlb; recomp_dbg_stop_after_jal = stop_after_jal; /* Warning: invalid_code is shared between both running and debugged recompiler*/ beginning=(uint32_t *)recomp_dbg_out; recomp_dbg_new_recompile_block(addr); end=(uint32_t *)recomp_dbg_out; int disasm=0; int block, inst; for(block=0;block<(sizeof(disasm_block)>>2);block++) { for(inst=0;inst= NEW_DYNAREC_ARM if(INSTRUCTION.operands[1].reg == FP_REGISTER) { uint32_t j = 0; uint32_t imm; if(INSTRUCTION.op_count > 2) imm = INSTRUCTION.operands[2].mem.base; else imm = INSTRUCTION.operands[1].mem.disp; assert(imm>=0 && imm<4096); while(var[j].addr != -1) { uint32_t offset = var[j].addr - (uintptr_t)&g_dev.r4300.new_dynarec_hot_state.dynarec_local; if(imm >= offset && imm < (offset + var[j].size)) break; j++; } if(var[j].addr != -1) { if((imm - (var[j].addr - (uintptr_t)&g_dev.r4300.new_dynarec_hot_state.dynarec_local)) == 0) fprintf(pFile, "0x%" PRIxPTR ": %s %s (%s)\n", (uintptr_t)instr[i].address, instr[i].mnemonic, instr[i].op_str, var[j].name); else fprintf(pFile, "0x%" PRIxPTR ": %s %s (%s+%d)\n", (uintptr_t)instr[i].address, instr[i].mnemonic, instr[i].op_str, var[j].name, imm - (var[j].addr - (uintptr_t)&g_dev.r4300.new_dynarec_hot_state.dynarec_local)); continue; } } #else if(INSTRUCTION.disp /*|| (INSTRUCTION.operands[1].imm && INSTRUCTION.operands[1].type == X86_OP_IMM)*/) { char op_str[256]; uint32_t j = 0; uint32_t off = 0; int64_t addr = INSTRUCTION.disp; strcpy(op_str, instr[i].op_str); char *ptr = strstr(op_str, "rip"); if(ptr != NULL) // rip relative addr = addr + instr[i+1].address; while(var[j].addr != -1) { if(addr >= var[j].addr && addr < (var[j].addr + var[j].size)) break; j++; } //TODO: remove replace_addr? if(var[j].addr != -1) replace_addr(addr, INSTRUCTION.disp, sizeof(INSTRUCTION.disp), &var[j], op_str, sizeof(op_str)); //uint32_t k = 0; //while(var[k].addr != -1) { // if(INSTRUCTION.operands[1].imm >= var[k].addr && INSTRUCTION.operands[1].imm < (var[k].addr + var[k].size)) // break; // k++; //} // //if(var[k].addr != -1) // replace_addr(addr, INSTRUCTION.operands[1].imm, sizeof(INSTRUCTION.operands[1].imm), &var[k], op_str, sizeof(op_str)); if((var[j].addr != -1) /*|| (var[k].addr != -1)*/) { fprintf(pFile, "0x%" PRIxPTR ": %s %s\n", (uintptr_t)instr[i].address, instr[i].mnemonic, op_str); continue; } } #endif if(instr[i].id == CALL_INST || instr[i].id == BRANCH_INST) { uint32_t j = 0; intptr_t addr = (intptr_t)INSTRUCTION.operands[0].imm; intptr_t * paddr = (intptr_t*)addr; while(func[j].addr != -1) { #if RECOMPILER_DEBUG >= NEW_DYNAREC_ARM if((addr>>2 == func[j].addr>>2) || ((*(paddr+1))>>2 == func[j].addr>>2)) // check jump_table_symbols on ARM #else if(addr>>2 == func[j].addr>>2) #endif break; j++; } if(func[j].addr != -1) { fprintf(pFile, "0x%" PRIxPTR ": %s %s\n", (uintptr_t)instr[i].address, instr[i].mnemonic, func[j].name); continue; } } fprintf(pFile, "0x%" PRIxPTR ": %s %s\n", (uintptr_t)instr[i].address, instr[i].mnemonic, instr[i].op_str); } if(size != sum) fprintf(pFile, "Failed to disassemble code at: 0x%.8x\n", (uintptr_t)beginning + sum); cs_free(instr, count); fflush(pFile); fclose(pFile); } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x64/000077500000000000000000000000001464506436200231635ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x64/assem_x64.c000066400000000000000000003654241464506436200251560ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assem_x64.c * * Copyright (C) 2009-2011 Ari64 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void jump_vaddr_eax(void); void jump_vaddr_ecx(void); void jump_vaddr_edx(void); void jump_vaddr_ebx(void); void jump_vaddr_ebp(void); void jump_vaddr_esi(void); void jump_vaddr_edi(void); void invalidate_block_eax(void); void invalidate_block_ecx(void); void invalidate_block_edx(void); void invalidate_block_ebx(void); void invalidate_block_ebp(void); void invalidate_block_esi(void); void invalidate_block_edi(void); // We need these for cmovcc instructions on x64 static const u_int const_zero=0; static const u_int const_one=1; static const uintptr_t jump_vaddr_reg[8] = { (uintptr_t)jump_vaddr_eax, (uintptr_t)jump_vaddr_ecx, (uintptr_t)jump_vaddr_edx, #ifdef _WIN32 (uintptr_t)jump_vaddr_ebx, #else 0, #endif 0, (uintptr_t)jump_vaddr_ebp, #ifdef _WIN32 0, #else (uintptr_t)jump_vaddr_esi, #endif (uintptr_t)jump_vaddr_edi }; static const uintptr_t invalidate_block_reg[8] = { (uintptr_t)invalidate_block_eax, (uintptr_t)invalidate_block_ecx, (uintptr_t)invalidate_block_edx, (uintptr_t)invalidate_block_ebx, 0, (uintptr_t)invalidate_block_ebp, (uintptr_t)invalidate_block_esi, (uintptr_t)invalidate_block_edi }; /* Linker */ static void set_jump_target(uintptr_t addr,uintptr_t target) { u_char *ptr=(u_char *)addr; if(*ptr==0x0f) { assert(ptr[1]>=0x80&&ptr[1]<=0x8f); // conditional jmp u_int *ptr2=(u_int *)(ptr+2); *ptr2=(intptr_t)target-(intptr_t)ptr2-4; } else if(*ptr==0xe8||*ptr==0xe9) { u_int *ptr2=(u_int *)(ptr+1); *ptr2=(intptr_t)target-(intptr_t)ptr2-4; } else { //mini_ht assert(*(ptr+1)==0xbf); /* mov immediate to r15 (store address) */ uintptr_t *ptr2=(uintptr_t *)(ptr+2); *ptr2=target; } } static void *add_pointer(void *src, void* addr) { int *ptr=(int*)src; int *ptr2=(int*)((uintptr_t)ptr+(uintptr_t)*ptr+4); u_char *ptr3=(u_char*)ptr2; assert((*(ptr3+1)&0xFF)==0x8d); //lea u_int offset=(uintptr_t)addr-(uintptr_t)ptr-4; *ptr=offset; return (void*)ptr2; } static void *kill_pointer(void *stub) { intptr_t ptr=(intptr_t)stub+3; uintptr_t i_ptr=(intptr_t)ptr+*((int *)ptr)+4; // rip relative *((int *)i_ptr)=(intptr_t)stub-(intptr_t)i_ptr-4; return (void *)i_ptr; } static intptr_t get_pointer(void *stub) { intptr_t ptr=(intptr_t)stub+3; uintptr_t i_ptr=(intptr_t)ptr+*((int *)ptr)+4; // rip relative return *((int *)i_ptr)+(intptr_t)i_ptr+4; } /* Register allocation */ // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). static void alloc_reg(struct regstat *cur,int i,signed char reg) { int r,hr; int preferred_reg = (reg&3)+(reg>28)*4-(reg==32)+(HOST_CCREG-4)*(reg==36)-(reg==40)-(reg==44)-(reg==48); // Don't allocate unused registers if((cur->u>>reg)&1) return; // see if it's already allocated for(hr=0;hrregmap[hr]==reg) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) if(i==0||(unneeded_reg[i-1]>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) if(i==0||(unneeded_reg_upper[i-1]>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<uu>>reg)&1) return; // see if the upper half is already allocated for(hr=0;hrregmap[hr]==reg+64) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg|64; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==reg) return; } // Try to allocate any available register, starting with EDI, ESI, EBP... // We prefer EDI, ESI, EBP since the others are used for byte/halfword stores for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<uu>>(r&63))&1) { if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hr2) { if(cur->regmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<2) { if(cur->regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[n]==reg) { dirty=(cur->dirty>>n)&1; cur->regmap[n]=-1; } } cur->regmap[hr]=reg; cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<u&=~(1LL<u&=~(1LL<is32|=1LL<is32|=1LL<u>>LOREG)&1)||((current->uu>>LOREG)&1)) alloc_reg64(current,i,HIREG); else alloc_reg(current,i,HIREG); alloc_reg64(current,i,LOREG); alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rs2[i]); current->is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32|=1LL<=8||rt>=8) output_rex(0,rs>>3,0,rt>>3); output_byte(0x89); output_modrm(3,rt&7,rs&7); } static void emit_mov64(int rs,int rt) { assem_debug("mov %%%s,%%%s",regname[rs],regname[rt]); output_rex(1,0,0,rt>>3); // FIXME output_byte(0x89); output_modrm(3,rt&7,rs); } static void emit_add(int rs1,int rs2,int rt) { if(rs1==rt) { assem_debug("add %%%s,%%%s",regname[rs2],regname[rs1]); output_byte(0x01); output_modrm(3,rs1,rs2); }else if(rs2==rt) { assem_debug("add %%%s,%%%s",regname[rs1],regname[rs2]); output_byte(0x01); output_modrm(3,rs2,rs1); }else { assem_debug("mov %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x89); output_modrm(3,rt,rs1); assem_debug("add %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x01); output_modrm(3,rt,rs2); } } static void emit_adc(int rs1,int rs2,int rt) { if(rs1==rt) { assem_debug("adc %%%s,%%%s",regname[rs2],regname[rs1]); output_byte(0x11); output_modrm(3,rs1,rs2); }else if(rs2==rt) { assem_debug("adc %%%s,%%%s",regname[rs1],regname[rs2]); output_byte(0x11); output_modrm(3,rs2,rs1); }else { assem_debug("mov %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x89); output_modrm(3,rt,rs1); assem_debug("adc %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x11); output_modrm(3,rt,rs2); } } static void emit_adds(int rs1,int rs2,int rt) { emit_add(rs1,rs2,rt); } static void emit_lea8(int rs1,int rt) { assem_debug("lea 0(%%%s,8),%%%s",regname[rs1],regname[rt]); output_byte(0x8D); output_modrm(0,4,rt); output_sib(3,rs1,5); output_w32(0); } static void emit_leairrx1(int imm,int rs1,int rs2,int rt) { assem_debug("lea %x(%%%s,%%%s,1),%%%s",imm,regname[rs1],regname[rs2],regname[rt]); output_rex(1,rt>>3,rs2>>3,rs1>>3); output_byte(0x8D); if(imm!=0||rs1==EBP) { output_modrm(2,4,rt&7); output_sib(0,rs2&7,rs1&7); output_w32(imm); }else{ output_modrm(0,4,rt&7); output_sib(0,rs2&7,rs1&7); } } static void emit_leairrx4(int imm,int rs1,int rs2,int rt) { assem_debug("lea %x(%%%s,%%%s,4),%%%s",imm,regname[rs1],regname[rs2],regname[rt]); output_rex(1,rt>>3,rs2>>3,rs1>>3); output_byte(0x8D); if(imm!=0||rs1==EBP) { output_modrm(2,4,rt&7); output_sib(2,rs2&7,rs1&7); output_w32(imm); }else{ output_modrm(0,4,rt&7); output_sib(2,rs2&7,rs1&7); } } static void emit_lea_rip(intptr_t addr, int hr) { assert(addr-(intptr_t)out>=-2147483648LL&&addr-(intptr_t)out<2147483647LL); if(addr==(intptr_t)&g_dev.r4300.new_dynarec_hot_state.memory_map) assem_debug("lea %llx,%%%s%s",addr,regname[hr]," [memory_map]"); if(addr==(intptr_t)&g_dev.r4300.cached_interp.invalid_code) assem_debug("lea %llx,%%%s%s",addr,regname[hr]," [invalid_code]"); output_rex(1,hr>>3,0,0); // 64-bit registers output_byte(0x8D); output_modrm(0,5,hr&7); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_neg(int rs, int rt) { if(rs!=rt) emit_mov(rs,rt); assem_debug("neg %%%s",regname[rt]); output_byte(0xF7); output_modrm(3,rt,3); } static void emit_negs(int rs, int rt) { emit_neg(rs,rt); } static void emit_sub(int rs1,int rs2,int rt) { if(rs1==rt) { assem_debug("sub %%%s,%%%s",regname[rs2],regname[rs1]); output_byte(0x29); output_modrm(3,rs1,rs2); } else if(rs2==rt) { emit_neg(rs2,rs2); emit_add(rs2,rs1,rs2); } else { emit_mov(rs1,rt); emit_sub(rt,rs2,rt); } } static void emit_subs(int rs1,int rs2,int rt) { emit_sub(rs1,rs2,rt); } static void emit_zeroreg(int rt) { output_byte(0x31); output_modrm(3,rt,rt); assem_debug("xor %%%s,%%%s",regname[rt],regname[rt]); } static void emit_loadreg(int r, int hr) { if((r&63)==0) emit_zeroreg(hr); else if(r==MMREG) emit_lea_rip((intptr_t)g_dev.r4300.new_dynarec_hot_state.memory_map,hr); else if(r==INVCP) emit_lea_rip((intptr_t)g_dev.r4300.cached_interp.invalid_code,hr); else if(r==ROREG) { intptr_t addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.ram_offset; assert(addr-(intptr_t)out>=-2147483648LL&&addr-(intptr_t)out<2147483647LL); assem_debug("mov (%llx),%%%s [ram_offset]",addr,regname[hr]); output_rex(1,hr>>3,0,0); // 64-bit load output_byte(0x8B); output_modrm(0,5,hr&7); // allow r15 output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } else { intptr_t addr=((intptr_t)g_dev.r4300.new_dynarec_hot_state.regs)+((r&63)<<3)+((r&64)>>4); if((r&63)==HIREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.hi+((r&64)>>4); if((r&63)==LOREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.lo+((r&64)>>4); if(r==CCREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cycle_count; if(r==CSREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[CP0_STATUS_REG]; if(r==FSREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31; assert(addr-(intptr_t)out>=-2147483648LL&&addr-(intptr_t)out<2147483647LL); assem_debug("mov %llx+%d,%%%s",addr,r,regname[hr]); if(hr>=8) output_rex(0,hr>>3,0,0); output_byte(0x8B); output_modrm(0,5,hr&7); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } } static void emit_storereg(int r, int hr) { intptr_t addr=((intptr_t)g_dev.r4300.new_dynarec_hot_state.regs)+((r&63)<<3)+((r&64)>>4); if((r&63)==HIREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.hi+((r&64)>>4); if((r&63)==LOREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.lo+((r&64)>>4); if(r==CCREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cycle_count; if(r==FSREG) addr=(intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31; assert((r&63)!=CSREG); assert((r&63)!=0); assert((r&63)<=CCREG); assert(addr-(intptr_t)out>=-2147483648LL&&addr-(intptr_t)out<2147483647LL); assem_debug("mov %%%s,%llx+%d",regname[hr],addr,r); if(hr>=8) output_rex(0,hr>>3,0,0); output_byte(0x89); output_modrm(0,5,hr&7); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_test(int rs, int rt) { assem_debug("test %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x85); output_modrm(3,rs,rt); } static void emit_test64(int rs, int rt) { assert(rs<8&&rt<8); assem_debug("test %%%s,%%%s",regname[rs],regname[rt]); output_rex(1,0,0,0); output_byte(0x85); output_modrm(3,rs,rt); } static void emit_testimm(int rs,int imm) { assem_debug("test $0x%x,%%%s",imm,regname[rs]); if(imm<128&&imm>=-128&&rs<4) { output_byte(0xF6); output_modrm(3,rs,0); output_byte(imm); } else { output_byte(0xF7); output_modrm(3,rs,0); output_w32(imm); } } static void emit_not(int rs,int rt) { if(rs!=rt) emit_mov(rs,rt); assem_debug("not %%%s",regname[rt]); output_byte(0xF7); output_modrm(3,rt,2); } static void emit_and(u_int rs1,u_int rs2,u_int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("and %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x21); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("and %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x21); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_and(rt,rs2,rt); } } static void emit_or(u_int rs1,u_int rs2,u_int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("or %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x09); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("or %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x09); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_or(rt,rs2,rt); } } static void emit_or_and_set_flags(int rs1,int rs2,int rt) { emit_or(rs1,rs2,rt); } static void emit_xor(u_int rs1,u_int rs2,u_int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("xor %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x31); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("xor %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x31); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_xor(rt,rs2,rt); } } static void emit_movimm(int imm,u_int rt) { assem_debug("mov $%d,%%%s",imm,regname[rt]); assert(rt<16); if(rt>=8) output_rex(0,0,0,1); output_byte(0xB8+(rt&7)); output_w32(imm); } static void emit_movimm64(int64_t imm,u_int rt) { assem_debug("mov $%lld,%%%s",imm,regname[rt]); assert(rt<16); output_rex(1,0,0,rt>>3); output_byte(0xB8+(rt&7)); output_w64(imm); } static void emit_addimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("add $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } } else { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s",imm,regname[rs],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rs,rt); output_byte(imm); }else{ output_modrm(2,rs,rt); output_w32(imm); } }else{ emit_mov(rs,rt); } } } static void emit_addimm64(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("add $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_rex(1,0,0,rt>>3); output_byte(0x83); output_modrm(3,rt&7,0); output_byte(imm); } else { output_rex(1,0,0,rt>>3); output_byte(0x81); output_modrm(3,rt&7,0); output_w32(imm); } } } else { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s",imm,regname[rs],regname[rt]); output_rex(1,rt>>3,0,rs>>3); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rs&7,rt&7); output_byte(imm); }else{ output_modrm(2,rs&7,rt&7); output_w32(imm); } }else{ emit_mov(rs,rt); } } } static void emit_addimm_and_set_flags(int imm,int rt) { assem_debug("add $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } static void emit_addimm_no_flags(int imm,int rt) { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s",imm,regname[rt],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rt,rt); output_byte(imm); }else{ output_modrm(2,rt,rt); output_w32(imm); } } } static void emit_adcimm(int imm,u_int rt) { assem_debug("adc $%d,%%%s",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,2); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,2); output_w32(imm); } } static void emit_sbbimm(int imm,u_int rt) { assem_debug("sbb $%d,%%%s",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,3); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,3); output_w32(imm); } } static void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) { if(rsh==rth&&rsl==rtl) { assem_debug("add $%d,%%%s",imm,regname[rtl]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rtl,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rtl,0); output_w32(imm); } assem_debug("adc $%d,%%%s",imm>>31,regname[rth]); output_byte(0x83); output_modrm(3,rth,2); output_byte(imm>>31); } else { emit_mov(rsh,rth); emit_mov(rsl,rtl); emit_addimm64_32(rth,rtl,imm,rth,rtl); } } static void emit_sub64_32(int rs1l,int rs1h,int rs2l,int rs2h,int rtl,int rth) { if((rs1l==rtl)&&(rs1h==rth)) { assem_debug("sub %%%s,%%%s",regname[rs2l],regname[rs1l]); output_byte(0x29); output_modrm(3,rs1l,rs2l); assem_debug("sbb %%%s,%%%s",regname[rs2h],regname[rs1h]); output_byte(0x19); output_modrm(3,rs1h,rs2h); } else if((rs2l==rtl)&&(rs2h==rth)) { emit_neg(rs2l,rs2l); emit_adcimm(-1,rs2h); assem_debug("add %%%s,%%%s",regname[rs1l],regname[rs2l]); output_byte(0x01); output_modrm(3,rs2l,rs1l); emit_not(rs2h,rs2h); assem_debug("adc %%%s,%%%s",regname[rs1h],regname[rs2h]); output_byte(0x11); output_modrm(3,rs2h,rs1h); } else { emit_mov(rs1l,rtl); assem_debug("sub %%%s,%%%s",regname[rs2l],regname[rtl]); output_byte(0x29); output_modrm(3,rtl,rs2l); emit_mov(rs1h,rth); assem_debug("sbb %%%s,%%%s",regname[rs2h],regname[rth]); output_byte(0x19); output_modrm(3,rth,rs2h); } } static void emit_sbb(int rs1,int rs2) { assem_debug("sbb %%%s,%%%s",regname[rs1],regname[rs2]); output_byte(0x19); output_modrm(3,rs2,rs1); } static void emit_andimm(int rs,int imm,int rt) { if(imm==0) { emit_zeroreg(rt); } else if(rs==rt) { assem_debug("and $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,4); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,4); output_w32(imm); } } else { emit_mov(rs,rt); emit_andimm(rt,imm,rt); } } static void emit_orimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("or $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,1); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,1); output_w32(imm); } } } else { emit_mov(rs,rt); emit_orimm(rt,imm,rt); } } static void emit_xorimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("xor $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,6); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,6); output_w32(imm); } } } else { emit_mov(rs,rt); emit_xorimm(rt,imm,rt); } } static void emit_shlimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("shl %%%s,%d",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,4); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shlimm(rt,imm,rt); } } static void emit_shlimm64(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("shl %%%s,%d",regname[rt],imm); assert(imm>0); output_rex(1,0,0,rt>>3); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt&7,4); if(imm>1) output_byte(imm); } else { emit_mov64(rs,rt); emit_shlimm64(rt,imm,rt); } } static void emit_shrimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("shr %%%s,%d",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,5); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shrimm(rt,imm,rt); } } static void emit_shrimm64(int rs,u_int imm,int rt) { assert(rs==rt); if(rs==rt) { assem_debug("shr %%%s,%d",regname[rt],imm); assert(imm>0); output_rex(1,0,0,rt>>3); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt&7,5); if(imm>1) output_byte(imm); } else { emit_mov64(rs,rt); emit_shrimm64(rt,imm,rt); } } static void emit_sarimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("sar %%%s,%d",regname[rt],imm); assert(imm>0); if(rt>=8) output_rex(0,0,0,rt>>3); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt&7,7); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_sarimm(rt,imm,rt); } } static void emit_rorimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("ror %%%s,%d",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,1); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_rorimm(rt,imm,rt); } } static void emit_shldimm(int rs,int rs2,u_int imm,int rt) { if(rs==rt) { assem_debug("shld %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xA4); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shldimm(rt,rs2,imm,rt); } } static void emit_shrdimm(int rs,int rs2,u_int imm,int rt) { if(rs==rt) { assem_debug("shrd %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xAC); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shrdimm(rt,rs2,imm,rt); } } static void emit_shlcl(int r) { assem_debug("shl %%%s,%%cl",regname[r]); if(r>=8)output_rex(0,0,0,r>>3); output_byte(0xD3); output_modrm(3,r&7,4); } static void emit_shrcl(int r) { assem_debug("shr %%%s,%%cl",regname[r]); if(r>=8)output_rex(0,0,0,r>>3); output_byte(0xD3); output_modrm(3,r&7,5); } static void emit_sarcl(int r) { assem_debug("sar %%%s,%%cl",regname[r]); output_byte(0xD3); output_modrm(3,r,7); } static void emit_shldcl(int r1,int r2) { assem_debug("shld %%%s,%%%s,%%cl",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xA5); output_modrm(3,r1,r2); } static void emit_shrdcl(int r1,int r2) { assem_debug("shrd %%%s,%%%s,%%cl",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xAD); output_modrm(3,r1,r2); } static void emit_cmpimm(int rs,int imm) { assem_debug("cmp $%d,%%%s",imm,regname[rs]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rs,7); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rs,7); output_w32(imm); } } static void emit_cmovne(const u_int *addr,int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("cmovne %llx,%%%s",(intptr_t)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]"); else if(addr==&const_one) assem_debug(" [one]"); else assem_debug(""); output_byte(0x0F); output_byte(0x45); output_modrm(0,5,rt); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_cmovl(const u_int *addr,int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("cmovl %llx,%%%s",(intptr_t)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]"); else if(addr==&const_one) assem_debug(" [one]"); else assem_debug(""); output_byte(0x0F); output_byte(0x4C); output_modrm(0,5,rt); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_cmovs(const u_int *addr,int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("cmovs %llx,%%%s",(intptr_t)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]"); else if(addr==&const_one) assem_debug(" [one]"); else assem_debug(""); output_byte(0x0F); output_byte(0x48); output_modrm(0,5,rt); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_cmovne_reg(int rs,int rt) { assem_debug("cmovne %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x45); output_modrm(3,rs,rt); } static void emit_cmovl_reg(int rs,int rt) { assem_debug("cmovl %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4C); output_modrm(3,rs,rt); } static void emit_cmovs_reg(int rs,int rt) { assem_debug("cmovs %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x48); output_modrm(3,rs,rt); } static void emit_cmovnc_reg(int rs,int rt) { assem_debug("cmovae %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x43); output_modrm(3,rs,rt); } static void emit_cmova_reg(int rs,int rt) { assem_debug("cmova %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x47); output_modrm(3,rs,rt); } static void emit_cmovp_reg(int rs,int rt) { assem_debug("cmovp %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4A); output_modrm(3,rs,rt); } static void emit_cmovnp_reg(int rs,int rt) { assem_debug("cmovnp %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4B); output_modrm(3,rs,rt); } static void emit_setl(int rt) { assem_debug("setl %%%s",regname[rt]); output_byte(0x0F); output_byte(0x9C); output_modrm(3,rt,2); } static void emit_movzbl_reg(int rs, int rt) { if(rs<4&&rt<8) { assem_debug("movzbl %%%s,%%%s",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(3,rs,rt); } else { assert(rs<8); assert(rt<8); assem_debug("movzbl %%%s,%%%s",regname[rs]+1,regname[rt]); output_rex(0,rt>>3,0,rs>>3); output_byte(0x0F); output_byte(0xB6); output_modrm(3,rs&7,rt&7); } } static void emit_slti32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rt<4) { emit_setl(rt); if(rs==rt) emit_movzbl_reg(rt,rt); } else { if(rs==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } } static void emit_sltiu32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } static void emit_slti64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_slti32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); emit_cmovs(&const_one,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_zero,rt); emit_cmovl(&const_one,rt); } } static void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_sltiu32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_one,rt); } } static void emit_cmp(int rs,int rt) { assem_debug("cmp %%%s,%%%s",regname[rt],regname[rs]); output_byte(0x39); output_modrm(3,rs,rt); } static void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_cmovl(&const_zero,rt); } static void emit_set_nz32(int rs, int rt) { //assem_debug("set_nz32"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_sbbimm(0,rt); } static void emit_set_gz64_32(int rsh, int rsl, int rt) { //assem_debug("set_gz64"); emit_set_gz32(rsl,rt); emit_test(rsh,rsh); emit_cmovne(&const_one,rt); emit_cmovs(&const_zero,rt); } static void emit_set_nz64_32(int rsh, int rsl, int rt) { //assem_debug("set_nz64"); emit_or_and_set_flags(rsh,rsl,rt); emit_cmovne(&const_one,rt); } static void emit_set_if_less32(int rs1, int rs2, int rt) { //assem_debug("set if less (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } static void emit_set_if_carry32(int rs1, int rs2, int rt) { //assem_debug("set if carry (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } static void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_cmovl(&const_one,rt); } static void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_adcimm(0,rt); } static void emit_call(intptr_t a) { assem_debug("call %llx (%llx+%llx)",a,(intptr_t)out+5,a-(intptr_t)out-5); output_byte(0xe8); output_w32(a-(intptr_t)out-4); } static void emit_jmp(intptr_t a) { assem_debug("jmp %llx (%llx+%llx)",a,(intptr_t)out+5,a-(intptr_t)out-5); output_byte(0xe9); output_w32(a-(intptr_t)out-4); } static void emit_jne(intptr_t a) { assem_debug("jne %llx",a); output_byte(0x0f); output_byte(0x85); output_w32(a-(intptr_t)out-4); } static void emit_jeq(intptr_t a) { assem_debug("jeq %llx",a); output_byte(0x0f); output_byte(0x84); output_w32(a-(intptr_t)out-4); } static void emit_js(intptr_t a) { assem_debug("js %llx",a); output_byte(0x0f); output_byte(0x88); output_w32(a-(intptr_t)out-4); } static void emit_jns(intptr_t a) { assem_debug("jns %llx",a); output_byte(0x0f); output_byte(0x89); output_w32(a-(intptr_t)out-4); } static void emit_jl(intptr_t a) { assem_debug("jl %llx",a); output_byte(0x0f); output_byte(0x8c); output_w32(a-(intptr_t)out-4); } static void emit_jge(intptr_t a) { assem_debug("jge %llx",a); output_byte(0x0f); output_byte(0x8d); output_w32(a-(intptr_t)out-4); } static void emit_jno(intptr_t a) { assem_debug("jno %llx",a); output_byte(0x0f); output_byte(0x81); output_w32(a-(intptr_t)out-4); } static void emit_jc(intptr_t a) { assem_debug("jc %llx",a); output_byte(0x0f); output_byte(0x82); output_w32(a-(intptr_t)out-4); } static void emit_jae(intptr_t a) { assem_debug("jae %llx",a); output_byte(0x0f); output_byte(0x83); output_w32(a-(intptr_t)out-4); } static void emit_jb(intptr_t a) { assem_debug("jb %llx",a); output_byte(0x0f); output_byte(0x82); output_w32(a-(intptr_t)out-4); } static void emit_pushimm(int imm) { assert(0); assem_debug("push $%x",imm); output_byte(0x68); output_w32(imm); } static void emit_pushreg(u_int r) { assem_debug("push %%%s",regname[r]); if(r>=8) output_rex(0,0,0,r>>3); output_byte(0x50+(r&7)); } static void emit_popreg(u_int r) { assem_debug("pop %%%s",regname[r]); if(r>=8) output_rex(0,0,0,r>>3); output_byte(0x58+(r&7)); } static void emit_callreg(u_int r) { assem_debug("call *%%%s",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,2); } static void emit_jmpreg(u_int r) { assem_debug("jmp *%%%s",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,4); } static void emit_jmpmem_indexed(u_int addr,u_int r) { assem_debug("jmp *%x(%%%s)",addr,regname[r]); assert(r<8); output_byte(0xFF); output_modrm(2,r,4); output_w32(addr); } static void emit_addmem64(intptr_t addr,int hr) { assert(0); assert(addr-(intptr_t)out>-2147483648LL&&addr-(intptr_t)out<2147483647LL); if(addr==(intptr_t)&g_dev.r4300.new_dynarec_hot_state.ram_offset) assem_debug("add (%llx),%%%s [ram_offset]",addr,regname[hr]); //else if(addr==(intptr_t)&rounding_modes_ptr) assem_debug("add (%x),%%%s [rounding_modes]",addr,regname[hr]); else assem_debug("add (%llx),%%%s",addr,regname[hr]); output_rex(1,hr>>3,0,0); // 64-bit load output_byte(0x03); output_modrm(0,5,hr&7); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } // Undo the above operation static void emit_submem64(intptr_t addr,int hr) { assert(0); assert(addr-(intptr_t)out>-2147483648LL&&addr-(intptr_t)out<2147483647LL); if(addr==(intptr_t)&g_dev.r4300.new_dynarec_hot_state.ram_offset) assem_debug("sub (%llx),%%%s [ram_offset]",addr,regname[hr]); else assem_debug("sub (%llx),%%%s",addr,regname[hr]); output_rex(1,hr>>3,0,0); // 64-bit load output_byte(0x2B); output_modrm(0,5,hr&7); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_readword(intptr_t addr, int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("mov %llx,%%%s",addr,regname[rt]); output_byte(0x8B); output_modrm(0,5,rt); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_readword_indexed(intptr_t addr, int rs, int rt) { assem_debug("mov %llx+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x8B); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { assert((uintptr_t)addr<4294967296LL); output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } static void emit_readword_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); /*if(map<0) emit_readword_indexed(addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs, rt); else*/ { assem_debug("mov %x(%%%s,%%%s),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); //output_byte(0x67); if(map>=8) { assert(map==HOST_TEMPREG); output_rex(0,0,map>>3,0); } output_byte(0x8B); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map&7,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map&7,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map&7,rs); output_w32(addr); } } } static void emit_readdword_dualindexedx8(int rs1, int rs2, int rt) { assem_debug("mov (%%%s,%%%s,8),%%%s",regname[rs1],regname[rs2],regname[rt]); assert(rs1!=ESP); output_rex(1,rt>>3,rs2>>3,rs1>>3); output_byte(0x8B); if(rs1!=EBP) { output_modrm(0,4,rt&7); output_sib(3,rs2&7,rs1&7); } else { output_modrm(1,4,rt); output_sib(3,rs2&7,rs1&7); output_byte(0); } } static void emit_movmem_indexedx4(int addr, int rs, int rt) { assert(0); assem_debug("mov (%x,%%%s,4),%%%s",addr,regname[rs],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,rs,5); output_w32(addr); } static void emit_movmem_indexedx4_addr32(int addr, int rs, int rt) { assert(0); assem_debug("addr32 mov (%x,%%%s,4),%%%s",addr,regname[rs],regname[rt]); output_byte(0x67); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,rs,5); output_w32(addr); } static void emit_movmem_indexedx8(int addr, int rs, int rt) { assert(0); assem_debug("mov (%x,%%%s,8),%%%s",addr,regname[rs],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(3,rs,5); output_w32(addr); } static void emit_movmem64_irrx8(int offset, int rs1, int rs2, int rt) { assert(0); assem_debug("mov %x(%%%s,%%%s,8),%%%s",offset,regname[rs1],regname[rs2],regname[rt]); output_rex(1,rt>>3,rs2>>3,rs1>>3); output_byte(0x8B); if(offset!=0||rs1==EBP) { output_modrm(2,4,rt&7); output_sib(3,rs2&7,rs1&7); output_w32(offset); }else{ output_modrm(0,4,rt&7); output_sib(3,rs2&7,rs1&7); } } static void emit_movmem64(intptr_t addr, int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movq %llx,%%%s",addr,regname[rt]); output_rex(1,rt>>3,0,0); output_byte(0x8B); output_modrm(0,5,rt&7); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_readdword_indexed(intptr_t addr, int rs, int rt) { assem_debug("mov %x+%%%s,%%%s",addr,regname[rs],regname[rt]); output_rex(1,rt>>3,0,rs>>3); output_byte(0x8B); if(addr<128&&addr>=-128) { output_modrm(1,rs&7,rt&7); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { assert(addr<4294967296LL); output_modrm(2,rs&7,rt&7); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } static void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl) { assert(map>=0); assert(rh!=rs); if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh); emit_readword_indexed_tlb(addr+4, rs, map, rl); } static void emit_movsbl(intptr_t addr, int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movsbl %llx,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(0,5,rt); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_movsbl_indexed(uintptr_t addr, int rs, int rt) { assert(addr<4294967296LL); assem_debug("movsbl %llx+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); /*if(map<0) emit_movsbl_indexed(addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs, rt); else*/ { assem_debug("movsbl %x(%%%s,%%%s),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); //output_byte(0x67); if(map>=8) { assert(map==HOST_TEMPREG); output_rex(0,0,map>>3,0); } output_byte(0x0F); output_byte(0xBE); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map&7,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map&7,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map&7,rs); output_w32(addr); } } } static void emit_movswl(intptr_t addr, int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movswl %llx,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(0,5,rt); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_movswl_indexed(uintptr_t addr, int rs, int rt) { assert(addr<4294967296LL); assem_debug("movswl %llx+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movswl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); /*if(map<0) emit_movswl_indexed(addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs, rt); else*/ { assem_debug("movswl %x(%%%s,%%%s),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); //output_byte(0x67); if(map>=8) { assert(map==HOST_TEMPREG); output_rex(0,0,map>>3,0); } output_byte(0x0F); output_byte(0xBF); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map&7,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map&7,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map&7,rs); output_w32(addr); } } } static void emit_movzbl(intptr_t addr, int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movzbl %llx,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(0,5,rt); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_movzbl_indexed(uintptr_t addr, int rs, int rt) { assert(addr<4294967296LL); assem_debug("movzbl %llx+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); /*if(map<0) emit_movzbl_indexed(addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs, rt); else*/ { assem_debug("movzbl %x(%%%s,%%%s),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); //output_byte(0x67); if(map>=8) { assert(map==HOST_TEMPREG); output_rex(0,0,map>>3,0); } output_byte(0x0F); output_byte(0xB6); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map&7,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map&7,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map&7,rs); output_w32(addr); } } } static void emit_movzwl(intptr_t addr, int rt) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movzwl %llx,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(0,5,rt); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_movzwl_indexed(uintptr_t addr, int rs, int rt) { assert(addr<4294967296LL); assem_debug("movzwl %llx+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movzwl_indexed_tlb(int addr, int rs, int map, int rt) { assert(map>=0); /*if(map<0) emit_movzwl_indexed(addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs, rt); else*/ { assem_debug("movzwl %x(%%%s,%%%s),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); //output_byte(0x67); if(map>=8) { assert(map==HOST_TEMPREG); output_rex(0,0,map>>3,0); } output_byte(0x0F); output_byte(0xB7); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map&7,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map&7,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map&7,rs); output_w32(addr); } } } static void emit_xchg(int rs, int rt) { assem_debug("xchg %%%s,%%%s",regname[rs],regname[rt]); if(rs==EAX) { output_byte(0x90+rt); } else { output_byte(0x87); output_modrm(3,rs,rt); } } static void emit_xchg64(int rs, int rt) { assem_debug("xchg %%%s,%%%s",regname[rs],regname[rt]); if(rs==EAX) { output_rex(1,0,0,rt>>3); // FIXME output_byte(0x90+(rt&7)); } else { output_rex(1,0,0,rt>>3); // FIXME output_byte(0x87); output_modrm(3,rs,rt&7); } } static void emit_writeword(int rt, intptr_t addr) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movl %%%s,%llx",regname[rt],addr); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_writeword_indexed(int rt, intptr_t addr, int rs) { assem_debug("mov %%%s,%llx+%%%s",regname[rt],addr,regname[rs]); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { assert((uintptr_t)addr<4294967296LL); output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } static void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map) { assert(map>=0); /*if(map<0) emit_writeword_indexed(rt, addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs); else*/ { assem_debug("mov %%%s,%x(%%%s,%%%s)",regname[rt],addr,regname[rs],regname[map]); assert(rs!=ESP); //output_byte(0x67); if(map>=8) { assert(map==HOST_TEMPREG); output_rex(0,0,map>>3,0); } output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map&7,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map&7,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map&7,rs); output_w32(addr); } } } static void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map) { assert(map>=0); assert(rh>=0); emit_writeword_indexed_tlb(rh, addr, rs, map); emit_writeword_indexed_tlb(rl, addr+4, rs, map); } static void emit_writehword(int rt, int addr) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movw %%%s,%llx",regname[rt]+1,addr); output_byte(0x66); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_writehword_indexed(int rt, intptr_t addr, int rs) { assem_debug("movw %%%s,%llx+%%%s",regname[rt]+1,addr,regname[rs]); output_byte(0x66); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); output_byte(addr); } else { assert((uintptr_t)addr<4294967296LL); output_modrm(2,rs,rt); output_w32(addr); } } static void emit_writehword_indexed_tlb(int rt, int addr, int rs, int map) { assert(map>=0); /*if(map<0) emit_writehword_indexed(rt, addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs); else*/ { assem_debug("movw %%%s,%x(%%%s,%%%s)",regname[rt]+1,addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x66); if(rt>=4||rs>=8||map>=8) { if(map>=8) assert(map==HOST_TEMPREG); assert(rs<8); output_rex(0,rt>>3,map>>3,rs>>3); } output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt&7); output_sib(0,map&7,rs&7); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt&7); output_sib(0,map&7,rs&7); output_byte(addr); } else { output_modrm(2,4,rt&7); output_sib(0,map&7,rs&7); output_w32(addr); } } } static void emit_writebyte(int rt, int addr) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movb %%%cl,%llx",regname[rt][1],addr); if(rt>=4) output_rex(0,rt>>3,0,0); output_byte(0x88); output_modrm(0,5,rt&7); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_writebyte_indexed(int rt, intptr_t addr, int rs) { assem_debug("movb %%%cl,%llx+%%%s",regname[rt][1],addr,regname[rs]); if(rt>=4||rs>=8) output_rex(0,rt>>3,0,rs>>3); output_byte(0x88); if(addr<128&&addr>=-128) { output_modrm(1,rs&7,rt&7); output_byte(addr); } else { assert((uintptr_t)addr<4294967296LL); output_modrm(2,rs,rt); output_w32(addr); } } static void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map) { assert(map>=0); /*if(map<0) emit_writebyte_indexed(rt, addr+(intptr_t)g_dev.rdram.dram-0x80000000LL, rs); else*/ { assem_debug("movb %%%cl,%x(%%%s,%%%s)",regname[rt][1],addr,regname[rs],regname[map]); assert(rs!=ESP); //output_byte(0x67); if(rt>=4||rs>=8||map>=8) { if(map>=8) assert(map==HOST_TEMPREG); assert(rs<8); output_rex(0,rt>>3,map>>3,rs>>3); } output_byte(0x88); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt&7); output_sib(0,map&7,rs&7); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt&7); output_sib(0,map&7,rs&7); output_byte(addr); } else { output_modrm(2,4,rt&7); output_sib(0,map&7,rs&7); output_w32(addr); } } } static void emit_writeword_imm(int imm, intptr_t addr) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movl $%x,%llx",imm,addr); output_byte(0xC7); output_modrm(0,5,0); output_w32(addr-(intptr_t)out-8); // Note: rip-relative in 64-bit mode output_w32(imm); } static void emit_writeword_imm_esp(int imm, intptr_t addr) { assert(0); assem_debug("mov $%x,%llx(%%esp)",imm,addr); assert(addr>=-128&&addr<128); output_byte(0xC7); output_modrm(!!addr,4,0); output_sib(0,4,4); if(addr) output_byte(addr); output_w32(imm); } static void emit_writedword_imm32(int imm, intptr_t addr) { assert(0); assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movq $%x,%llx",imm,addr); output_rex(1,0,0,0); output_byte(0xC7); output_modrm(0,5,0); output_w32(addr-(intptr_t)out-8); // Note: rip-relative in 64-bit mode output_w32(imm); // Note: This 32-bit value will be sign extended } static void emit_writebyte_imm(int imm, intptr_t addr) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movb $%x,%llx",imm,addr); assert(imm>=-128&&imm<128); output_byte(0xC6); output_modrm(0,5,0); output_w32(addr-(intptr_t)out-5); // Note: rip-relative in 64-bit mode output_byte(imm); } static void emit_writedword(int rt, intptr_t addr) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("movq %%%s,%llx",regname[rt],addr); output_rex(1,rt>>3,0,0); output_byte(0x89); output_modrm(0,5,rt&7); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_mul(int rs) { assem_debug("mul %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,4); } static void emit_imul(int rs) { assem_debug("imul %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,5); } static void emit_div(int rs) { assem_debug("div %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,6); } static void emit_idiv(int rs) { assem_debug("idiv %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,7); } static void emit_cdq(void) { assem_debug("cdq"); output_byte(0x99); } // Load 2 immediates optimizing for small code size static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2) { emit_movimm(imm1,rt1); if(imm2-imm1<128&&imm2-imm1>=-128) emit_addimm(rt1,imm2-imm1,rt2); else emit_movimm(imm2,rt2); } // special case for checking pending_exception static void emit_cmpmem_imm(intptr_t addr, int imm) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assert(imm<128&&imm>=-127); assem_debug("cmp $%d,%llx",imm,addr); output_byte(0x83); output_modrm(0,5,7); output_w32(addr-(intptr_t)out-5); // Note: rip-relative in 64-bit mode output_byte(imm); } // special case for checking invalid_code static void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) { assert(0); } static void emit_cmpmem_indexedsr12_reg(int base,int r,int imm) { assert(imm<128&&imm>=-127); assert(r>=0&&r<8); emit_shrimm(r,12,r); assem_debug("cmp $%d,(%%%s,%%%s)",imm,regname[r],regname[base]); output_byte(0x80); output_modrm(0,4,7); assert(r!=base); if(r!=EBP) { output_sib(0,base,r); }else{ output_sib(0,r,base); } output_byte(imm); } // special case for checking hash_table static void emit_cmpmem_dualindexed(int base,int rs,int rt) { assert(rs>=0&&rs<8); assert(rt>=0&&rt<8); assert(base==HOST_TEMPREG); assem_debug("cmp (%%%s,%%%s),%%%s",regname[rs],regname[base],regname[rt]); output_rex(0,0,0,base>>3); output_byte(0x3B); output_modrm(0,4,rt); output_sib(0,rs,base&7); } static void emit_readdword_dualindexed(int offset, int base,int rs,int rt) { assert(rs>=0&&rs<8); assert(rt>=0&&rt<8); assert(base==HOST_TEMPREG); assert(offset<128&&offset>=-128); assem_debug("mov %x(%%%s,%%%s),%%%s",offset,regname[rs],regname[base],regname[rt]); output_rex(1,0,0,base>>3); output_byte(0x8B); if(offset==0) { output_modrm(0,4,rt); output_sib(0,rs,base&7); } else if(offset<128&&offset>=-128) { output_modrm(1,4,rt); output_sib(0,rs,base&7); output_byte(offset); } } // special case for checking memory_map in verify_mapping static void emit_cmpmem(intptr_t addr,int rt) { assert(0); assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assert(rt>=0&&rt<8); assem_debug("cmp %llx,%%%s",addr,regname[rt]); output_byte(0x39); output_modrm(0,5,rt); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } // Used to preload hash table entries #ifdef IMM_PREFETCH static void emit_prefetch(void *addr) { assert(0); assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("prefetch %llx",(intptr_t)addr); output_byte(0x0F); output_byte(0x18); output_modrm(0,5,1); output_w32((intptr_t)addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } #endif /*void emit_submem(int r,intptr_t addr) { assert(r>=0&&r<8); assem_debug("sub %llx,%%%s",addr,regname[r]); output_byte(0x2B); output_modrm(0,5,r); output_w32(addr); }*/ static void emit_readptr(intptr_t addr, int rt) { emit_movmem64(addr,rt); } static void emit_flds(int r) { assem_debug("flds (%%%s)",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fldl(int r) { assem_debug("fldl (%%%s)",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fucomip(u_int r) { assem_debug("fucomip %d",r); assert(r<8); output_byte(0xdf); output_byte(0xe8+r); } static void emit_fchs(void) { assem_debug("fchs"); output_byte(0xd9); output_byte(0xe0); } static void emit_fabs(void) { assem_debug("fabs"); output_byte(0xd9); output_byte(0xe1); } static void emit_fsqrt(void) { assem_debug("fsqrt"); output_byte(0xd9); output_byte(0xfa); } static void emit_fadds(int r) { assem_debug("fadds (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_faddl(int r) { assem_debug("faddl (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fadd(int r) { assem_debug("fadd st%d",r); output_byte(0xd8); output_byte(0xc0+r); } static void emit_fsubs(int r) { assem_debug("fsubs (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } static void emit_fsubl(int r) { assem_debug("fsubl (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } static void emit_fsub(int r) { assem_debug("fsub st%d",r); output_byte(0xd8); output_byte(0xe0+r); } static void emit_fmuls(int r) { assem_debug("fmuls (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } static void emit_fmull(int r) { assem_debug("fmull (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } static void emit_fmul(int r) { assem_debug("fmul st%d",r); output_byte(0xd8); output_byte(0xc8+r); } static void emit_fdivs(int r) { assem_debug("fdivs (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } static void emit_fdivl(int r) { assem_debug("fdivl (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } static void emit_fdiv(int r) { assem_debug("fdiv st%d",r); output_byte(0xd8); output_byte(0xf0+r); } static void emit_fpop(void) { // fstp st(0) assem_debug("fpop"); output_byte(0xdd); output_byte(0xd8); } static void emit_fildl(int r) { assem_debug("fildl (%%%s)",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fildll(int r) { assem_debug("fildll (%%%s)",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,5); else {output_modrm(1,EBP,5);output_byte(0);} } static void emit_fistpl(int r) { assem_debug("fistpl (%%%s)",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } static void emit_fistpll(int r) { assem_debug("fistpll (%%%s)",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,7); else {output_modrm(1,EBP,7);output_byte(0);} } static void emit_fstps(int r) { assem_debug("fstps (%%%s)",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } static void emit_fstpl(int r) { assem_debug("fstpl (%%%s)",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } static void emit_fnstcw_stack(void) { assem_debug("fnstcw (%%esp)"); output_byte(0xd9); output_modrm(0,4,7); output_sib(0,4,4); } static void emit_fldcw_stack(void) { assem_debug("fldcw (%%esp)"); output_byte(0xd9); output_modrm(0,4,5); output_sib(0,4,4); } static void emit_fldcw_indexed(intptr_t addr,int r) { assert(0); assem_debug("fldcw %llx(%%%s,2)",addr,regname[r]); output_byte(0xd9); output_modrm(0,4,5); output_sib(1,r,5); output_w32(addr); } static void emit_fldcw_indexedx4(int addr, int r) { assem_debug("fldcw (%%%s,%%%s,4)",regname[addr],regname[r]); assert(addr==HOST_TEMPREG); output_rex(0,0,0,addr>>3); output_byte(0xd9); output_modrm(0,4,5); output_sib(2,r,addr&7); } static void emit_fldcw(intptr_t addr) { assert((intptr_t)addr-(intptr_t)out>=-2147483648LL&&(intptr_t)addr-(intptr_t)out<2147483647LL); assem_debug("fldcw %llx",addr); output_byte(0xd9); output_modrm(0,5,5); output_w32(addr-(intptr_t)out-4); // Note: rip-relative in 64-bit mode } static void emit_movss_load(u_int addr,u_int ssereg) { assem_debug("movss (%%%s),xmm%d",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } static void emit_movsd_load(u_int addr,u_int ssereg) { assem_debug("movsd (%%%s),xmm%d",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf2); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } static void emit_movd_store(u_int ssereg,u_int addr) { assem_debug("movd xmm%d,(%%%s)",ssereg,regname[addr]); assert(ssereg<8); output_byte(0x66); output_byte(0x0f); output_byte(0x7e); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } static void emit_cvttps2dq(u_int ssereg1,u_int ssereg2) { assem_debug("cvttps2dq xmm%d,xmm%d",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x5b); output_modrm(3,ssereg1,ssereg2); } static void emit_cvttpd2dq(u_int ssereg1,u_int ssereg2) { assem_debug("cvttpd2dq xmm%d,xmm%d",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0x66); output_byte(0x0f); output_byte(0xe6); output_modrm(3,ssereg1,ssereg2); } static unsigned int count_bits(u_int reglist) { int count=0; while(reglist) { count+=reglist&1; reglist>>=1; } return count; } // Save registers before function call // This code is executed infrequently so we try to minimize code size // by pushing registers onto the stack instead of writing them to their // usual locations static void save_regs2(u_int reglist) { int hr; reglist&=~(1<>hr)&1) { emit_pushreg(hr); } } } } emit_addimm64(ESP,-(16-count)*8,ESP); } // Restore registers after function call static void restore_regs2(u_int reglist) { int hr; reglist&=~(1<=0;hr--) { if(hr!=EXCLUDE_REG) { if((reglist>>hr)&1) { emit_popreg(hr); } } } } } static void save_regs(u_int reglist) { reglist&=CALLER_SAVED_REGS; // only save the caller-save registers save_regs2(reglist); } static void restore_regs(u_int reglist) { reglist&=CALLER_SAVED_REGS; // only restore the caller-save registers restore_regs2(reglist); } /* Stubs/epilogue */ static void emit_extjump2(intptr_t addr, int target, intptr_t linker) { u_char *ptr=(u_char *)addr; if(*ptr==0x0f) { assert(ptr[1]>=0x80&&ptr[1]<=0x8f); addr+=2; } else { assert(*ptr==0xe8||*ptr==0xe9); addr++; } emit_lea_rip(addr,ARG1_REG); emit_movimm(target,ARG2_REG); emit_jmp(linker); } static void do_invstub(int n) { u_int reglist=stubs[n][3]; set_jump_target(stubs[n][1],(intptr_t)out); save_regs(reglist); emit_call((intptr_t)invalidate_block_reg[stubs[n][4]]); restore_regs(reglist); emit_jmp(stubs[n][2]); // return address } static intptr_t do_dirty_stub(int i, struct ll_entry * head) { assem_debug("do_dirty_stub %x",head->vaddr); emit_movimm64((intptr_t)head,ARG1_REG); emit_call((intptr_t)verify_code); intptr_t entry=(intptr_t)out; load_regs_entry(i); if(entry==(intptr_t)out) entry=instr_addr[i]; emit_jmp(instr_addr[i]); return entry; } static void do_dirty_stub_ds(struct ll_entry *head) { assem_debug("do_dirty_stub_ds %x",head->vaddr); emit_movimm64((intptr_t)head,ARG1_REG); emit_call((intptr_t)verify_code); } /* TLB */ static int do_tlb_r(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. // if(addr<0x80800000) load directly from RDRAM to avoid generating tlb code if((signed int)addr>=(signed int)0xC0000000) { emit_movmem64((intptr_t)(g_dev.r4300.new_dynarec_hot_state.memory_map+(addr>>12)),map); } else if((signed int)addr<(signed int)0x80800000) { emit_loadreg(ROREG,HOST_TEMPREG); // On 64bit ROREG is needed to load from RDRAM return HOST_TEMPREG; } else return -1; // No mapping } else { if(cache<0) emit_loadreg(MMREG,cache=HOST_TEMPREG); assert(s!=map); emit_shrimm(s,12,map); // Schedule this while we wait on the load //if(x) emit_xorimm(addr,x,addr); emit_readdword_dualindexedx8(cache,map,map); } return map; } static int do_tlb_r_branch(int map, int c, u_int addr, intptr_t *jaddr) { if(!c||(signed int)addr>=(signed int)0xC0000000) { emit_test64(map,map); *jaddr=(intptr_t)out; emit_js(0); emit_shlimm64(map,2,map); } return map; } static int do_tlb_w(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { if(addr<0x80800000||addr>=0xC0000000) { emit_movmem64((intptr_t)(g_dev.r4300.new_dynarec_hot_state.memory_map+(addr>>12)),map); } else { return -1; // No mapping } } else { if(cache<0) emit_loadreg(MMREG,cache=HOST_TEMPREG); assert(s!=map); emit_shrimm(s,12,map); // Schedule this while we wait on the load //if(x) emit_xorimm(s,x,addr); emit_readdword_dualindexedx8(cache,map,map); } emit_shlimm64(map,2,map); return map; } static void do_tlb_w_branch(int map, int c, u_int addr, intptr_t *jaddr) { if(!c||addr<0x80800000||addr>=0xC0000000) { *jaddr=(intptr_t)out; emit_jc(0); } } // We don't need this for x64 static void generate_map_const(u_int addr,int reg) { // void *mapaddr=g_dev.r4300.new_dynarec_hot_state.memory_map+(addr>>12); } static void set_rounding_mode(int s,int temp) { assert(temp>=0); emit_movimm(3,temp); emit_and(s,temp,temp); emit_lea_rip((intptr_t)g_dev.r4300.new_dynarec_hot_state.rounding_modes, HOST_TEMPREG); emit_fldcw_indexedx4(HOST_TEMPREG, temp); } /* Special assem */ static void shift_assemble_x64(int i,struct regstat *i_regs) { if(rt1[i]) { if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV { signed char s,t,shift; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(t>=0){ if(rs1[i]==0) { emit_zeroreg(t); } else if(rs2[i]==0) { assert(s>=0); if(s!=t) emit_mov(s,t); } else { signed char temp=get_reg(i_regs->regmap,-1); assert(s>=0); if(t==ECX&&s!=ECX) { if(shift!=ECX) emit_mov(shift,ECX); if(rt1[i]==rs2[i]) {shift=temp;} if(s!=shift) emit_mov(s,shift); } else { if(rt1[i]==rs2[i]) {emit_mov(shift,temp);shift=temp;} if(s!=t) emit_mov(s,t); if(shift!=ECX) { if(i_regs->regmap[ECX]<0) emit_mov(shift,ECX); else { if(i_regs->regmap[ECX]>=INVCP) emit_xchg64(shift,ECX); else emit_xchg(shift,ECX); } } } if(opcode2[i]==4) // SLLV { emit_shlcl(t==ECX?shift:t); } if(opcode2[i]==6) // SRLV { emit_shrcl(t==ECX?shift:t); } if(opcode2[i]==7) // SRAV { emit_sarcl(t==ECX?shift:t); } if(shift!=ECX&&i_regs->regmap[ECX]>=0) { if(i_regs->regmap[ECX]>=INVCP) emit_xchg64(shift,ECX); else emit_xchg(shift,ECX); } } } } else { // DSLLV/DSRLV/DSRAV signed char sh,sl,th,tl,shift; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(tl>=0){ if(rs1[i]==0) { emit_zeroreg(tl); if(th>=0) emit_zeroreg(th); } else if(rs2[i]==0) { assert(sl>=0); if(sl!=tl) emit_mov(sl,tl); if(th>=0&&sh!=th) emit_mov(sh,th); } else { int temp=get_reg(i_regs->regmap,-1); int real_tl=tl; int real_th=th; if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register assert(sl>=0); assert(sh>=0); if(tl==ECX&&sl!=ECX) { if(shift!=ECX) emit_mov(shift,ECX); if((sl!=shift)&&(shift!=tl)) emit_mov(sl,shift); if(th>=0 && sh!=th) emit_mov(sh,th); if(shift==tl) { emit_pushreg(sl); tl=sl; } } else if(th==ECX&&sh!=ECX) { if(shift!=ECX) emit_mov(shift,ECX); if(sh!=shift) emit_mov(sh,shift); if((sl!=tl)&&(shift!=tl)) emit_mov(sl,tl); if(shift==tl) { emit_pushreg(sl); tl=sl; } } else { if((sl!=tl)&&(shift!=tl)) emit_mov(sl,tl); if(th>=0 && sh!=th) emit_mov(sh,th); if(shift!=ECX) { if(shift==tl) { emit_pushreg(sl); tl=sl; } if(i_regs->regmap[ECX]>=INVCP) emit_xchg64(shift,ECX); else emit_xchg(shift,ECX); } } if(opcode2[i]==0x14) // DSLLV { if(th>=0) emit_shldcl(th==ECX?shift:th,tl==ECX?shift:tl); emit_shlcl(tl==ECX?shift:tl); emit_testimm(ECX,32); if(th>=0) emit_cmovne_reg(tl==ECX?shift:tl,th==ECX?shift:th); emit_cmovne(&const_zero,tl==ECX?shift:tl); } if(opcode2[i]==0x16) // DSRLV { assert(th>=0); emit_shrdcl(tl==ECX?shift:tl,th==ECX?shift:th); emit_shrcl(th==ECX?shift:th); emit_testimm(ECX,32); emit_cmovne_reg(th==ECX?shift:th,tl==ECX?shift:tl); if(real_th>=0) emit_cmovne(&const_zero,th==ECX?shift:th); } if(opcode2[i]==0x17) // DSRAV { assert(th>=0); emit_shrdcl(tl==ECX?shift:tl,th==ECX?shift:th); if(real_th>=0) { assert(temp>=0); emit_mov(th==ECX?shift:th,temp==ECX?shift:temp); } emit_sarcl(th==ECX?shift:th); if(real_th>=0) emit_sarimm(temp==ECX?shift:temp,31,temp==ECX?shift:temp); emit_testimm(ECX,32); emit_cmovne_reg(th==ECX?shift:th,tl==ECX?shift:tl); if(real_th>=0) emit_cmovne_reg(temp==ECX?shift:temp,th==ECX?shift:th); } if(real_tl==ECX&&sl!=ECX&&shift==real_tl) { emit_mov(sl,real_tl); emit_popreg(sl); } else if(th==ECX&&sh!=ECX&&shift==real_tl) { emit_mov(sl,real_tl); emit_popreg(sl); } else { if(shift!=ECX) { if(i_regs->regmap[ECX]>=INVCP) emit_xchg64(shift,ECX); else emit_xchg(shift,ECX); if(real_tl==shift) { emit_mov(sl,real_tl); emit_popreg(sl); } } } } } } } } #define shift_assemble shift_assemble_x64 static void loadlr_assemble_x64(int i,struct regstat *i_regs) { signed char s,th,tl,temp,temp2,temp2h,addr,map=-1,cache=-1; int offset,type=0,memtarget=0,c=0; intptr_t jaddr=0; u_int hr,reglist=0; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); temp=get_reg(i_regs->regmap,-1); temp2=get_reg(i_regs->regmap,FTEMP); temp2h=get_reg(i_regs->regmap,FTEMP|64); addr=get_reg(i_regs->regmap,AGEN1+(i&1)); assert(addr<0); assert(temp>=0); assert(temp2>=0); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { c=(i_regs->wasconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } if(offset||s<0||c) addr=temp2; else addr=s; int dummy=(rt1[i]==0)||(tl!=get_reg(i_regs->regmap,rt1[i])); // ignore loads to r0 and unneeded reg switch(opcode[i]) { case 0x22: type=LOADWL_STUB; break; case 0x26: type=LOADWR_STUB; break; case 0x1A: type=LOADDL_STUB; break; case 0x1B: type=LOADDR_STUB; break; } #ifndef INTERPRET_LOADLR int ldlr=(opcode[i]==0x1A||opcode[i]==0x1B); // LDL/LDR always do inline_readstub if non constant if(!using_tlb) { if(!c&&!ldlr) { emit_cmpimm(addr,0x800000); jaddr=(intptr_t)out; emit_jno(0); } #ifdef RAM_OFFSET if(((!c&&!ldlr)||memtarget)&&!dummy) { map=get_reg(i_regs->regmap,ROREG); if(map<0) emit_loadreg(ROREG,map=HOST_TEMPREG); } #endif }else{ // using tlb map=get_reg(i_regs->regmap,TLREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<=0); if(!c) { emit_lea8(addr,temp); emit_andimm(addr,~3,temp2); emit_readword_indexed_tlb(0,temp2,map,temp2); emit_andimm(temp,24,temp); if (opcode[i]==0x26) emit_xorimm(temp,24,temp); // LWR if(temp!=ECX) emit_xchg64(ECX,temp); emit_movimm(-1,HOST_TEMPREG); if (opcode[i]==0x26) { emit_shrcl(HOST_TEMPREG); emit_shrcl(temp2==ECX?temp:temp2); }else{ emit_shlcl(HOST_TEMPREG); emit_shlcl(temp2==ECX?temp:temp2); } emit_mov(HOST_TEMPREG,ECX); emit_not(ECX,ECX); if(temp!=ECX) emit_xchg64(temp,ECX); emit_and(temp,tl,tl); emit_or(temp2,tl,tl); } else { int shift=((constmap[i][s]+offset)&3)<<3; uint32_t mask=~UINT32_C(0); if (opcode[i]==0x26) { //LWR shift^=24; mask>>=shift; } else { //LWL mask<<=shift; } if((constmap[i][s]+offset)&3) emit_andimm(addr,~3,temp2); if(shift) { emit_readword_indexed_tlb(0,temp2,map,temp2); if (opcode[i]==0x26) emit_shrimm(temp2,shift,temp2); else emit_shlimm(temp2,shift,temp2); emit_andimm(tl,~mask,tl); emit_or(temp2,tl,tl); } else emit_readword_indexed_tlb(0,temp2,map,tl); } } if(opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR assert(tl>=0); assert(th>=0); assert(temp2h>=0); if(!c) { //TODO: implement recompiled code inline_readstub(type,i,0,addr,i_regs,rt1[i],ccadj[i],reglist); } else { int shift=((constmap[i][s]+offset)&7)<<3; uint64_t mask=~UINT64_C(0); if (opcode[i]==0x1B) { //LDR shift^=56; mask>>=shift; } else { //LDL mask<<=shift; } if((constmap[i][s]+offset)&7) emit_andimm(addr,~7,temp2); if(shift) { emit_readdword_indexed_tlb(0,temp2,map,temp2h,temp2); if (opcode[i]==0x1B) { emit_shrdimm(temp2h,temp2,shift,temp2h); emit_shrimm(temp2,shift,temp2); } else { emit_shldimm(temp2h,temp2,shift,temp2h); emit_shlimm(temp2,shift,temp2); } emit_andimm(tl,~mask,tl); emit_andimm(th,~mask>>32,th); emit_or(temp2,tl,tl); emit_or(temp2h,th,th); } else emit_readdword_indexed_tlb(0,temp2,map,th,tl); } } } if(jaddr) { add_stub(type,jaddr,(intptr_t)out,i,addr,(intptr_t)i_regs,ccadj[i],reglist); } else if(c&&!memtarget) { inline_readstub(type,i,(constmap[i][s]+offset),addr,i_regs,rt1[i],ccadj[i],reglist); } #else inline_readstub(type,i,c?(constmap[i][s]+offset):0,addr,i_regs,rt1[i],ccadj[i],reglist); #endif } #define loadlr_assemble loadlr_assemble_x64 static void fconv_assemble_x64(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char rs=get_reg(i_regs->regmap,CSREG); assert(rs>=0); emit_testimm(rs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,rs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCONV #ifdef __SSE__ if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { // trunc_w_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_movss_load(temp,0); emit_cvttps2dq(0,0); // float->int, truncate if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_movd_store(0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { // trunc_w_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_movsd_load(temp,0); emit_cvttpd2dq(0,0); // double->int, truncate emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_movd_store(0,temp); return; } #endif if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { // cvt_s_w emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_fildl(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); return; } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { // cvt_d_w emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_fildl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); return; } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { // cvt_s_l emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fildll(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); return; } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { // cvt_d_l emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fildll(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { // cvt_d_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { // cvt_s_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); return; } if(opcode2[i]==0x10) { // cvt_*_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); } if(opcode2[i]==0x11) { // cvt_*_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); } if((source[i]&0x3f)<0x10) { emit_fnstcw_stack(); if((source[i]&3)==0) emit_fldcw((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[0]); //DebugMessage(M64MSG_VERBOSE, "round"); if((source[i]&3)==1) emit_fldcw((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[1]); //DebugMessage(M64MSG_VERBOSE, "trunc"); if((source[i]&3)==2) emit_fldcw((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[2]); //DebugMessage(M64MSG_VERBOSE, "ceil"); if((source[i]&3)==3) emit_fldcw((intptr_t)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[3]); //DebugMessage(M64MSG_VERBOSE, "floor"); } if((source[i]&0x3f)==0x24||(source[i]&0x3c)==0x0c) { // cvt_w_* if(opcode2[i]!=0x10||((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fistpl(temp); } if((source[i]&0x3f)==0x25||(source[i]&0x3c)==0x08) { // cvt_l_* if(opcode2[i]!=0x11||((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fistpll(temp); } if((source[i]&0x3f)<0x10) { emit_fldcw_stack(); } return; #endif // C emulation code u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,FSREG); save_regs(reglist); if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_s_w); } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)cvt_d_w); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_s_l); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_d_l); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)cvt_d_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_l_s); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_s_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); emit_call((intptr_t)cvt_l_d); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_l_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_w_s); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_w_s); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_l_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)round_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)trunc_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)ceil_w_d); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); emit_call((intptr_t)floor_w_d); } restore_regs(reglist); return; } #define fconv_assemble fconv_assemble_x64 static void fcomp_assemble(int i,struct regstat *i_regs) { signed char fs=get_reg(i_regs->regmap,FSREG); signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,cs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCOMP if((source[i]&0x3f)==0x30) { emit_andimm(fs,~0x800000,fs); return; } if((source[i]&0x3e)==0x38) { // sf/ngle - these should throw exceptions for NaNs emit_andimm(fs,~0x800000,fs); return; } if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],temp); emit_flds(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); emit_movimm(0x800000,temp); emit_or(fs,temp,fs); emit_xor(temp,fs,temp); emit_fucomip(1); emit_fpop(); if((source[i]&0x3f)==0x31) emit_cmovnp_reg(temp,fs); // c_un_s if((source[i]&0x3f)==0x32) {emit_cmovne_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_eq_s if((source[i]&0x3f)==0x33) emit_cmovne_reg(temp,fs); // c_ueq_s if((source[i]&0x3f)==0x34) {emit_cmovnc_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_olt_s if((source[i]&0x3f)==0x35) emit_cmovnc_reg(temp,fs); // c_ult_s if((source[i]&0x3f)==0x36) {emit_cmova_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_ole_s if((source[i]&0x3f)==0x37) emit_cmova_reg(temp,fs); // c_ule_s if((source[i]&0x3f)==0x3a) emit_cmovne_reg(temp,fs); // c_seq_s if((source[i]&0x3f)==0x3b) emit_cmovne_reg(temp,fs); // c_ngl_s if((source[i]&0x3f)==0x3c) emit_cmovnc_reg(temp,fs); // c_lt_s if((source[i]&0x3f)==0x3d) emit_cmovnc_reg(temp,fs); // c_nge_s if((source[i]&0x3f)==0x3e) emit_cmova_reg(temp,fs); // c_le_s if((source[i]&0x3f)==0x3f) emit_cmova_reg(temp,fs); // c_ngt_s return; } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],temp); emit_fldl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); emit_movimm(0x800000,temp); emit_or(fs,temp,fs); emit_xor(temp,fs,temp); emit_fucomip(1); emit_fpop(); if((source[i]&0x3f)==0x31) emit_cmovnp_reg(temp,fs); // c_un_d if((source[i]&0x3f)==0x32) {emit_cmovne_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_eq_d if((source[i]&0x3f)==0x33) emit_cmovne_reg(temp,fs); // c_ueq_d if((source[i]&0x3f)==0x34) {emit_cmovnc_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_olt_d if((source[i]&0x3f)==0x35) emit_cmovnc_reg(temp,fs); // c_ult_d if((source[i]&0x3f)==0x36) {emit_cmova_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_ole_d if((source[i]&0x3f)==0x37) emit_cmova_reg(temp,fs); // c_ule_d if((source[i]&0x3f)==0x3a) emit_cmovne_reg(temp,fs); // c_seq_d if((source[i]&0x3f)==0x3b) emit_cmovne_reg(temp,fs); // c_ngl_d if((source[i]&0x3f)==0x3c) emit_cmovnc_reg(temp,fs); // c_lt_d if((source[i]&0x3f)==0x3d) emit_cmovnc_reg(temp,fs); // c_nge_d if((source[i]&0x3f)==0x3e) emit_cmova_reg(temp,fs); // c_le_d if((source[i]&0x3f)==0x3f) emit_cmova_reg(temp,fs); // c_ngt_d return; } #endif // C only u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],ARG3_REG); if((source[i]&0x3f)==0x30) emit_call((intptr_t)c_f_s); if((source[i]&0x3f)==0x31) emit_call((intptr_t)c_un_s); if((source[i]&0x3f)==0x32) emit_call((intptr_t)c_eq_s); if((source[i]&0x3f)==0x33) emit_call((intptr_t)c_ueq_s); if((source[i]&0x3f)==0x34) emit_call((intptr_t)c_olt_s); if((source[i]&0x3f)==0x35) emit_call((intptr_t)c_ult_s); if((source[i]&0x3f)==0x36) emit_call((intptr_t)c_ole_s); if((source[i]&0x3f)==0x37) emit_call((intptr_t)c_ule_s); if((source[i]&0x3f)==0x38) emit_call((intptr_t)c_sf_s); if((source[i]&0x3f)==0x39) emit_call((intptr_t)c_ngle_s); if((source[i]&0x3f)==0x3a) emit_call((intptr_t)c_seq_s); if((source[i]&0x3f)==0x3b) emit_call((intptr_t)c_ngl_s); if((source[i]&0x3f)==0x3c) emit_call((intptr_t)c_lt_s); if((source[i]&0x3f)==0x3d) emit_call((intptr_t)c_nge_s); if((source[i]&0x3f)==0x3e) emit_call((intptr_t)c_le_s); if((source[i]&0x3f)==0x3f) emit_call((intptr_t)c_ngt_s); } if(opcode2[i]==0x11) { emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],ARG3_REG); if((source[i]&0x3f)==0x30) emit_call((intptr_t)c_f_d); if((source[i]&0x3f)==0x31) emit_call((intptr_t)c_un_d); if((source[i]&0x3f)==0x32) emit_call((intptr_t)c_eq_d); if((source[i]&0x3f)==0x33) emit_call((intptr_t)c_ueq_d); if((source[i]&0x3f)==0x34) emit_call((intptr_t)c_olt_d); if((source[i]&0x3f)==0x35) emit_call((intptr_t)c_ult_d); if((source[i]&0x3f)==0x36) emit_call((intptr_t)c_ole_d); if((source[i]&0x3f)==0x37) emit_call((intptr_t)c_ule_d); if((source[i]&0x3f)==0x38) emit_call((intptr_t)c_sf_d); if((source[i]&0x3f)==0x39) emit_call((intptr_t)c_ngle_d); if((source[i]&0x3f)==0x3a) emit_call((intptr_t)c_seq_d); if((source[i]&0x3f)==0x3b) emit_call((intptr_t)c_ngl_d); if((source[i]&0x3f)==0x3c) emit_call((intptr_t)c_lt_d); if((source[i]&0x3f)==0x3d) emit_call((intptr_t)c_nge_d); if((source[i]&0x3f)==0x3e) emit_call((intptr_t)c_le_d); if((source[i]&0x3f)==0x3f) emit_call((intptr_t)c_ngt_d); } restore_regs(reglist); emit_loadreg(FSREG,fs); } static void float_assemble(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); intptr_t jaddr=(intptr_t)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(intptr_t)out,i,cs,(intptr_t)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FLOAT if((source[i]&0x3f)==6) // mov { if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); } } return; } if((source[i]&0x3f)>3) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } } if((source[i]&0x3f)==4) // sqrt emit_fsqrt(); if((source[i]&0x3f)==5) // abs emit_fabs(); if((source[i]&0x3f)==7) // neg emit_fchs(); if(opcode2[i]==0x10) { emit_fstps(temp); } if(opcode2[i]==0x11) { emit_fstpl(temp); } return; } if((source[i]&0x3f)<4) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); } if(((source[i]>>11)&0x1f)!=((source[i]>>16)&0x1f)) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],temp); if((source[i]&0x3f)==0) emit_fadds(temp); if((source[i]&0x3f)==1) emit_fsubs(temp); if((source[i]&0x3f)==2) emit_fmuls(temp); if((source[i]&0x3f)==3) emit_fdivs(temp); } else if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],temp); if((source[i]&0x3f)==0) emit_faddl(temp); if((source[i]&0x3f)==1) emit_fsubl(temp); if((source[i]&0x3f)==2) emit_fmull(temp); if((source[i]&0x3f)==3) emit_fdivl(temp); } } else { if((source[i]&0x3f)==0) emit_fadd(0); if((source[i]&0x3f)==1) emit_fsub(0); if((source[i]&0x3f)==2) emit_fmul(0); if((source[i]&0x3f)==3) emit_fdiv(0); } if(opcode2[i]==0x10) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } emit_fstps(temp); } if(opcode2[i]==0x11) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } emit_fstpl(temp); } return; } #endif u_int hr,reglist=0; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,FSREG); if(opcode2[i]==0x10) { // Single precision save_regs(reglist); switch(source[i]&0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],ARG3_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG4_REG); break; case 0x04: emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG3_REG); break; case 0x05: case 0x06: case 0x07: emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f],ARG2_REG); break; } switch(source[i]&0x3f) { case 0x00: emit_call((intptr_t)add_s);break; case 0x01: emit_call((intptr_t)sub_s);break; case 0x02: emit_call((intptr_t)mul_s);break; case 0x03: emit_call((intptr_t)div_s);break; case 0x04: emit_call((intptr_t)sqrt_s);break; case 0x05: emit_call((intptr_t)abs_s);break; case 0x06: emit_call((intptr_t)mov_s);break; case 0x07: emit_call((intptr_t)neg_s);break; } restore_regs(reglist); } if(opcode2[i]==0x11) { // Double precision save_regs(reglist); switch(source[i]&0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],ARG3_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG4_REG); break; case 0x04: emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG2_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG3_REG); break; case 0x05: case 0x06: case 0x07: emit_lea_rip((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31,ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],ARG1_REG); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f],ARG2_REG); break; } switch(source[i]&0x3f) { case 0x00: emit_call((intptr_t)add_d);break; case 0x01: emit_call((intptr_t)sub_d);break; case 0x02: emit_call((intptr_t)mul_d);break; case 0x03: emit_call((intptr_t)div_d);break; case 0x04: emit_call((intptr_t)sqrt_d);break; case 0x05: emit_call((intptr_t)abs_d);break; case 0x06: emit_call((intptr_t)mov_d);break; case 0x07: emit_call((intptr_t)neg_d);break; } restore_regs(reglist); } } static void multdiv_assemble_x64(int i,struct regstat *i_regs) { // case 0x18: MULT // case 0x19: MULTU // case 0x1A: DIV // case 0x1B: DIVU // case 0x1C: DMULT // case 0x1D: DMULTU // case 0x1E: DDIV // case 0x1F: DDIVU if(rs1[i]&&rs2[i]) { if((opcode2[i]&4)==0) // 32-bit { #ifndef INTERPRET_MULT if((opcode2[i]==0x18) || (opcode2[i]==0x19)) { signed char m1=get_reg(i_regs->regmap,rs1[i]); signed char m2=get_reg(i_regs->regmap,rs2[i]); assert(m1>=0); assert(m2>=0); emit_mov(m1,EAX); if(opcode2[i]==0x18) //MULT emit_imul(m2); else if(opcode2[i]==0x19) //MULTU emit_mul(m2); } else #endif #ifndef INTERPRET_DIV if((opcode2[i]==0x1A) || (opcode2[i]==0x1B)) { signed char d1=get_reg(i_regs->regmap,rs1[i]); signed char d2=get_reg(i_regs->regmap,rs2[i]); assert(d1>=0); assert(d2>=0); emit_mov(d1,EAX); if(opcode2[i]==0x1A) //DIV { emit_cdq(); emit_test(d2,d2); emit_jeq((intptr_t)out+8); emit_idiv(d2); } else if(opcode2[i]==0x1B) //DIVU { emit_zeroreg(EDX); emit_test(d2,d2); emit_jeq((intptr_t)out+8); emit_div(d2); } } else #endif { u_int reglist=0; signed char r1=get_reg(i_regs->regmap,rs1[i]); signed char r2=get_reg(i_regs->regmap,rs2[i]); signed char hi=get_reg(i_regs->regmap,HIREG); signed char lo=get_reg(i_regs->regmap,LOREG); assert(r1>=0); assert(r2>=0); for(int hr=0;hrregmap[hr]>=0) reglist|=1<=0) reglist&=~(1<=0) reglist&=~(1<=0) emit_loadreg(HIREG,hi); if(lo>=0) emit_loadreg(LOREG,lo); } } else // 64-bit { u_int reglist=0; signed char r1h=get_reg(i_regs->regmap,rs1[i]|64); signed char r1l=get_reg(i_regs->regmap,rs1[i]); signed char r2h=get_reg(i_regs->regmap,rs2[i]|64); signed char r2l=get_reg(i_regs->regmap,rs2[i]); signed char hih=get_reg(i_regs->regmap,HIREG|64); signed char hil=get_reg(i_regs->regmap,HIREG); signed char loh=get_reg(i_regs->regmap,LOREG|64); signed char lol=get_reg(i_regs->regmap,LOREG); assert(r1h>=0); assert(r2h>=0); assert(r1l>=0); assert(r2l>=0); for(int hr=0;hrregmap[hr]>=0) reglist|=1<=0) reglist&=~(1<=0) reglist&=~(1<=0) reglist&=~(1<=0) reglist&=~(1<=0) emit_loadreg(HIREG|64,hih); if(hil>=0) emit_loadreg(HIREG,hil); if(loh>=0) emit_loadreg(LOREG|64,loh); if(lol>=0) emit_loadreg(LOREG,lol); } } else { // Multiply by zero is zero. // MIPS does not have a divide by zero exception. // The result is undefined, we return zero. signed char hr=get_reg(i_regs->regmap,HIREG); signed char lr=get_reg(i_regs->regmap,LOREG); if(hr>=0) emit_zeroreg(hr); if(lr>=0) emit_zeroreg(lr); } } #define multdiv_assemble multdiv_assemble_x64 static void do_preload_rhash(int r) { emit_movimm(0x1f0,r); } static void do_preload_rhtbl(int r) { // Don't need this for x64 } static void do_rhash(int rs,int rh) { emit_and(rs,rh,rh); } static void do_miniht_load(int ht,int rh) { // Don't need this for x64. The load and compare can be combined into // a single instruction (below) } static void do_miniht_jump(int rs,int rh,int ht) { emit_lea_rip((intptr_t)g_dev.r4300.new_dynarec_hot_state.mini_ht,HOST_TEMPREG); emit_cmpmem_dualindexed(HOST_TEMPREG,rh,rs); emit_jne(jump_vaddr_reg[rs]); emit_readdword_dualindexed(8,HOST_TEMPREG,rh,rh); emit_jmpreg(rh); } static void do_miniht_insert(int return_address,int rt,int temp) { emit_movimm(return_address,rt); // PC into link register emit_writeword(rt,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0x1FF)>>4][0]); add_to_linker((intptr_t)out,return_address,1); emit_movimm64(0,temp); emit_writedword(temp,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0x1FF)>>4][1]); } // We don't need this for x64 static void literal_pool(int n) {} static void literal_pool_jumpover(int n) {} // CPU-architecture-specific initialization static void arch_init() { g_dev.r4300.new_dynarec_hot_state.rounding_modes[0]=0x33F; // round g_dev.r4300.new_dynarec_hot_state.rounding_modes[1]=0xF3F; // trunc g_dev.r4300.new_dynarec_hot_state.rounding_modes[2]=0xB3F; // ceil g_dev.r4300.new_dynarec_hot_state.rounding_modes[3]=0x73F; // floor g_dev.r4300.new_dynarec_hot_state.ram_offset=(intptr_t)g_dev.rdram.dram-(intptr_t)0x80000000LL; } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x64/assem_x64.h000066400000000000000000000034571464506436200251560ustar00rootroot00000000000000#ifndef M64P_DEVICE_R4300_NEW_DYNAREC_X64_ASSEM_X64_H #define M64P_DEVICE_R4300_NEW_DYNAREC_X64_ASSEM_X64_H #define EAX 0 #define ECX 1 #define EDX 2 #define EBX 3 #define ESP 4 #define EBP 5 #define ESI 6 #define EDI 7 #define RAX 0 #define RCX 1 #define RDX 2 #define RBX 3 #define RSP 4 #define RBP 5 #define RSI 6 #define RDI 7 #define R8 8 #define R9 9 #define R10 10 #define R11 11 #define R12 12 #define R13 13 #define R14 14 #define R15 15 #define HOST_REGS 8 #define HOST_BTREG EBP #define EXCLUDE_REG ESP #define HOST_TEMPREG R15 //#define IMM_PREFETCH 1 #define NATIVE_64 1 #define RAM_OFFSET 1 #define NEED_INVC_PTR 1 #define INVERTED_CARRY 1 //#define DESTRUCTIVE_WRITEBACK 1 #define DESTRUCTIVE_SHIFT 1 #define USE_MINI_HT 1 #define TARGET_SIZE_2 25 // 2^25 = 32 megabytes #define JUMP_TABLE_SIZE 0 // Not needed for x86 #ifdef _WIN32 /* Microsoft x64 calling convention: func(rcx, rdx, r8, r9) {return rax;} callee-save: %rbx %rbp %rdi %rsi %rsp %r12-%r15 The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile (caller-saved). The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile (callee-saved).*/ #define ARG1_REG ECX #define ARG2_REG EDX #define ARG3_REG R8 #define ARG4_REG R9 #define CALLER_SAVED_REGS 0xF07 #define HOST_CCREG ESI #else /* amd64 calling convention: func(rdi, rsi, rdx, rcx, r8, r9) {return rax;} callee-save: %rbp %rbx %r12-%r15 The registers RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11 are considered volatile (caller-saved). The registers RBX, RBP, RSP, R12, R13, R14, and R15 are considered nonvolatile (callee-saved).*/ #define ARG1_REG EDI #define ARG2_REG ESI #define ARG3_REG EDX #define ARG4_REG ECX #define CALLER_SAVED_REGS 0xFC7 #define HOST_CCREG EBX #endif #endif /* M64P_DEVICE_R4300_NEW_DYNAREC_X64_ASSEM_X64_H */ mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x64/linkage_x64.asm000066400000000000000000000165641464506436200260140ustar00rootroot00000000000000;Mupen64plus - linkage_x86.asm ;Copyright (C) 2009-2011 Ari64 ; ;This program is free software; you can redistribute it and/or modify ;it under the terms of the GNU General Public License as published by ;the Free Software Foundation; either version 2 of the License, or ;(at your option) any later version. ; ;This program is distributed in the hope that it will be useful, ;but WITHOUT ANY WARRANTY; without even the implied warranty of ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;GNU General Public License for more details. ; ;You should have received a copy of the GNU General Public License ;along with this program; if not, write to the ;Free Software Foundation, Inc., ;51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. %include "asm_defines_nasm.h" %ifidn __OUTPUT_FORMAT__,elf section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf32 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf64 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifdef LEADING_UNDERSCORE %macro cglobal 1 global _%1 %define %1 _%1 %endmacro %macro cextern 1 extern _%1 %define %1 _%1 %endmacro %else %macro cglobal 1 global %1 %endmacro %macro cextern 1 extern %1 %endmacro %endif %ifdef WIN64 %define ARG1_REG ecx %define ARG2_REG edx %define ARG3_REG r8d %define ARG4_REG r9d %define ARG1_REG64 rcx %define ARG2_REG64 rdx %define ARG3_REG64 r8 %define ARG4_REG64 r9 %define CCREG esi %else %define ARG1_REG edi %define ARG2_REG esi %define ARG3_REG edx %define ARG4_REG ecx %define ARG1_REG64 rdi %define ARG2_REG64 rsi %define ARG3_REG64 rdx %define ARG4_REG64 rcx %define CCREG ebx %endif %define g_dev_r4300_new_dynarec_hot_state_stop (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_stop) %define g_dev_r4300_new_dynarec_hot_state_cycle_count (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_cycle_count) %define g_dev_r4300_new_dynarec_hot_state_pending_exception (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_pending_exception) %define g_dev_r4300_new_dynarec_hot_state_pcaddr (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_pcaddr) cglobal jump_vaddr_eax cglobal jump_vaddr_ecx cglobal jump_vaddr_edx cglobal jump_vaddr_ebx cglobal jump_vaddr_ebp cglobal jump_vaddr_esi cglobal jump_vaddr_edi cglobal verify_code cglobal cc_interrupt cglobal do_interrupt cglobal fp_exception cglobal jump_syscall cglobal jump_eret cglobal new_dyna_start cglobal invalidate_block_eax cglobal invalidate_block_ecx cglobal invalidate_block_edx cglobal invalidate_block_ebx cglobal invalidate_block_ebp cglobal invalidate_block_esi cglobal invalidate_block_edi cglobal breakpoint cglobal dyna_linker cglobal dyna_linker_ds cextern base_addr cextern new_recompile_block cextern get_addr_ht cextern get_addr cextern dynarec_gen_interrupt cextern clean_blocks cextern invalidate_block cextern ERET_new cextern get_addr_32 cextern g_dev cextern verify_dirty cextern cop1_unusable cextern SYSCALL_new cextern dynamic_linker cextern dynamic_linker_ds section .bss align 4 section .rodata section .text jump_vaddr_eax: mov ARG1_REG, eax jmp jump_vaddr jump_vaddr_edx: mov ARG1_REG, edx jmp jump_vaddr jump_vaddr_ebx: %ifdef WIN64 mov ARG1_REG, ebx jmp jump_vaddr %else int 3 %endif jump_vaddr_edi: mov ARG1_REG, edi jmp jump_vaddr jump_vaddr_ebp: mov ARG1_REG, ebp jmp jump_vaddr jump_vaddr_esi: %ifdef WIN64 int 3 %else mov ARG1_REG, esi jmp jump_vaddr %endif jump_vaddr_ecx: mov ARG1_REG, ecx jump_vaddr: call get_addr_ht jmp rax verify_code: ;ARG1_REG64 = head add rsp, -8 call verify_dirty test eax,eax jne _D1 add rsp, 8 ret _D1: mov ARG1_REG, eax call get_addr add rsp, 16 jmp rax cc_interrupt: mov DWORD[rel g_dev_r4300_new_dynarec_hot_state_cycle_count], CCREG add rsp, -56 ;Align stack mov DWORD [rel g_dev_r4300_new_dynarec_hot_state_pending_exception], 0 call dynarec_gen_interrupt mov CCREG, DWORD[rel g_dev_r4300_new_dynarec_hot_state_cycle_count] mov ecx, DWORD[rel g_dev_r4300_new_dynarec_hot_state_pending_exception] mov edx, DWORD[rel g_dev_r4300_new_dynarec_hot_state_stop] add rsp, 56 test edx, edx jne _E2 test ecx, ecx jne _E1 ret _E1: add rsp, -8 mov ARG1_REG, DWORD[rel g_dev_r4300_new_dynarec_hot_state_pcaddr] call get_addr_ht add rsp, 16 jmp rax _E2: add rsp, 8 ;pop return address new_dyna_stop: add rsp, 56 ;restore callee-save registers pop rbp pop r15 pop r14 pop r13 pop r12 pop rbx %ifdef WIN64 pop rsi pop rdi %endif ret ;exit dynarec do_interrupt: mov edx, DWORD[rel g_dev_r4300_new_dynarec_hot_state_stop] test edx, edx jne new_dyna_stop mov ARG1_REG, [rel g_dev_r4300_new_dynarec_hot_state_pcaddr] call get_addr_ht mov CCREG, [rel g_dev_r4300_new_dynarec_hot_state_cycle_count] jmp rax fp_exception: mov DWORD[rel g_dev_r4300_new_dynarec_hot_state_pcaddr], eax call cop1_unusable jmp rax jump_syscall: mov DWORD[rel g_dev_r4300_new_dynarec_hot_state_pcaddr], eax call SYSCALL_new jmp rax jump_eret: mov DWORD[rel g_dev_r4300_new_dynarec_hot_state_cycle_count], CCREG call ERET_new mov CCREG, DWORD[rel g_dev_r4300_new_dynarec_hot_state_cycle_count] test rax, rax je new_dyna_stop jmp rax dyna_linker: call dynamic_linker jmp rax dyna_linker_ds: call dynamic_linker_ds jmp rax new_dyna_start: ;we must push an even # of registers to keep stack 16-byte aligned %ifdef WIN64 push rdi push rsi %endif push rbx push r12 push r13 push r14 push r15 push rbp add rsp, -56 mov ARG1_REG, 0a4000040h call new_recompile_block mov CCREG, DWORD [rel g_dev_r4300_new_dynarec_hot_state_cycle_count] mov rax, QWORD[rel base_addr] jmp rax invalidate_block_eax: mov ARG1_REG, eax jmp invalidate_block_call invalidate_block_edi: mov ARG1_REG, edi jmp invalidate_block_call invalidate_block_edx: mov ARG1_REG, edx jmp invalidate_block_call invalidate_block_ebx: mov ARG1_REG, ebx jmp invalidate_block_call invalidate_block_ebp: mov ARG1_REG, ebp jmp invalidate_block_call invalidate_block_esi: mov ARG1_REG, esi jmp invalidate_block_call invalidate_block_ecx: mov ARG1_REG, ecx invalidate_block_call: add rsp, -56 call invalidate_block add rsp, 56 ret breakpoint: int 3 ret mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x86/000077500000000000000000000000001464506436200231675ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x86/assem_x86.c000066400000000000000000003322611464506436200251570ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assem_x86.c * * Copyright (C) 2009-2011 Ari64 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void jump_vaddr_eax(void); void jump_vaddr_ecx(void); void jump_vaddr_edx(void); void jump_vaddr_ebx(void); void jump_vaddr_ebp(void); void jump_vaddr_edi(void); void invalidate_block_eax(void); void invalidate_block_ecx(void); void invalidate_block_edx(void); void invalidate_block_ebx(void); void invalidate_block_ebp(void); void invalidate_block_esi(void); void invalidate_block_edi(void); // We need these for cmovcc instructions on x86 static const u_int const_zero=0; static const u_int const_one=1; static const u_int jump_vaddr_reg[8] = { (int)jump_vaddr_eax, (int)jump_vaddr_ecx, (int)jump_vaddr_edx, (int)jump_vaddr_ebx, 0, (int)jump_vaddr_ebp, 0, (int)jump_vaddr_edi }; static const u_int invalidate_block_reg[8] = { (int)invalidate_block_eax, (int)invalidate_block_ecx, (int)invalidate_block_edx, (int)invalidate_block_ebx, 0, (int)invalidate_block_ebp, (int)invalidate_block_esi, (int)invalidate_block_edi }; /* Linker */ static void set_jump_target(int addr,int target) { u_char *ptr=(u_char *)addr; if(*ptr==0x0f) { assert(ptr[1]>=0x80&&ptr[1]<=0x8f); u_int *ptr2=(u_int *)(ptr+2); *ptr2=target-(int)ptr2-4; } else if(*ptr==0xe8||*ptr==0xe9) { u_int *ptr2=(u_int *)(ptr+1); *ptr2=target-(int)ptr2-4; } else { assert(*ptr==0xc7); /* mov immediate (store address) */ u_int *ptr2=(u_int *)(ptr+6); *ptr2=target; } } static void *add_pointer(void *src, void* addr) { int *ptr=(int*)src; int *ptr2=(int*)((u_int)ptr+(u_int)*ptr+4); assert((*ptr2&0xFF)==0x68); //push assert((*(int*)((u_int)ptr2+5)&0xFF)==0x68); //push u_int offset=(u_int)addr-(u_int)ptr-4; *ptr=offset; return (void*)ptr2; } static void *kill_pointer(void *stub) { int *i_ptr=*((int **)((int)stub+6)); *i_ptr=(int)stub-(int)i_ptr-4; return i_ptr; } static int get_pointer(void *stub) { int *i_ptr=*((int **)((int)stub+6)); return *i_ptr+(int)i_ptr+4; } /* Register allocation */ // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). static void alloc_reg(struct regstat *cur,int i,signed char reg) { int r,hr; int preferred_reg = (reg&3)+(reg>28)*4-(reg==32)+2*(reg==36)-(reg==40); // Don't allocate unused registers if((cur->u>>reg)&1) return; // see if it's already allocated for(hr=0;hrregmap[hr]==reg) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) if(i==0||(unneeded_reg[i-1]>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) if(i==0||(unneeded_reg_upper[i-1]>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<uu>>reg)&1) return; // see if the upper half is already allocated for(hr=0;hrregmap[hr]==reg+64) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<=64&&((cur->uu>>(r&63))&1)) { cur->regmap[preferred_reg]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;} } else { if((cur->uu>>(r&63))&1) {cur->regmap[hr]=-1;break;} } } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<regmap[preferred_reg]=reg|64; return; } for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg|64; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==reg) return; } // Try to allocate any available register, starting with EDI, ESI, EBP... // We prefer EDI, ESI, EBP since the others are used for byte/halfword stores for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if(r<64) { if((cur->u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<uu>>(r&63))&1) { if(i==0||((unneeded_reg_upper[i-1]>>(r&63))&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP||itype[i-2]==FJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hr2) { if(cur->regmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<2) { if(cur->regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<=0;j--) { for(r=1;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isconst&=~(1<regmap[n]==reg) { dirty=(cur->dirty>>n)&1; cur->regmap[n]=-1; } } cur->regmap[hr]=reg; cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<u&=~(1LL<u&=~(1LL<is32|=1LL<is32|=1LL<u&=~(1LL<uu&=~(1LL<is32&=~(1LL<is32&=~(1LL<u>>LOREG)&1)||((current->uu>>LOREG)&1)) alloc_reg64(current,i,HIREG); else alloc_reg(current,i,HIREG); alloc_reg64(current,i,LOREG); alloc_reg64(current,i,rs1[i]); alloc_reg64(current,i,rs2[i]); current->is32&=~(1LL<is32&=~(1LL<is32|=1LL<is32|=1LL<>4); if((r&63)==HIREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.hi+((r&64)>>4); if((r&63)==LOREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.lo+((r&64)>>4); if(r==CCREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.cycle_count; if(r==CSREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.cp0_regs[CP0_STATUS_REG]; if(r==FSREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31; assem_debug("mov %x+%d,%%%s",addr,r,regname[hr]); output_byte(0x8B); output_modrm(0,5,hr); output_w32(addr); } } static void emit_storereg(int r, int hr) { int addr=((int)g_dev.r4300.new_dynarec_hot_state.regs)+((r&63)<<3)+((r&64)>>4); if((r&63)==HIREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.hi+((r&64)>>4); if((r&63)==LOREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.lo+((r&64)>>4); if(r==CCREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.cycle_count; if(r==FSREG) addr=(int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31; assert((r&63)!=CSREG); assert((r&63)!=0); assert((r&63)<=CCREG); assem_debug("mov %%%s,%x+%d",regname[hr],addr,r); output_byte(0x89); output_modrm(0,5,hr); output_w32(addr); } static void emit_test(int rs, int rt) { assem_debug("test %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x85); output_modrm(3,rs,rt); } static void emit_testimm(int rs,int imm) { assem_debug("test $0x%x,%%%s",imm,regname[rs]); if(imm<128&&imm>=-128&&rs<4) { output_byte(0xF6); output_modrm(3,rs,0); output_byte(imm); } else { output_byte(0xF7); output_modrm(3,rs,0); output_w32(imm); } } static void emit_not(int rs,int rt) { if(rs!=rt) emit_mov(rs,rt); assem_debug("not %%%s",regname[rt]); output_byte(0xF7); output_modrm(3,rt,2); } static void emit_and(u_int rs1,u_int rs2,u_int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("and %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x21); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("and %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x21); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_and(rt,rs2,rt); } } static void emit_or(u_int rs1,u_int rs2,u_int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("or %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x09); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("or %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x09); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_or(rt,rs2,rt); } } static void emit_or_and_set_flags(int rs1,int rs2,int rt) { emit_or(rs1,rs2,rt); } static void emit_xor(u_int rs1,u_int rs2,u_int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("xor %%%s,%%%s",regname[rs2],regname[rt]); output_byte(0x31); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("xor %%%s,%%%s",regname[rs1],regname[rt]); output_byte(0x31); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_xor(rt,rs2,rt); } } static void emit_movimm(int imm,u_int rt) { assem_debug("mov $%d,%%%s",imm,regname[rt]); assert(rt<8); output_byte(0xB8+rt); output_w32(imm); } static void emit_addimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("add $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } } else { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s",imm,regname[rs],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rs,rt); output_byte(imm); }else{ output_modrm(2,rs,rt); output_w32(imm); } }else{ emit_mov(rs,rt); } } } static void emit_addimm_and_set_flags(int imm,int rt) { assem_debug("add $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } static void emit_addimm_no_flags(int imm,int rt) { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s",imm,regname[rt],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rt,rt); output_byte(imm); }else{ output_modrm(2,rt,rt); output_w32(imm); } } } static void emit_adcimm(int imm,u_int rt) { assem_debug("adc $%d,%%%s",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,2); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,2); output_w32(imm); } } static void emit_sbbimm(int imm,u_int rt) { assem_debug("sbb $%d,%%%s",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,3); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,3); output_w32(imm); } } static void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) { if(rsh==rth&&rsl==rtl) { assem_debug("add $%d,%%%s",imm,regname[rtl]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rtl,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rtl,0); output_w32(imm); } assem_debug("adc $%d,%%%s",imm>>31,regname[rth]); output_byte(0x83); output_modrm(3,rth,2); output_byte(imm>>31); } else { emit_mov(rsh,rth); emit_mov(rsl,rtl); emit_addimm64_32(rth,rtl,imm,rth,rtl); } } static void emit_sub64_32(int rs1l,int rs1h,int rs2l,int rs2h,int rtl,int rth) { if((rs1l==rtl)&&(rs1h==rth)) { assem_debug("sub %%%s,%%%s",regname[rs2l],regname[rs1l]); output_byte(0x29); output_modrm(3,rs1l,rs2l); assem_debug("sbb %%%s,%%%s",regname[rs2h],regname[rs1h]); output_byte(0x19); output_modrm(3,rs1h,rs2h); } else if((rs2l==rtl)&&(rs2h==rth)) { emit_neg(rs2l,rs2l); emit_adcimm(-1,rs2h); assem_debug("add %%%s,%%%s",regname[rs1l],regname[rs2l]); output_byte(0x01); output_modrm(3,rs2l,rs1l); emit_not(rs2h,rs2h); assem_debug("adc %%%s,%%%s",regname[rs1h],regname[rs2h]); output_byte(0x11); output_modrm(3,rs2h,rs1h); } else { emit_mov(rs1l,rtl); assem_debug("sub %%%s,%%%s",regname[rs2l],regname[rtl]); output_byte(0x29); output_modrm(3,rtl,rs2l); emit_mov(rs1h,rth); assem_debug("sbb %%%s,%%%s",regname[rs2h],regname[rth]); output_byte(0x19); output_modrm(3,rth,rs2h); } } static void emit_sbb(int rs1,int rs2) { assem_debug("sbb %%%s,%%%s",regname[rs1],regname[rs2]); output_byte(0x19); output_modrm(3,rs2,rs1); } static void emit_andimm(int rs,int imm,int rt) { if(imm==0) { emit_zeroreg(rt); } else if(rs==rt) { assem_debug("and $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,4); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,4); output_w32(imm); } } else { emit_mov(rs,rt); emit_andimm(rt,imm,rt); } } static void emit_orimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("or $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,1); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,1); output_w32(imm); } } } else { emit_mov(rs,rt); emit_orimm(rt,imm,rt); } } static void emit_xorimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("xor $%d,%%%s",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,6); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,6); output_w32(imm); } } } else { emit_mov(rs,rt); emit_xorimm(rt,imm,rt); } } static void emit_shlimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("shl %%%s,%d",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,4); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shlimm(rt,imm,rt); } } static void emit_shrimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("shr %%%s,%d",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,5); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shrimm(rt,imm,rt); } } static void emit_sarimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("sar %%%s,%d",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,7); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_sarimm(rt,imm,rt); } } static void emit_rorimm(int rs,u_int imm,int rt) { if(rs==rt) { assem_debug("ror %%%s,%d",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,1); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_rorimm(rt,imm,rt); } } static void emit_shldimm(int rs,int rs2,u_int imm,int rt) { if(rs==rt) { assem_debug("shld %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xA4); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shldimm(rt,rs2,imm,rt); } } static void emit_shrdimm(int rs,int rs2,u_int imm,int rt) { if(rs==rt) { assem_debug("shrd %%%s,%%%s,%d",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xAC); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shrdimm(rt,rs2,imm,rt); } } static void emit_shlcl(int r) { assem_debug("shl %%%s,%%cl",regname[r]); output_byte(0xD3); output_modrm(3,r,4); } static void emit_shrcl(int r) { assem_debug("shr %%%s,%%cl",regname[r]); output_byte(0xD3); output_modrm(3,r,5); } static void emit_sarcl(int r) { assem_debug("sar %%%s,%%cl",regname[r]); output_byte(0xD3); output_modrm(3,r,7); } static void emit_shldcl(int r1,int r2) { assem_debug("shld %%%s,%%%s,%%cl",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xA5); output_modrm(3,r1,r2); } static void emit_shrdcl(int r1,int r2) { assem_debug("shrd %%%s,%%%s,%%cl",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xAD); output_modrm(3,r1,r2); } static void emit_cmpimm(int rs,int imm) { assem_debug("cmp $%d,%%%s",imm,regname[rs]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rs,7); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rs,7); output_w32(imm); } } static void emit_cmovne(const u_int *addr,int rt) { assem_debug("cmovne %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]"); else if(addr==&const_one) assem_debug(" [one]"); else assem_debug(""); output_byte(0x0F); output_byte(0x45); output_modrm(0,5,rt); output_w32((int)addr); } static void emit_cmovl(const u_int *addr,int rt) { assem_debug("cmovl %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]"); else if(addr==&const_one) assem_debug(" [one]"); else assem_debug(""); output_byte(0x0F); output_byte(0x4C); output_modrm(0,5,rt); output_w32((int)addr); } static void emit_cmovs(const u_int *addr,int rt) { assem_debug("cmovs %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]"); else if(addr==&const_one) assem_debug(" [one]"); else assem_debug(""); output_byte(0x0F); output_byte(0x48); output_modrm(0,5,rt); output_w32((int)addr); } static void emit_cmovne_reg(int rs,int rt) { assem_debug("cmovne %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x45); output_modrm(3,rs,rt); } static void emit_cmovl_reg(int rs,int rt) { assem_debug("cmovl %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4C); output_modrm(3,rs,rt); } static void emit_cmovs_reg(int rs,int rt) { assem_debug("cmovs %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x48); output_modrm(3,rs,rt); } static void emit_cmovnc_reg(int rs,int rt) { assem_debug("cmovae %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x43); output_modrm(3,rs,rt); } static void emit_cmova_reg(int rs,int rt) { assem_debug("cmova %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x47); output_modrm(3,rs,rt); } static void emit_cmovp_reg(int rs,int rt) { assem_debug("cmovp %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4A); output_modrm(3,rs,rt); } static void emit_cmovnp_reg(int rs,int rt) { assem_debug("cmovnp %%%s,%%%s",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4B); output_modrm(3,rs,rt); } static void emit_setl(int rt) { assem_debug("setl %%%s",regname[rt]); output_byte(0x0F); output_byte(0x9C); output_modrm(3,rt,2); } static void emit_movzbl_reg(int rs, int rt) { assem_debug("movzbl %%%s,%%%s",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(3,rs,rt); } static void emit_slti32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rt<4) { emit_setl(rt); if(rs==rt) emit_movzbl_reg(rt,rt); } else { if(rs==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } } static void emit_sltiu32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } static void emit_slti64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_slti32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); emit_cmovs(&const_one,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_zero,rt); emit_cmovl(&const_one,rt); } } static void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_sltiu32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_one,rt); } } static void emit_cmp(int rs,int rt) { assem_debug("cmp %%%s,%%%s",regname[rt],regname[rs]); output_byte(0x39); output_modrm(3,rs,rt); } static void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_cmovl(&const_zero,rt); } static void emit_set_nz32(int rs, int rt) { //assem_debug("set_nz32"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_sbbimm(0,rt); } static void emit_set_gz64_32(int rsh, int rsl, int rt) { //assem_debug("set_gz64"); emit_set_gz32(rsl,rt); emit_test(rsh,rsh); emit_cmovne(&const_one,rt); emit_cmovs(&const_zero,rt); } static void emit_set_nz64_32(int rsh, int rsl, int rt) { //assem_debug("set_nz64"); emit_or_and_set_flags(rsh,rsl,rt); emit_cmovne(&const_one,rt); } static void emit_set_if_less32(int rs1, int rs2, int rt) { //assem_debug("set if less (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } static void emit_set_if_carry32(int rs1, int rs2, int rt) { //assem_debug("set if carry (%%%s,%%%s),%%%s",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } static void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_cmovl(&const_one,rt); } static void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_adcimm(0,rt); } static void emit_call(int a) { assem_debug("call %x (%x+%x)",a,(int)out+5,a-(int)out-5); output_byte(0xe8); output_w32(a-(int)out-4); } static void emit_jmp(int a) { assem_debug("jmp %x (%x+%x)",a,(int)out+5,a-(int)out-5); output_byte(0xe9); output_w32(a-(int)out-4); } static void emit_jne(int a) { assem_debug("jne %x",a); output_byte(0x0f); output_byte(0x85); output_w32(a-(int)out-4); } static void emit_jeq(int a) { assem_debug("jeq %x",a); output_byte(0x0f); output_byte(0x84); output_w32(a-(int)out-4); } static void emit_js(int a) { assem_debug("js %x",a); output_byte(0x0f); output_byte(0x88); output_w32(a-(int)out-4); } static void emit_jns(int a) { assem_debug("jns %x",a); output_byte(0x0f); output_byte(0x89); output_w32(a-(int)out-4); } static void emit_jl(int a) { assem_debug("jl %x",a); output_byte(0x0f); output_byte(0x8c); output_w32(a-(int)out-4); } static void emit_jge(int a) { assem_debug("jge %x",a); output_byte(0x0f); output_byte(0x8d); output_w32(a-(int)out-4); } static void emit_jno(int a) { assem_debug("jno %x",a); output_byte(0x0f); output_byte(0x81); output_w32(a-(int)out-4); } static void emit_jc(int a) { assem_debug("jc %x",a); output_byte(0x0f); output_byte(0x82); output_w32(a-(int)out-4); } static void emit_jae(int a) { assem_debug("jae %x",a); output_byte(0x0f); output_byte(0x83); output_w32(a-(int)out-4); } static void emit_jb(int a) { assem_debug("jb %x",a); output_byte(0x0f); output_byte(0x82); output_w32(a-(int)out-4); } static void emit_pushimm(int imm) { assem_debug("push $%x",imm); output_byte(0x68); output_w32(imm); } static void emit_pushmem(int addr) { assem_debug("push *%x",addr); output_byte(0xFF); output_modrm(0,5,6); output_w32(addr); } static void emit_pusha(void) { assem_debug("pusha"); output_byte(0x60); } static void emit_popa(void) { assem_debug("popa"); output_byte(0x61); } static void emit_pushreg(u_int r) { assem_debug("push %%%s",regname[r]); assert(r<8); output_byte(0x50+r); } static void emit_popreg(u_int r) { assem_debug("pop %%%s",regname[r]); assert(r<8); output_byte(0x58+r); } static void emit_callreg(u_int r) { assem_debug("call *%%%s",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,2); } static void emit_jmpreg(u_int r) { assem_debug("jmp *%%%s",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,4); } static void emit_jmpmem_indexed(u_int addr,u_int r) { assem_debug("jmp *%x(%%%s)",addr,regname[r]); assert(r<8); output_byte(0xFF); output_modrm(2,r,4); output_w32(addr); } static void emit_readword(int addr, int rt) { assem_debug("mov %x,%%%s",addr,regname[rt]); output_byte(0x8B); output_modrm(0,5,rt); output_w32(addr); } static void emit_readword_indexed(int addr, int rs, int rt) { assem_debug("mov %x+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x8B); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } static void emit_readword_tlb(int addr, int map, int rt) { if(map<0) emit_readword(addr+(int)g_dev.rdram.dram-0x80000000, rt); else { assem_debug("mov (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } static void emit_readword_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_readword_indexed(addr+(int)g_dev.rdram.dram-0x80000000, rs, rt); else { assem_debug("mov %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x8B); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } static void emit_readptr(int addr, int rt) { emit_readword(addr,rt); } static void emit_movmem_indexedx4(int addr, int rs, int rt) { assem_debug("mov (%x,%%%s,4),%%%s",addr,regname[rs],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,rs,5); output_w32(addr); } static void emit_readdword_tlb(int addr, int map, int rh, int rl) { if(map<0) { if(rh>=0) emit_readword(addr+(int)g_dev.rdram.dram-0x80000000, rh); emit_readword(addr+(int)g_dev.rdram.dram-0x7FFFFFFC, rl); } else { if(rh>=0) emit_movmem_indexedx4(addr, map, rh); emit_movmem_indexedx4(addr+4, map, rl); } } static void emit_readdword_indexed_tlb(int addr, int rs, int map, int rh, int rl) { assert(rh!=rs); if(rh>=0) emit_readword_indexed_tlb(addr, rs, map, rh); emit_readword_indexed_tlb(addr+4, rs, map, rl); } static void emit_movsbl(int addr, int rt) { assem_debug("movsbl %x,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(0,5,rt); output_w32(addr); } static void emit_movsbl_indexed(int addr, int rs, int rt) { assem_debug("movsbl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movsbl_tlb(int addr, int map, int rt) { if(map<0) emit_movsbl(addr+(int)g_dev.rdram.dram-0x80000000, rt); else { assem_debug("movsbl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } static void emit_movsbl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movsbl_indexed(addr+(int)g_dev.rdram.dram-0x80000000, rs, rt); else { assem_debug("movsbl %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xBE); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } static void emit_movswl(int addr, int rt) { assem_debug("movswl %x,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(0,5,rt); output_w32(addr); } static void emit_movswl_indexed(int addr, int rs, int rt) { assem_debug("movswl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movswl_tlb(int addr, int map, int rt) { if(map<0) emit_movswl(addr+(int)g_dev.rdram.dram-0x80000000, rt); else { assem_debug("movswl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } static void emit_movswl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movswl_indexed(addr+(int)g_dev.rdram.dram-0x80000000, rs, rt); else { assem_debug("movswl %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xBF); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } static void emit_movzbl(int addr, int rt) { assem_debug("movzbl %x,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(0,5,rt); output_w32(addr); } static void emit_movzbl_indexed(int addr, int rs, int rt) { assem_debug("movzbl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movzbl_tlb(int addr, int map, int rt) { if(map<0) emit_movzbl(addr+(int)g_dev.rdram.dram-0x80000000, rt); else { assem_debug("movzbl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } static void emit_movzbl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movzbl_indexed(addr+(int)g_dev.rdram.dram-0x80000000, rs, rt); else { assem_debug("movzbl %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xB6); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } static void emit_movzwl(int addr, int rt) { assem_debug("movzwl %x,%%%s",addr,regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(0,5,rt); output_w32(addr); } static void emit_movzwl_indexed(int addr, int rs, int rt) { assem_debug("movzwl %x+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(2,rs,rt); output_w32(addr); } static void emit_movzwl_tlb(int addr, int map, int rt) { if(map<0) emit_movzwl(addr+(int)g_dev.rdram.dram-0x80000000, rt); else { assem_debug("movzwl (%x,%%%s,4),%%%s",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } static void emit_movzwl_indexed_tlb(int addr, int rs, int map, int rt) { if(map<0) emit_movzwl_indexed(addr+(int)g_dev.rdram.dram-0x80000000, rs, rt); else { assem_debug("movzwl %x(%%%s,%%%s,4),%%%s",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xB7); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } /* static void emit_movzwl_reg(int rs, int rt) { assem_debug("movzwl %%%s,%%%s",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(3,rs,rt); }*/ static void emit_xchg(int rs, int rt) { assem_debug("xchg %%%s,%%%s",regname[rs],regname[rt]); if(rs==EAX) { output_byte(0x90+rt); } else { output_byte(0x87); output_modrm(3,rs,rt); } } static void emit_writeword(int rt, int addr) { assem_debug("movl %%%s,%x",regname[rt],addr); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr); } static void emit_writeword_indexed(int rt, int addr, int rs) { assem_debug("mov %%%s,%x+%%%s",regname[rt],addr,regname[rs]); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } static void emit_writeword_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writeword_indexed(rt, addr+(int)g_dev.rdram.dram-0x80000000, rs); else { assem_debug("mov %%%s,%x(%%%s,%%%s,1)",regname[rt],addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } } static void emit_writedword_indexed_tlb(int rh, int rl, int addr, int rs, int map) { assert(rh>=0); emit_writeword_indexed_tlb(rh, addr, rs, map); emit_writeword_indexed_tlb(rl, addr+4, rs, map); } static void emit_writehword(int rt, int addr) { assem_debug("movw %%%s,%x",regname[rt]+1,addr); output_byte(0x66); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr); } static void emit_writehword_indexed(int rt, int addr, int rs) { assem_debug("movw %%%s,%x+%%%s",regname[rt]+1,addr,regname[rs]); output_byte(0x66); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); output_byte(addr); } else { output_modrm(2,rs,rt); output_w32(addr); } } static void emit_writehword_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writehword_indexed(rt, addr+(int)g_dev.rdram.dram-0x80000000, rs); else { assem_debug("movw %%%s,%x(%%%s,%%%s,1)",regname[rt]+1,addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x66); output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } } static void emit_writebyte(int rt, int addr) { if(rt<4) { assem_debug("movb %%%cl,%x",regname[rt][1],addr); output_byte(0x88); output_modrm(0,5,rt); output_w32(addr); } else { emit_xchg(EAX,rt); emit_writebyte(EAX,addr); emit_xchg(EAX,rt); } } static void emit_writebyte_indexed(int rt, int addr, int rs) { if(rt<4) { assem_debug("movb %%%cl,%x+%%%s",regname[rt][1],addr,regname[rs]); output_byte(0x88); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); output_byte(addr); } else { output_modrm(2,rs,rt); output_w32(addr); } } else { emit_xchg(EAX,rt); emit_writebyte_indexed(EAX,addr,rs==EAX?rt:rs); emit_xchg(EAX,rt); } } static void emit_writebyte_indexed_tlb(int rt, int addr, int rs, int map) { if(map<0) emit_writebyte_indexed(rt, addr+(int)g_dev.rdram.dram-0x80000000, rs); else if(rt<4) { assem_debug("movb %%%cl,%x(%%%s,%%%s,1)",regname[rt][1],addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x88); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } else { emit_xchg(EAX,rt); emit_writebyte_indexed_tlb(EAX,addr,rs==EAX?rt:rs,map==EAX?rt:map); emit_xchg(EAX,rt); } } static void emit_writeword_imm(int imm, int addr) { assem_debug("movl $%x,%x",imm,addr); output_byte(0xC7); output_modrm(0,5,0); output_w32(addr); output_w32(imm); } static void emit_writeword_imm_esp(int imm, int addr) { assem_debug("mov $%x,%x(%%esp)",imm,addr); assert(addr>=-128&&addr<128); output_byte(0xC7); output_modrm(1,4,0); output_sib(0,4,4); output_byte(addr); output_w32(imm); } static void emit_writebyte_imm(int imm, int addr) { assem_debug("movb $%x,%x",imm,addr); assert(imm>=-128&&imm<128); output_byte(0xC6); output_modrm(0,5,0); output_w32(addr); output_byte(imm); } static void emit_mul(int rs) { assem_debug("mul %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,4); } static void emit_imul(int rs) { assem_debug("imul %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,5); } static void emit_div(int rs) { assem_debug("div %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,6); } static void emit_idiv(int rs) { assem_debug("idiv %%%s",regname[rs]); output_byte(0xF7); output_modrm(3,rs,7); } static void emit_cdq(void) { assem_debug("cdq"); output_byte(0x99); } // Load 2 immediates optimizing for small code size static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2) { emit_movimm(imm1,rt1); if(imm2-imm1<128&&imm2-imm1>=-128) emit_addimm(rt1,imm2-imm1,rt2); else emit_movimm(imm2,rt2); } // special case for checking pending_exception static void emit_cmpmem_imm(int addr, int imm) { assert(imm<128&&imm>=-127); assem_debug("cmp $%d,%x",imm,addr); output_byte(0x83); output_modrm(0,5,7); output_w32(addr); output_byte(imm); } // special case for checking invalid_code static void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) { assert(imm<128&&imm>=-127); assert(r>=0&&r<8); emit_shrimm(r,12,r); assem_debug("cmp $%d,%x+%%%s",imm,addr,regname[r]); output_byte(0x80); output_modrm(2,r,7); output_w32(addr); output_byte(imm); } // special case for checking hash_table static void emit_cmpmem_indexed(int addr,int rs,int rt) { assert(rs>=0&&rs<8); assert(rt>=0&&rt<8); assem_debug("cmp %x+%%%s,%%%s",addr,regname[rs],regname[rt]); output_byte(0x39); output_modrm(2,rs,rt); output_w32(addr); } // Used to preload hash table entries #ifdef IMM_PREFETCH static void emit_prefetch(void *addr) { assem_debug("prefetch %x",(int)addr); output_byte(0x0F); output_byte(0x18); output_modrm(0,5,1); output_w32((int)addr); } #endif /*void emit_submem(int r,int addr) { assert(r>=0&&r<8); assem_debug("sub %x,%%%s",addr,regname[r]); output_byte(0x2B); output_modrm(0,5,r); output_w32((int)addr); } static void emit_subfrommem(int addr,int r) { assert(r>=0&&r<8); assem_debug("sub %%%s,%x",regname[r],addr); output_byte(0x29); output_modrm(0,5,r); output_w32((int)addr); }*/ static void emit_flds(int r) { assem_debug("flds (%%%s)",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fldl(int r) { assem_debug("fldl (%%%s)",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fucomip(u_int r) { assem_debug("fucomip %d",r); assert(r<8); output_byte(0xdf); output_byte(0xe8+r); } static void emit_fchs(void) { assem_debug("fchs"); output_byte(0xd9); output_byte(0xe0); } static void emit_fabs(void) { assem_debug("fabs"); output_byte(0xd9); output_byte(0xe1); } static void emit_fsqrt(void) { assem_debug("fsqrt"); output_byte(0xd9); output_byte(0xfa); } static void emit_fadds(int r) { assem_debug("fadds (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_faddl(int r) { assem_debug("faddl (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fadd(int r) { assem_debug("fadd st%d",r); output_byte(0xd8); output_byte(0xc0+r); } static void emit_fsubs(int r) { assem_debug("fsubs (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } static void emit_fsubl(int r) { assem_debug("fsubl (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } static void emit_fsub(int r) { assem_debug("fsub st%d",r); output_byte(0xd8); output_byte(0xe0+r); } static void emit_fmuls(int r) { assem_debug("fmuls (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } static void emit_fmull(int r) { assem_debug("fmull (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } static void emit_fmul(int r) { assem_debug("fmul st%d",r); output_byte(0xd8); output_byte(0xc8+r); } static void emit_fdivs(int r) { assem_debug("fdivs (%%%s)",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } static void emit_fdivl(int r) { assem_debug("fdivl (%%%s)",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } static void emit_fdiv(int r) { assem_debug("fdiv st%d",r); output_byte(0xd8); output_byte(0xf0+r); } static void emit_fpop(void) { // fstp st(0) assem_debug("fpop"); output_byte(0xdd); output_byte(0xd8); } static void emit_fildl(int r) { assem_debug("fildl (%%%s)",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } static void emit_fildll(int r) { assem_debug("fildll (%%%s)",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,5); else {output_modrm(1,EBP,5);output_byte(0);} } static void emit_fistpl(int r) { assem_debug("fistpl (%%%s)",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } static void emit_fistpll(int r) { assem_debug("fistpll (%%%s)",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,7); else {output_modrm(1,EBP,7);output_byte(0);} } static void emit_fstps(int r) { assem_debug("fstps (%%%s)",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } static void emit_fstpl(int r) { assem_debug("fstpl (%%%s)",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } static void emit_fnstcw_stack(void) { assem_debug("fnstcw (%%esp)"); output_byte(0xd9); output_modrm(0,4,7); output_sib(0,4,4); } static void emit_fldcw_stack(void) { assem_debug("fldcw (%%esp)"); output_byte(0xd9); output_modrm(0,4,5); output_sib(0,4,4); } static void emit_fldcw_indexed(int addr,int r) { assem_debug("fldcw %x(%%%s)",addr,regname[r]); output_byte(0xd9); output_modrm(0,4,5); output_sib(2,r,5); output_w32(addr); } static void emit_fldcw(int addr) { assem_debug("fldcw %x",addr); output_byte(0xd9); output_modrm(0,5,5); output_w32(addr); } #ifdef __SSE__ static void emit_movss_load(u_int addr,u_int ssereg) { assem_debug("movss (%%%s),xmm%d",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } static void emit_movsd_load(u_int addr,u_int ssereg) { assem_debug("movsd (%%%s),xmm%d",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf2); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } static void emit_movd_store(u_int ssereg,u_int addr) { assem_debug("movd xmm%d,(%%%s)",ssereg,regname[addr]); assert(ssereg<8); output_byte(0x66); output_byte(0x0f); output_byte(0x7e); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } static void emit_cvttps2dq(u_int ssereg1,u_int ssereg2) { assem_debug("cvttps2dq xmm%d,xmm%d",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x5b); output_modrm(3,ssereg1,ssereg2); } static void emit_cvttpd2dq(u_int ssereg1,u_int ssereg2) { assem_debug("cvttpd2dq xmm%d,xmm%d",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0x66); output_byte(0x0f); output_byte(0xe6); output_modrm(3,ssereg1,ssereg2); } #endif static void save_regs(u_int reglist) { (void)reglist; emit_pusha(); } static void restore_regs(u_int reglist) { (void)reglist; emit_popa(); } /* Stubs/epilogue */ static void emit_extjump2(int addr, int target, int linker) { u_char *ptr=(u_char *)addr; if(*ptr==0x0f) { assert(ptr[1]>=0x80&&ptr[1]<=0x8f); addr+=2; } else { assert(*ptr==0xe8||*ptr==0xe9); addr++; } emit_pushimm(target); emit_pushimm(addr); emit_jmp(linker); } static void do_invstub(int n) { set_jump_target(stubs[n][1],(int)out); emit_call(invalidate_block_reg[stubs[n][4]]); emit_jmp(stubs[n][2]); // return address } static int do_dirty_stub(int i, struct ll_entry * head) { assem_debug("do_dirty_stub %x",head->vaddr); emit_movimm((int)head,EAX); emit_call((int)&verify_code); int entry=(int)out; load_regs_entry(i); if(entry==(int)out) entry=instr_addr[i]; emit_jmp(instr_addr[i]); return entry; } static void do_dirty_stub_ds(struct ll_entry * head) { assem_debug("do_dirty_stub_ds %x",head->vaddr); emit_movimm((int)head,EAX); emit_call((int)&verify_code); } /* TLB */ static int do_tlb_r(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { if((signed int)addr>=(signed int)0xC0000000) { emit_readword((int)(g_dev.r4300.new_dynarec_hot_state.memory_map+(addr>>12)),map); } else return -1; // No mapping } else { if(s!=map) emit_mov(s,map); emit_shrimm(map,12,map); // Schedule this while we wait on the load //if(x) emit_xorimm(addr,x,addr); emit_movmem_indexedx4((int)g_dev.r4300.new_dynarec_hot_state.memory_map,map,map); } return map; } static int do_tlb_r_branch(int map, int c, u_int addr, int *jaddr) { if(!c||(signed int)addr>=(signed int)0xC0000000) { emit_test(map,map); *jaddr=(int)out; emit_js(0); } return map; } static int do_tlb_w(int s,int ar,int map,int cache,int x,int c,u_int addr) { if(c) { if(addr<0x80800000||addr>=0xC0000000) { emit_readword((int)(g_dev.r4300.new_dynarec_hot_state.memory_map+(addr>>12)),map); } else return -1; // No mapping } else { if(s!=map) emit_mov(s,map); //if(s!=ar) emit_mov(s,ar); emit_shrimm(map,12,map); // Schedule this while we wait on the load //if(x) emit_xorimm(s,x,addr); emit_movmem_indexedx4((int)g_dev.r4300.new_dynarec_hot_state.memory_map,map,map); } emit_shlimm(map,2,map); return map; } static void do_tlb_w_branch(int map, int c, u_int addr, int *jaddr) { if(!c||addr<0x80800000||addr>=0xC0000000) { *jaddr=(int)out; emit_jc(0); } } // We don't need this for x86 static void generate_map_const(u_int addr,int reg) { // void *mapaddr=g_dev.r4300.new_dynarec_hot_state.memory_map+(addr>>12); } static void set_rounding_mode(int s,int temp) { assert(temp>=0); emit_movimm(3,temp); emit_and(s,temp,temp); emit_fldcw_indexed((int)&g_dev.r4300.new_dynarec_hot_state.rounding_modes,temp); } /* Special assem */ static void shift_assemble_x86(int i,struct regstat *i_regs) { if(rt1[i]) { if(opcode2[i]<=0x07) // SLLV/SRLV/SRAV { signed char s,t,shift; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(t>=0){ if(rs1[i]==0) { emit_zeroreg(t); } else if(rs2[i]==0) { assert(s>=0); if(s!=t) emit_mov(s,t); } else { signed char temp=get_reg(i_regs->regmap,-1); assert(s>=0); if(t==ECX&&s!=ECX) { if(shift!=ECX) emit_mov(shift,ECX); if(rt1[i]==rs2[i]) {shift=temp;} if(s!=shift) emit_mov(s,shift); } else { if(rt1[i]==rs2[i]) {emit_mov(shift,temp);shift=temp;} if(s!=t) emit_mov(s,t); if(shift!=ECX) { if(i_regs->regmap[ECX]<0) emit_mov(shift,ECX); else emit_xchg(shift,ECX); } } if(opcode2[i]==4) // SLLV { emit_shlcl(t==ECX?shift:t); } if(opcode2[i]==6) // SRLV { emit_shrcl(t==ECX?shift:t); } if(opcode2[i]==7) // SRAV { emit_sarcl(t==ECX?shift:t); } if(shift!=ECX&&i_regs->regmap[ECX]>=0) emit_xchg(shift,ECX); } } } else { // DSLLV/DSRLV/DSRAV signed char sh,sl,th,tl,shift; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); sh=get_reg(i_regs->regmap,rs1[i]|64); sl=get_reg(i_regs->regmap,rs1[i]); shift=get_reg(i_regs->regmap,rs2[i]); if(tl>=0){ if(rs1[i]==0) { emit_zeroreg(tl); if(th>=0) emit_zeroreg(th); } else if(rs2[i]==0) { assert(sl>=0); if(sl!=tl) emit_mov(sl,tl); if(th>=0&&sh!=th) emit_mov(sh,th); } else { int temp=get_reg(i_regs->regmap,-1); int real_tl=tl; int real_th=th; if(th<0&&opcode2[i]!=0x14) {th=temp;} // DSLLV doesn't need a temporary register assert(sl>=0); assert(sh>=0); if(tl==ECX&&sl!=ECX) { if(shift!=ECX) emit_mov(shift,ECX); if((sl!=shift)&&(shift!=tl)) emit_mov(sl,shift); if(th>=0 && sh!=th) emit_mov(sh,th); if(shift==tl) { emit_pushreg(sl); tl=sl; } } else if(th==ECX&&sh!=ECX) { if(shift!=ECX) emit_mov(shift,ECX); if(sh!=shift) emit_mov(sh,shift); if((sl!=tl)&&(shift!=tl)) emit_mov(sl,tl); if(shift==tl) { emit_pushreg(sl); tl=sl; } } else { if((sl!=tl)&&(shift!=tl)) emit_mov(sl,tl); if(th>=0 && sh!=th) emit_mov(sh,th); if(shift!=ECX) { if(shift==tl) { emit_pushreg(sl); tl=sl; } emit_xchg(shift,ECX); } } if(opcode2[i]==0x14) // DSLLV { if(th>=0) emit_shldcl(th==ECX?shift:th,tl==ECX?shift:tl); emit_shlcl(tl==ECX?shift:tl); emit_testimm(ECX,32); if(th>=0) emit_cmovne_reg(tl==ECX?shift:tl,th==ECX?shift:th); emit_cmovne(&const_zero,tl==ECX?shift:tl); } if(opcode2[i]==0x16) // DSRLV { assert(th>=0); emit_shrdcl(tl==ECX?shift:tl,th==ECX?shift:th); emit_shrcl(th==ECX?shift:th); emit_testimm(ECX,32); emit_cmovne_reg(th==ECX?shift:th,tl==ECX?shift:tl); if(real_th>=0) emit_cmovne(&const_zero,th==ECX?shift:th); } if(opcode2[i]==0x17) // DSRAV { assert(th>=0); emit_shrdcl(tl==ECX?shift:tl,th==ECX?shift:th); if(real_th>=0) { assert(temp>=0); emit_mov(th==ECX?shift:th,temp==ECX?shift:temp); } emit_sarcl(th==ECX?shift:th); if(real_th>=0) emit_sarimm(temp==ECX?shift:temp,31,temp==ECX?shift:temp); emit_testimm(ECX,32); emit_cmovne_reg(th==ECX?shift:th,tl==ECX?shift:tl); if(real_th>=0) emit_cmovne_reg(temp==ECX?shift:temp,th==ECX?shift:th); } if(real_tl==ECX&&sl!=ECX&&shift==real_tl) { emit_mov(sl,real_tl); emit_popreg(sl); } else if(th==ECX&&sh!=ECX&&shift==real_tl) { emit_mov(sl,real_tl); emit_popreg(sl); } else { if(shift!=ECX) { emit_xchg(shift,ECX); if(real_tl==shift) { emit_mov(sl,real_tl); emit_popreg(sl); } } } } } } } } #define shift_assemble shift_assemble_x86 static void loadlr_assemble_x86(int i,struct regstat *i_regs) { signed char s,th,tl,temp,temp2,temp2h,addr,map=-1,cache=-1; int offset,type=0,memtarget=0,c=0; intptr_t jaddr=0; u_int hr,reglist=0; th=get_reg(i_regs->regmap,rt1[i]|64); tl=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); temp=get_reg(i_regs->regmap,-1); temp2=get_reg(i_regs->regmap,FTEMP); temp2h=get_reg(i_regs->regmap,FTEMP|64); addr=get_reg(i_regs->regmap,AGEN1+(i&1)); assert(addr<0); assert(temp>=0); assert(temp2>=0); assert(temp2h>=0); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { c=(i_regs->wasconst>>s)&1; memtarget=c&&((signed int)(constmap[i][s]+offset))<(signed int)0x80800000; if(c&&using_tlb&&((signed int)(constmap[i][s]+offset))>=(signed int)0xC0000000) memtarget=1; } if(offset||s<0||c) addr=temp2; else addr=s; int dummy=(rt1[i]==0)||(tl!=get_reg(i_regs->regmap,rt1[i])); // ignore loads to r0 and unneeded reg switch(opcode[i]) { case 0x22: type=LOADWL_STUB; break; case 0x26: type=LOADWR_STUB; break; case 0x1A: type=LOADDL_STUB; break; case 0x1B: type=LOADDR_STUB; break; } #ifndef INTERPRET_LOADLR int ldlr=(opcode[i]==0x1A||opcode[i]==0x1B); // LDL/LDR always do inline_readstub if non constant if(!using_tlb) { if(!c&&!ldlr) { emit_cmpimm(addr,0x800000); jaddr=(intptr_t)out; emit_jno(0); } }else{ // using tlb map=get_reg(i_regs->regmap,TLREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<=0); if(!c) { emit_lea8(addr,temp); emit_andimm(addr,~3,temp2); emit_readword_indexed_tlb(0,temp2,map,temp2); emit_andimm(temp,24,temp); if (opcode[i]==0x26) emit_xorimm(temp,24,temp); // LWR if(temp!=ECX) emit_xchg(ECX,temp); emit_movimm(-1,temp2h==ECX?temp:temp2h); if (opcode[i]==0x26) { emit_shrcl(temp2h==ECX?temp:temp2h); emit_shrcl(temp2==ECX?temp:temp2); }else{ emit_shlcl(temp2h==ECX?temp:temp2h); emit_shlcl(temp2==ECX?temp:temp2); } emit_mov(temp2h==ECX?temp:temp2h,ECX); emit_not(ECX,ECX); if(temp!=ECX) emit_xchg(temp,ECX); emit_and(temp,tl,tl); emit_or(temp2,tl,tl); } else { int shift=((constmap[i][s]+offset)&3)<<3; uint32_t mask=~UINT32_C(0); if (opcode[i]==0x26) { //LWR shift^=24; mask>>=shift; } else { //LWL mask<<=shift; } if(shift) { emit_readword_tlb((constmap[i][s]+offset)&~3,map,temp2); if (opcode[i]==0x26) emit_shrimm(temp2,shift,temp2); else emit_shlimm(temp2,shift,temp2); emit_andimm(tl,~mask,tl); emit_or(temp2,tl,tl); } else emit_readword_tlb((constmap[i][s]+offset)&~3,map,tl); } } if(opcode[i]==0x1A||opcode[i]==0x1B) { // LDL/LDR assert(tl>=0); assert(th>=0); if(!c) { //TODO: implement recompiled code inline_readstub(type,i,0,addr,i_regs,rt1[i],ccadj[i],reglist); } else { int shift=((constmap[i][s]+offset)&7)<<3; uint64_t mask=~UINT64_C(0); if (opcode[i]==0x1B) { //LDR shift^=56; mask>>=shift; } else { //LDL mask<<=shift; } if(shift) { emit_readdword_tlb((constmap[i][s]+offset)&~7,map,temp2h,temp2); if (opcode[i]==0x1B) { emit_shrdimm(temp2h,temp2,shift,temp2h); emit_shrimm(temp2,shift,temp2); } else { emit_shldimm(temp2h,temp2,shift,temp2h); emit_shlimm(temp2,shift,temp2); } emit_andimm(tl,~mask,tl); emit_andimm(th,~mask>>32,th); emit_or(temp2,tl,tl); emit_or(temp2h,th,th); } else emit_readdword_tlb((constmap[i][s]+offset)&~7,map,th,tl); } } } if(jaddr) { add_stub(type,jaddr,(intptr_t)out,i,addr,(intptr_t)i_regs,ccadj[i],reglist); } else if(c&&!memtarget) { inline_readstub(type,i,(constmap[i][s]+offset),addr,i_regs,rt1[i],ccadj[i],reglist); } #else inline_readstub(type,i,c?(constmap[i][s]+offset):0,addr,i_regs,rt1[i],ccadj[i],reglist); #endif } #define loadlr_assemble loadlr_assemble_x86 static void fconv_assemble_x86(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char rs=get_reg(i_regs->regmap,CSREG); assert(rs>=0); emit_testimm(rs,CP0_STATUS_CU1); int jaddr=(int)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(int)out,i,rs,(int)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCONV #ifdef __SSE__ if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { // trunc_w_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_movss_load(temp,0); emit_cvttps2dq(0,0); // float->int, truncate if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_movd_store(0,temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { // trunc_w_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_movsd_load(temp,0); emit_cvttpd2dq(0,0); // double->int, truncate emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_movd_store(0,temp); return; } #endif if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { // cvt_s_w emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_fildl(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); return; } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { // cvt_d_w emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_fildl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); return; } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { // cvt_s_l emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fildll(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); return; } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { // cvt_d_l emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fildll(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); return; } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { // cvt_d_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); return; } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { // cvt_s_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); return; } if(opcode2[i]==0x10) { // cvt_*_s emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); } if(opcode2[i]==0x11) { // cvt_*_d emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); } if((source[i]&0x3f)<0x10) { emit_fnstcw_stack(); if((source[i]&3)==0) emit_fldcw((int)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[0]); //DebugMessage(M64MSG_VERBOSE, "round"); if((source[i]&3)==1) emit_fldcw((int)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[1]); //DebugMessage(M64MSG_VERBOSE, "trunc"); if((source[i]&3)==2) emit_fldcw((int)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[2]); //DebugMessage(M64MSG_VERBOSE, "ceil"); if((source[i]&3)==3) emit_fldcw((int)&g_dev.r4300.new_dynarec_hot_state.rounding_modes[3]); //DebugMessage(M64MSG_VERBOSE, "floor"); } if((source[i]&0x3f)==0x24||(source[i]&0x3c)==0x0c) { // cvt_w_* if(opcode2[i]!=0x10||((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fistpl(temp); } if((source[i]&0x3f)==0x25||(source[i]&0x3c)==0x08) { // cvt_l_* if(opcode2[i]!=0x11||((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fistpll(temp); } if((source[i]&0x3f)<0x10) { emit_fldcw_stack(); } return; #endif // C emulation code for debugging signed char fs=get_reg(i_regs->regmap,FSREG); emit_pusha(); if(opcode2[i]==0x14&&(source[i]&0x3f)==0x20) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_s_w); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x14&&(source[i]&0x3f)==0x21) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)cvt_d_w); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x20) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_s_l); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x15&&(source[i]&0x3f)==0x21) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_d_l); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x21) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)cvt_d_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x24) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_w_s); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x25) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_l_s); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x20) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_s_d); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x24) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_w_d); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x25) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); emit_call((int)cvt_l_d); emit_addimm(ESP,12,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x08) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)round_l_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x09) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)trunc_l_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0a) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)ceil_l_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0b) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)floor_l_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0c) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)round_w_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0d) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)trunc_w_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0e) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)ceil_w_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x10&&(source[i]&0x3f)==0x0f) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_call((int)floor_w_s); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x08) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)round_l_d); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x09) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)trunc_l_d); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0a) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)ceil_l_d); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0b) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)floor_l_d); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0c) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)round_w_d); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0d) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)trunc_w_d); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0e) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)ceil_w_d); emit_addimm(ESP,8,ESP); } if(opcode2[i]==0x11&&(source[i]&0x3f)==0x0f) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_call((int)floor_w_d); emit_addimm(ESP,8,ESP); } emit_popa(); //emit_loadreg(CSREG,rs); return; } #define fconv_assemble fconv_assemble_x86 static void fcomp_assemble(int i,struct regstat *i_regs) { signed char fs=get_reg(i_regs->regmap,FSREG); signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); int jaddr=(int)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FCOMP if((source[i]&0x3f)==0x30) { emit_andimm(fs,~0x800000,fs); return; } if((source[i]&0x3e)==0x38) { // sf/ngle - these should throw exceptions for NaNs emit_andimm(fs,~0x800000,fs); return; } if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],temp); emit_flds(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); emit_movimm(0x800000,temp); emit_or(fs,temp,fs); emit_xor(temp,fs,temp); emit_fucomip(1); emit_fpop(); if((source[i]&0x3f)==0x31) emit_cmovnp_reg(temp,fs); // c_un_s if((source[i]&0x3f)==0x32) {emit_cmovne_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_eq_s if((source[i]&0x3f)==0x33) emit_cmovne_reg(temp,fs); // c_ueq_s if((source[i]&0x3f)==0x34) {emit_cmovnc_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_olt_s if((source[i]&0x3f)==0x35) emit_cmovnc_reg(temp,fs); // c_ult_s if((source[i]&0x3f)==0x36) {emit_cmova_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_ole_s if((source[i]&0x3f)==0x37) emit_cmova_reg(temp,fs); // c_ule_s if((source[i]&0x3f)==0x3a) emit_cmovne_reg(temp,fs); // c_seq_s if((source[i]&0x3f)==0x3b) emit_cmovne_reg(temp,fs); // c_ngl_s if((source[i]&0x3f)==0x3c) emit_cmovnc_reg(temp,fs); // c_lt_s if((source[i]&0x3f)==0x3d) emit_cmovnc_reg(temp,fs); // c_nge_s if((source[i]&0x3f)==0x3e) emit_cmova_reg(temp,fs); // c_le_s if((source[i]&0x3f)==0x3f) emit_cmova_reg(temp,fs); // c_ngt_s return; } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],temp); emit_fldl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); emit_movimm(0x800000,temp); emit_or(fs,temp,fs); emit_xor(temp,fs,temp); emit_fucomip(1); emit_fpop(); if((source[i]&0x3f)==0x31) emit_cmovnp_reg(temp,fs); // c_un_d if((source[i]&0x3f)==0x32) {emit_cmovne_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_eq_d if((source[i]&0x3f)==0x33) emit_cmovne_reg(temp,fs); // c_ueq_d if((source[i]&0x3f)==0x34) {emit_cmovnc_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_olt_d if((source[i]&0x3f)==0x35) emit_cmovnc_reg(temp,fs); // c_ult_d if((source[i]&0x3f)==0x36) {emit_cmova_reg(temp,fs);emit_cmovp_reg(temp,fs);} // c_ole_d if((source[i]&0x3f)==0x37) emit_cmova_reg(temp,fs); // c_ule_d if((source[i]&0x3f)==0x3a) emit_cmovne_reg(temp,fs); // c_seq_d if((source[i]&0x3f)==0x3b) emit_cmovne_reg(temp,fs); // c_ngl_d if((source[i]&0x3f)==0x3c) emit_cmovnc_reg(temp,fs); // c_lt_d if((source[i]&0x3f)==0x3d) emit_cmovnc_reg(temp,fs); // c_nge_d if((source[i]&0x3f)==0x3e) emit_cmova_reg(temp,fs); // c_le_d if((source[i]&0x3f)==0x3f) emit_cmova_reg(temp,fs); // c_ngt_d return; } #endif emit_storereg(FSREG, fs); emit_pusha(); if(opcode2[i]==0x10) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); if((source[i]&0x3f)==0x30) emit_call((int)c_f_s); if((source[i]&0x3f)==0x31) emit_call((int)c_un_s); if((source[i]&0x3f)==0x32) emit_call((int)c_eq_s); if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_s); if((source[i]&0x3f)==0x34) emit_call((int)c_olt_s); if((source[i]&0x3f)==0x35) emit_call((int)c_ult_s); if((source[i]&0x3f)==0x36) emit_call((int)c_ole_s); if((source[i]&0x3f)==0x37) emit_call((int)c_ule_s); if((source[i]&0x3f)==0x38) emit_call((int)c_sf_s); if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_s); if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_s); if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_s); if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_s); if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_s); if((source[i]&0x3f)==0x3e) emit_call((int)c_le_s); if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_s); } if(opcode2[i]==0x11) { emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); if((source[i]&0x3f)==0x30) emit_call((int)c_f_d); if((source[i]&0x3f)==0x31) emit_call((int)c_un_d); if((source[i]&0x3f)==0x32) emit_call((int)c_eq_d); if((source[i]&0x3f)==0x33) emit_call((int)c_ueq_d); if((source[i]&0x3f)==0x34) emit_call((int)c_olt_d); if((source[i]&0x3f)==0x35) emit_call((int)c_ult_d); if((source[i]&0x3f)==0x36) emit_call((int)c_ole_d); if((source[i]&0x3f)==0x37) emit_call((int)c_ule_d); if((source[i]&0x3f)==0x38) emit_call((int)c_sf_d); if((source[i]&0x3f)==0x39) emit_call((int)c_ngle_d); if((source[i]&0x3f)==0x3a) emit_call((int)c_seq_d); if((source[i]&0x3f)==0x3b) emit_call((int)c_ngl_d); if((source[i]&0x3f)==0x3c) emit_call((int)c_lt_d); if((source[i]&0x3f)==0x3d) emit_call((int)c_nge_d); if((source[i]&0x3f)==0x3e) emit_call((int)c_le_d); if((source[i]&0x3f)==0x3f) emit_call((int)c_ngt_d); } emit_addimm(ESP,12,ESP); emit_popa(); emit_loadreg(FSREG,fs); return; } static void float_assemble(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); assert(temp>=0); // Check cop1 unusable if(!cop1_usable) { signed char cs=get_reg(i_regs->regmap,CSREG); assert(cs>=0); emit_testimm(cs,CP0_STATUS_CU1); int jaddr=(int)out; emit_jeq(0); add_stub(FP_STUB,jaddr,(int)out,i,cs,(int)i_regs,is_delayslot,0); cop1_usable=1; } #ifndef INTERPRET_FLOAT if((source[i]&0x3f)==6) // mov { if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); emit_fstps(temp); } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); emit_fstpl(temp); } } return; } if((source[i]&0x3f)>3) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); if(((source[i]>>11)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } } if((source[i]&0x3f)==4) // sqrt emit_fsqrt(); if((source[i]&0x3f)==5) // abs emit_fabs(); if((source[i]&0x3f)==7) // neg emit_fchs(); if(opcode2[i]==0x10) { emit_fstps(temp); } if(opcode2[i]==0x11) { emit_fstpl(temp); } return; } if((source[i]&0x3f)<4) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f],temp); emit_flds(temp); } if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f],temp); emit_fldl(temp); } if(((source[i]>>11)&0x1f)!=((source[i]>>16)&0x1f)) { if(opcode2[i]==0x10) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f],temp); if((source[i]&0x3f)==0) emit_fadds(temp); if((source[i]&0x3f)==1) emit_fsubs(temp); if((source[i]&0x3f)==2) emit_fmuls(temp); if((source[i]&0x3f)==3) emit_fdivs(temp); } else if(opcode2[i]==0x11) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f],temp); if((source[i]&0x3f)==0) emit_faddl(temp); if((source[i]&0x3f)==1) emit_fsubl(temp); if((source[i]&0x3f)==2) emit_fmull(temp); if((source[i]&0x3f)==3) emit_fdivl(temp); } } else { if((source[i]&0x3f)==0) emit_fadd(0); if((source[i]&0x3f)==1) emit_fsub(0); if((source[i]&0x3f)==2) emit_fmul(0); if((source[i]&0x3f)==3) emit_fdiv(0); } if(opcode2[i]==0x10) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>6)&0x1f],temp); } emit_fstps(temp); } if(opcode2[i]==0x11) { if(((source[i]>>16)&0x1f)!=((source[i]>>6)&0x1f)) { emit_readptr((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>6)&0x1f],temp); } emit_fstpl(temp); } return; } #endif signed char fs=get_reg(i_regs->regmap,FSREG); if(opcode2[i]==0x10) { // Single precision emit_pusha(); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>> 6)&0x1f]); if((source[i]&0x3f)<4) emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>16)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_simple[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); switch(source[i]&0x3f) { case 0x00: emit_call((int)add_s); emit_addimm(ESP,16,ESP); break; case 0x01: emit_call((int)sub_s); emit_addimm(ESP,16,ESP); break; case 0x02: emit_call((int)mul_s); emit_addimm(ESP,16,ESP); break; case 0x03: emit_call((int)div_s); emit_addimm(ESP,16,ESP); break; case 0x04: emit_call((int)sqrt_s); emit_addimm(ESP,12,ESP); break; case 0x05: emit_call((int)abs_s); emit_addimm(ESP,8,ESP); break; case 0x06: emit_call((int)mov_s); emit_addimm(ESP,8,ESP); break; case 0x07: emit_call((int)neg_s); emit_addimm(ESP,8,ESP); break; } emit_popa(); } if(opcode2[i]==0x11) { // Double precision emit_pusha(); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>> 6)&0x1f]); if((source[i]&0x3f)<4) emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>16)&0x1f]); emit_pushmem((intptr_t)&g_dev.r4300.new_dynarec_hot_state.cp1_regs_double[(source[i]>>11)&0x1f]); emit_pushimm((int)&g_dev.r4300.new_dynarec_hot_state.cp1_fcr31); switch(source[i]&0x3f) { case 0x00: emit_call((int)add_d); emit_addimm(ESP,16,ESP); break; case 0x01: emit_call((int)sub_d); emit_addimm(ESP,16,ESP); break; case 0x02: emit_call((int)mul_d); emit_addimm(ESP,16,ESP); break; case 0x03: emit_call((int)div_d); emit_addimm(ESP,16,ESP); break; case 0x04: emit_call((int)sqrt_d); emit_addimm(ESP,12,ESP); break; case 0x05: emit_call((int)abs_d); emit_addimm(ESP,8,ESP); break; case 0x06: emit_call((int)mov_d); emit_addimm(ESP,8,ESP); break; case 0x07: emit_call((int)neg_d); emit_addimm(ESP,8,ESP); break; } emit_popa(); } } static void multdiv_assemble_x86(int i,struct regstat *i_regs) { // case 0x18: MULT // case 0x19: MULTU // case 0x1A: DIV // case 0x1B: DIVU // case 0x1C: DMULT // case 0x1D: DMULTU // case 0x1E: DDIV // case 0x1F: DDIVU if(rs1[i]&&rs2[i]) { if((opcode2[i]&4)==0) // 32-bit { #ifndef INTERPRET_MULT if((opcode2[i]==0x18) || (opcode2[i]==0x19)) { signed char m1=get_reg(i_regs->regmap,rs1[i]); signed char m2=get_reg(i_regs->regmap,rs2[i]); assert(m1>=0); assert(m2>=0); emit_mov(m1,EAX); if(opcode2[i]==0x18) //MULT emit_imul(m2); else if(opcode2[i]==0x19) //MULTU emit_mul(m2); } else #endif #ifndef INTERPRET_DIV if((opcode2[i]==0x1A) || (opcode2[i]==0x1B)) { signed char d1=get_reg(i_regs->regmap,rs1[i]); signed char d2=get_reg(i_regs->regmap,rs2[i]); assert(d1>=0); assert(d2>=0); emit_mov(d1,EAX); if(opcode2[i]==0x1A) //DIV { emit_cdq(); emit_test(d2,d2); emit_jeq((int)out+8); emit_idiv(d2); } else if(opcode2[i]==0x1B) //DIVU { emit_zeroreg(EDX); emit_test(d2,d2); emit_jeq((int)out+8); emit_div(d2); } } else #endif { u_int reglist=0; signed char r1=get_reg(i_regs->regmap,rs1[i]); signed char r2=get_reg(i_regs->regmap,rs2[i]); signed char hi=get_reg(i_regs->regmap,HIREG); signed char lo=get_reg(i_regs->regmap,LOREG); assert(r1>=0); assert(r2>=0); emit_writeword(r1,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.rs); emit_writeword(r2,(intptr_t)&g_dev.r4300.new_dynarec_hot_state.rt); emit_pusha(); if(opcode2[i]==0x18) emit_call((intptr_t)cached_interp_MULT); else if(opcode2[i]==0x19) emit_call((intptr_t)cached_interp_MULTU); else if(opcode2[i]==0x1A) emit_call((intptr_t)cached_interp_DIV); else if(opcode2[i]==0x1B) emit_call((intptr_t)cached_interp_DIVU); emit_popa(); if(hi>=0) emit_loadreg(HIREG,hi); if(lo>=0) emit_loadreg(LOREG,lo); } } else // 64-bit { #ifndef INTERPRET_MULT64 if(opcode2[i]==0x1C||opcode2[i]==0x1D) { signed char m1h=get_reg(i_regs->regmap,rs1[i]|64); signed char m1l=get_reg(i_regs->regmap,rs1[i]); signed char m2h=get_reg(i_regs->regmap,rs2[i]|64); signed char m2l=get_reg(i_regs->regmap,rs2[i]); signed char temp=get_reg(i_regs->regmap,-1); assert((m1h>=0)&&(m1h!=EAX)&&(m1h!=EDX)); assert((m2h>=0)&&(m2h!=EAX)&&(m2h!=EDX)); assert((m1l>=0)&&(m1l!=EAX)&&(m1l!=EDX)); assert((m2l>=0)&&(m2l!=EAX)&&(m2l!=EDX)); assert((temp>=0)&&(temp!=EAX)&&(temp!=EDX)); if(opcode2[i]==0x1C) // DMULT { // Multiply m2l*m1l emit_mov(m1l,EAX); emit_mul(m2l); emit_storereg(LOREG,EAX); emit_mov(EDX,temp); // Multiply m2l*m1h emit_mov(m1h,EAX); emit_mul(m2l); emit_add(EAX,temp,temp); emit_adcimm(0,EDX); emit_storereg(HIREG,EDX); // Multiply m2h*m1l emit_mov(m1l,EAX); emit_mul(m2h); emit_add(EAX,temp,temp); emit_adcimm(0,EDX); emit_storereg(LOREG|64,temp); emit_mov(EDX,temp); // Multiply m2h*m1h emit_mov(m1h,EAX); emit_mul(m2h); emit_add(EAX,temp,EAX); emit_adcimm(0,EDX); emit_loadreg(HIREG,temp); emit_add(EAX,temp,EAX); emit_adcimm(0,EDX); // If m1<0 subtract m2 from the high 64bit part emit_testimm(m1h,0x80000000); emit_jeq((int)out+10); emit_sub(EAX,m2l,EAX); emit_sbb(m2h,EDX); // If m2<0 subtract m1 from the high 64bit part emit_testimm(m2h,0x80000000); emit_jeq((int)out+10); emit_sub(EAX,m1l,EAX); emit_sbb(m1h,EDX); } else if(opcode2[i]==0x1D) // DMULTU { // Multiply m2l*m1l emit_mov(m1l,EAX); emit_mul(m2l); emit_storereg(LOREG,EAX); emit_mov(EDX,temp); // Multiply m2l*m1h emit_mov(m1h,EAX); emit_mul(m2l); emit_add(EAX,temp,temp); emit_adcimm(0,EDX); emit_storereg(HIREG,EDX); // Multiply m2h*m1l emit_mov(m1l, EAX); emit_mul(m2h); emit_add(EAX,temp,temp); emit_adcimm(0,EDX); emit_storereg(LOREG|64,temp); emit_mov(EDX,temp); // Multiply m2h*m1h emit_mov(m1h,EAX); emit_mul(m2h); emit_add(EAX,temp,EAX); emit_adcimm(0, EDX); emit_loadreg(HIREG,temp); emit_add(EAX,temp,EAX); emit_adcimm(0,EDX); } } else #endif { signed char r1h=get_reg(i_regs->regmap,rs1[i]|64); signed char r1l=get_reg(i_regs->regmap,rs1[i]); signed char r2h=get_reg(i_regs->regmap,rs2[i]|64); signed char r2l=get_reg(i_regs->regmap,rs2[i]); signed char hih=get_reg(i_regs->regmap,HIREG|64); signed char hil=get_reg(i_regs->regmap,HIREG); signed char loh=get_reg(i_regs->regmap,LOREG|64); signed char lol=get_reg(i_regs->regmap,LOREG); assert(r1h>=0); assert(r2h>=0); assert(r1l>=0); assert(r2l>=0); emit_writeword(r1l,(int)&g_dev.r4300.new_dynarec_hot_state.rs); emit_writeword(r1h,((int)&g_dev.r4300.new_dynarec_hot_state.rs)+4); emit_writeword(r2l,(int)&g_dev.r4300.new_dynarec_hot_state.rt); emit_writeword(r2h,((int)&g_dev.r4300.new_dynarec_hot_state.rt)+4); emit_pusha(); if(opcode2[i]==0x1C) // DMULT emit_call((int)cached_interp_DMULT); else if(opcode2[i]==0x1D) // DMULTU emit_call((int)cached_interp_DMULTU); else if(opcode2[i]==0x1E) // DDIV emit_call((int)cached_interp_DDIV); else if(opcode2[i]==0x1F) // DDIVU emit_call((int)cached_interp_DDIVU); emit_popa(); if(hih>=0) emit_loadreg(HIREG|64,hih); if(hil>=0) emit_loadreg(HIREG,hil); if(loh>=0) emit_loadreg(LOREG|64,loh); if(lol>=0) emit_loadreg(LOREG,lol); } } } else { // Multiply by zero is zero. // MIPS does not have a divide by zero exception. // The result is undefined, we return zero. signed char hr=get_reg(i_regs->regmap,HIREG); signed char lr=get_reg(i_regs->regmap,LOREG); if(hr>=0) emit_zeroreg(hr); if(lr>=0) emit_zeroreg(lr); } } #define multdiv_assemble multdiv_assemble_x86 static void do_preload_rhash(int r) { emit_movimm(0xf8,r); } static void do_preload_rhtbl(int r) { // Don't need this for x86 } static void do_rhash(int rs,int rh) { emit_and(rs,rh,rh); } static void do_miniht_load(int ht,int rh) { // Don't need this for x86. The load and compare can be combined into // a single instruction (below) } static void do_miniht_jump(int rs,int rh,int ht) { emit_cmpmem_indexed((int)g_dev.r4300.new_dynarec_hot_state.mini_ht,rh,rs); emit_jne(jump_vaddr_reg[rs]); emit_jmpmem_indexed((int)g_dev.r4300.new_dynarec_hot_state.mini_ht+4,rh); } static void do_miniht_insert(int return_address,int rt,int temp) { emit_movimm(return_address,rt); // PC into link register //emit_writeword_imm(return_address,(int)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0xFF)>>8][0]); emit_writeword(rt,(int)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0xFF)>>3][0]); add_to_linker((int)out,return_address,1); emit_writeword_imm(0,(int)&g_dev.r4300.new_dynarec_hot_state.mini_ht[(return_address&0xFF)>>3][1]); } // We don't need this for x86 static void literal_pool(int n) {} static void literal_pool_jumpover(int n) {} // CPU-architecture-specific initialization, not needed for x86 static void arch_init(void) { g_dev.r4300.new_dynarec_hot_state.rounding_modes[0]=0x33F; // round g_dev.r4300.new_dynarec_hot_state.rounding_modes[1]=0xF3F; // trunc g_dev.r4300.new_dynarec_hot_state.rounding_modes[2]=0xB3F; // ceil g_dev.r4300.new_dynarec_hot_state.rounding_modes[3]=0x73F; // floor } mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x86/assem_x86.h000066400000000000000000000013361464506436200251600ustar00rootroot00000000000000#ifndef M64P_DEVICE_R4300_NEW_DYNAREC_X86_ASSEM_X86_H #define M64P_DEVICE_R4300_NEW_DYNAREC_X86_ASSEM_X86_H #define EAX 0 #define ECX 1 #define EDX 2 #define EBX 3 #define ESP 4 #define EBP 5 #define ESI 6 #define EDI 7 #define HOST_REGS 8 #define HOST_CCREG ESI #define HOST_BTREG EBP #define EXCLUDE_REG ESP //#define IMM_PREFETCH 1 #define HOST_IMM_ADDR32 1 #define INVERTED_CARRY 1 #define DESTRUCTIVE_WRITEBACK 1 #define DESTRUCTIVE_SHIFT 1 #define USE_MINI_HT 1 #define TARGET_SIZE_2 25 // 2^25 = 32 megabytes #define JUMP_TABLE_SIZE 0 // Not needed for 32-bit x86 /* x86 calling convention: caller-save: %eax %ecx %edx callee-save: %ebp %ebx %esi %edi */ #endif /* M64P_DEVICE_R4300_NEW_DYNAREC_X86_ASSEM_X86_H */ mupen64plus-core-src-2.6.0/src/device/r4300/new_dynarec/x86/linkage_x86.asm000066400000000000000000000174301464506436200260150ustar00rootroot00000000000000;Mupen64plus - linkage_x86.asm ;Copyright (C) 2009-2011 Ari64 ; ;This program is free software; you can redistribute it and/or modify ;it under the terms of the GNU General Public License as published by ;the Free Software Foundation; either version 2 of the License, or ;(at your option) any later version. ; ;This program is distributed in the hope that it will be useful, ;but WITHOUT ANY WARRANTY; without even the implied warranty of ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;GNU General Public License for more details. ; ;You should have received a copy of the GNU General Public License ;along with this program; if not, write to the ;Free Software Foundation, Inc., ;51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. %include "asm_defines_nasm.h" %ifidn __OUTPUT_FORMAT__,elf section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf32 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf64 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifdef LEADING_UNDERSCORE %macro cglobal 1 global _%1 %define %1 _%1 %endmacro %macro cextern 1 extern _%1 %define %1 _%1 %endmacro %else %macro cglobal 1 global %1 %endmacro %macro cextern 1 extern %1 %endmacro %endif %macro get_GOT 0 call %%getgot %%getgot: pop ebx add ebx,_GLOBAL_OFFSET_TABLE_+$$-%%getgot wrt ..gotpc %endmacro %ifdef PIC %define get_got_address get_GOT %define find_local_data(a) ebx + a wrt ..gotoff %define find_external_data(a) ebx + a wrt ..got %else %define get_got_address %define find_local_data(a) a %define find_extern_data(a) a %endif %define g_dev_r4300_new_dynarec_hot_state_stop (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_stop) %define g_dev_r4300_new_dynarec_hot_state_cycle_count (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_cycle_count) %define g_dev_r4300_new_dynarec_hot_state_pending_exception (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_pending_exception) %define g_dev_r4300_new_dynarec_hot_state_pcaddr (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_new_dynarec_hot_state + offsetof_struct_new_dynarec_hot_state_pcaddr) cglobal jump_vaddr_eax cglobal jump_vaddr_ecx cglobal jump_vaddr_edx cglobal jump_vaddr_ebx cglobal jump_vaddr_ebp cglobal jump_vaddr_edi cglobal verify_code cglobal cc_interrupt cglobal do_interrupt cglobal fp_exception cglobal jump_syscall cglobal jump_eret cglobal new_dyna_start cglobal invalidate_block_eax cglobal invalidate_block_ecx cglobal invalidate_block_edx cglobal invalidate_block_ebx cglobal invalidate_block_ebp cglobal invalidate_block_esi cglobal invalidate_block_edi cglobal breakpoint cglobal dyna_linker cglobal dyna_linker_ds cextern base_addr cextern new_recompile_block cextern get_addr_ht cextern get_addr cextern dynarec_gen_interrupt cextern clean_blocks cextern invalidate_block cextern ERET_new cextern get_addr_32 cextern g_dev cextern verify_dirty cextern cop1_unusable cextern SYSCALL_new cextern dynamic_linker cextern dynamic_linker_ds %ifdef PIC cextern _GLOBAL_OFFSET_TABLE_ %endif section .bss align 4 section .rodata section .text jump_vaddr_eax: mov edi, eax jmp jump_vaddr_edi jump_vaddr_ecx: mov edi, ecx jmp jump_vaddr_edi jump_vaddr_edx: mov edi, edx jmp jump_vaddr_edi jump_vaddr_ebx: mov edi, ebx jmp jump_vaddr_edi jump_vaddr_ebp: mov edi, ebp jump_vaddr_edi: mov eax, edi jump_vaddr: add esp, -12 push edi call get_addr_ht add esp, 16 jmp eax verify_code: ;eax = head add esp, -8 push eax call verify_dirty test eax,eax jne _D1 add esp, 12 ret _D1: add esp, 4 push eax call get_addr add esp, 16 jmp eax cc_interrupt: get_got_address mov [find_local_data(g_dev_r4300_new_dynarec_hot_state_cycle_count)], esi ;Count add esp, -28 ;Align stack mov DWORD [find_local_data(g_dev_r4300_new_dynarec_hot_state_pending_exception)], 0 call dynarec_gen_interrupt mov esi, [find_local_data(g_dev_r4300_new_dynarec_hot_state_cycle_count)] mov edx, [find_local_data(g_dev_r4300_new_dynarec_hot_state_pending_exception)] mov ecx, [find_local_data(g_dev_r4300_new_dynarec_hot_state_stop)] add esp, 28 test ecx, ecx jne _E2 test edx, edx jne _E1 ret _E1: add esp, -8 mov edi, [find_local_data(g_dev_r4300_new_dynarec_hot_state_pcaddr)] push edi call get_addr_ht add esp, 16 jmp eax _E2: add esp, 4 ;pop return address new_dyna_stop: add esp, 12 ;pop stack pop edi ;restore edi pop esi ;restore esi pop ebx ;restore ebx pop ebp ;restore ebp ret ;exit dynarec do_interrupt: get_got_address mov ecx, [find_local_data(g_dev_r4300_new_dynarec_hot_state_stop)] test ecx, ecx jne new_dyna_stop mov edi, [find_local_data(g_dev_r4300_new_dynarec_hot_state_pcaddr)] add esp, -12 push edi call get_addr_ht add esp, 16 mov esi, [find_local_data(g_dev_r4300_new_dynarec_hot_state_cycle_count)] jmp eax fp_exception: get_got_address mov [find_local_data(g_dev_r4300_new_dynarec_hot_state_pcaddr)], eax call cop1_unusable jmp eax jump_syscall: get_got_address mov [find_local_data(g_dev_r4300_new_dynarec_hot_state_pcaddr)], eax call SYSCALL_new jmp eax jump_eret: get_got_address mov [find_local_data(g_dev_r4300_new_dynarec_hot_state_cycle_count)], esi call ERET_new mov esi, [find_local_data(g_dev_r4300_new_dynarec_hot_state_cycle_count)] test eax, eax je new_dyna_stop jmp eax dyna_linker: call dynamic_linker add esp, 8 jmp eax dyna_linker_ds: call dynamic_linker_ds add esp, 8 jmp eax new_dyna_start: push ebp push ebx push esi push edi add esp, -8 ;align stack push 0a4000040h call new_recompile_block get_got_address mov esi, DWORD [find_local_data(g_dev_r4300_new_dynarec_hot_state_cycle_count)] jmp DWORD [find_local_data(base_addr)] invalidate_block_eax: push eax push ecx push edx push eax jmp invalidate_block_call invalidate_block_ecx: push eax push ecx push edx push ecx jmp invalidate_block_call invalidate_block_edx: push eax push ecx push edx push edx jmp invalidate_block_call invalidate_block_ebx: push eax push ecx push edx push ebx jmp invalidate_block_call invalidate_block_ebp: push eax push ecx push edx push ebp jmp invalidate_block_call invalidate_block_esi: push eax push ecx push edx push esi jmp invalidate_block_call invalidate_block_edi: push eax push ecx push edx push edi invalidate_block_call: call invalidate_block pop eax ;Throw away pop edx pop ecx pop eax ret breakpoint: int 3 ret mupen64plus-core-src-2.6.0/src/device/r4300/opcodes.md000066400000000000000000000057071464506436200222330ustar00rootroot00000000000000 X(RESERVED), X(ADD), X(ADDI), X(ADDIU), X(ADDU), X(AND), X(ANDI), X(BC0F), X(BC0F_IDLE), X(BC0F_OUT), X(BC0FL), X(BC0FL_IDLE), X(BC0FL_OUT), X(BC0T), X(BC0T_IDLE), X(BC0T_OUT), X(BC0TL), X(BC0TL_IDLE), X(BC0TL_OUT), X(BC1F), X(BC1F_IDLE), X(BC1F_OUT), X(BC1FL), X(BC1FL_IDLE), X(BC1FL_OUT), X(BC1T), X(BC1T_IDLE), X(BC1T_OUT), X(BC1TL), X(BC1TL_IDLE), X(BC1TL_OUT), X(BC2F), X(BC2F_IDLE), X(BC2F_OUT), X(BC2FL), X(BC2FL_IDLE), X(BC2FL_OUT), X(BC2T), X(BC2T_IDLE), X(BC2T_OUT), X(BC2TL), X(BC2TL_IDLE), X(BC2TL_OUT), X(BEQ), X(BEQ_IDLE), X(BEQ_OUT), X(BEQL), X(BEQL_IDLE), X(BEQL_OUT), X(BGEZ), X(BGEZ_IDLE), X(BGEZ_OUT), X(BGEZAL), X(BGEZAL_IDLE), X(BGEZAL_OUT), X(BGEZALL), X(BGEZALL_IDLE), X(BGEZALL_OUT), X(BGEZL), X(BGEZL_IDLE), X(BGEZL_OUT), X(BGTZ), X(BGTZ_IDLE), X(BGTZ_OUT), X(BGTZL), X(BGTZL_IDLE), X(BGTZL_OUT), X(BLEZ), X(BLEZ_IDLE), X(BLEZ_OUT), X(BLEZL), X(BLEZL_IDLE), X(BLEZL_OUT), X(BLTZ), X(BLTZ_IDLE), X(BLTZ_OUT), X(BLTZAL), X(BLTZAL_IDLE), X(BLTZAL_OUT), X(BLTZALL), X(BLTZALL_IDLE), X(BLTZALL_OUT), X(BLTZL), X(BLTZL_IDLE), X(BLTZL_OUT), X(BNE), X(BNE_IDLE), X(BNE_OUT), X(BNEL), X(BNEL_IDLE), X(BNEL_OUT), X(BREAK), X(CACHE), X(CFC0), X(CFC1), X(DCFC1), X(CFC2), X(DCFC2), X(CP1_ABS), X(CP1_ADD), X(CP1_CEIL_L), X(CP1_CEIL_W), X(CP1_C_EQ), X(CP1_C_F), X(CP1_C_LE), X(CP1_C_LT), X(CP1_C_NGE), X(CP1_C_NGL), X(CP1_C_NGLE), X(CP1_C_NGT), X(CP1_C_OLE), X(CP1_C_OLT), X(CP1_C_SEQ), X(CP1_C_SF), X(CP1_C_UEQ), X(CP1_C_ULE), X(CP1_C_ULT), X(CP1_C_UN), X(CP1_CVT_D), X(CP1_CVT_L), X(CP1_CVT_S), X(CP1_CVT_W), X(CP1_DIV), X(CP1_FLOOR_L), X(CP1_FLOOR_W), X(CP1_MOV), X(CP1_MUL), X(CP1_NEG), X(CP1_ROUND_L), X(CP1_ROUND_W), X(CP1_SQRT), X(CP1_SUB), X(CP1_TRUNC_L), X(CP1_TRUNC_W), X(CTC0), X(CTC1), X(DCTC1), X(CTC2), X(DCTC2), X(DADD), X(DADDI), X(DADDIU), X(DADDU), X(DDIV), X(DDIVU), X(DIV), X(DIVU), X(DMFC0), X(DMFC1), X(DMFC2), X(DMTC0), X(DMTC1), X(DMTC2), X(DMULT), X(DMULTU), X(DSLL), X(DSLL32), X(DSLLV), X(DSRA), X(DSRA32), X(DSRAV), X(DSRL), X(DSRL32), X(DSRLV), X(DSUB), X(DSUBU), X(ERET), X(J), X(J_IDLE), X(J_OUT), X(JAL), X(JAL_IDLE), X(JAL_OUT), X(JALR), X(JALR_IDLE), X(JALR_OUT), X(JR), X(JR_IDLE), X(JR_OUT), X(LB), X(LBU), X(LD), X(LDC1), X(LDC2), X(LDL), X(LDR), X(LH), X(LHU), X(LL), X(LLD), X(LUI), X(LW), X(LWC1), X(LWC2), X(LWL), X(LWR), X(LWU), X(MFC0), X(MFC1), X(MFC2), X(MFHI), X(MFLO), X(MTC0), X(MTC1), X(MTC2), X(MTHI), X(MTLO), X(MULT), X(MULTU), X(NOP), X(NOR), X(OR), X(ORI), X(SB), X(SC), X(SCD), X(SD), X(SDC1), X(SDC2), X(SDL), X(SDR), X(SH), X(SLL), X(SLLV), X(SLT), X(SLTI), X(SLTIU), X(SLTU), X(SRA), X(SRAV), X(SRL), X(SRLV), X(SUB), X(SUBU), X(SW), X(SWC1), X(SWC2), X(SWL), X(SWR), X(SYNC), X(SYSCALL), X(TEQ), X(TEQI), X(TGE), X(TGEI), X(TGEIU), X(TGEU), X(TLBP), X(TLBR), X(TLBWI), X(TLBWR), X(TLT), X(TLTI), X(TLTIU), X(TLTU), X(TNE), X(TNEI), X(XOR), X(XORI) mupen64plus-core-src-2.6.0/src/device/r4300/pure_interp.c000066400000000000000000000657771464506436200227720ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - pure_interp.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2015 Nebuleon * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "pure_interp.h" #include #define __STDC_FORMAT_MACROS #include #include "api/callbacks.h" #include "api/debugger.h" #include "api/m64p_types.h" #include "device/r4300/r4300_core.h" #include "osal/preproc.h" #ifdef DBG #include "debugger/dbg_debugger.h" #endif static void InterpretOpcode(struct r4300_core* r4300); #define DECLARE_R4300 #define PCADDR r4300->interp_PC.addr #define ADD_TO_PC(x) r4300->interp_PC.addr += x*4; #define DECLARE_INSTRUCTION(name) static void name(struct r4300_core* r4300, uint32_t op) #define DECLARE_JUMP(name, destination, condition, link, likely, cop1) \ static void name(struct r4300_core* r4300, uint32_t op) \ { \ const int take_jump = (condition); \ const uint32_t jump_target = (destination); \ int64_t *link_register = (link); \ if (cop1 && check_cop1_unusable(r4300)) return; \ if (link_register != &r4300_regs(r4300)[0]) \ { \ *link_register = SE32(r4300->interp_PC.addr + 8); \ } \ if (!likely || take_jump) \ { \ r4300->interp_PC.addr += 4; \ r4300->delay_slot=1; \ InterpretOpcode(r4300); \ cp0_update_count(r4300); \ r4300->delay_slot=0; \ if (take_jump && !r4300->skip_jump) \ { \ r4300->interp_PC.addr = jump_target; \ } \ } \ else \ { \ r4300->interp_PC.addr += 8; \ cp0_update_count(r4300); \ } \ r4300->cp0.last_addr = r4300->interp_PC.addr; \ if (*r4300_cp0_cycle_count(&r4300->cp0) >= 0) gen_interrupt(r4300); \ } \ static void name##_IDLE(struct r4300_core* r4300, uint32_t op) \ { \ uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0); \ int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0); \ const int take_jump = (condition); \ if (cop1 && check_cop1_unusable(r4300)) return; \ if (take_jump) \ { \ cp0_update_count(r4300); \ if(*cp0_cycle_count < 0) \ { \ cp0_regs[CP0_COUNT_REG] -= *cp0_cycle_count; \ *cp0_cycle_count = 0; \ } \ } \ name(r4300, op); \ } #define RD_OF(op) (((op) >> 11) & 0x1F) #define RS_OF(op) (((op) >> 21) & 0x1F) #define RT_OF(op) (((op) >> 16) & 0x1F) #define SA_OF(op) (((op) >> 6) & 0x1F) #define IMM16S_OF(op) ((int16_t) (op)) #define IMM16U_OF(op) ((uint16_t) (op)) #define FD_OF(op) (((op) >> 6) & 0x1F) #define FS_OF(op) (((op) >> 11) & 0x1F) #define FT_OF(op) (((op) >> 16) & 0x1F) #define JUMP_OF(op) ((op) & UINT32_C(0x3FFFFFF)) /* Determines whether a relative jump in a 16-bit immediate goes back to the * same instruction without doing any work in its delay slot. The jump is * relative to the instruction in the delay slot, so 1 instruction backwards * (-1) goes back to the jump. */ #define IS_RELATIVE_IDLE_LOOP(r4300, op, addr) \ (IMM16S_OF(op) == -1 && *fast_mem_access((r4300), (addr) + 4) == 0) /* Determines whether an absolute jump in a 26-bit immediate goes back to the * same instruction without doing any work in its delay slot. The jump is * in the same 256 MiB segment as the delay slot, so if the jump instruction * is at the last address in its segment, it does not jump back to itself. */ #define IS_ABSOLUTE_IDLE_LOOP(r4300, op, addr) \ (JUMP_OF(op) == ((addr) & UINT32_C(0x0FFFFFFF)) >> 2 \ && ((addr) & UINT32_C(0x0FFFFFFF)) != UINT32_C(0x0FFFFFFC) \ && *fast_mem_access((r4300), (addr) + 4) == 0) /* These macros parse opcode fields. */ #define rrt r4300_regs(r4300)[RT_OF(op)] #define rrd r4300_regs(r4300)[RD_OF(op)] #define rfs FS_OF(op) #define rrs r4300_regs(r4300)[RS_OF(op)] #define rsa SA_OF(op) #define irt r4300_regs(r4300)[RT_OF(op)] #define ioffset IMM16S_OF(op) #define iimmediate IMM16S_OF(op) #define irs r4300_regs(r4300)[RS_OF(op)] #define ibase r4300_regs(r4300)[RS_OF(op)] #define jinst_index JUMP_OF(op) #define lfbase RS_OF(op) #define lfft FT_OF(op) #define lfoffset IMM16S_OF(op) #define cfft FT_OF(op) #define cffs FS_OF(op) #define cffd FD_OF(op) // 32 bits macros #ifndef M64P_BIG_ENDIAN #define rrt32 *((int32_t*) &r4300_regs(r4300)[RT_OF(op)]) #define rrd32 *((int32_t*) &r4300_regs(r4300)[RD_OF(op)]) #define rrs32 *((int32_t*) &r4300_regs(r4300)[RS_OF(op)]) #define irs32 *((int32_t*) &r4300_regs(r4300)[RS_OF(op)]) #define irt32 *((int32_t*) &r4300_regs(r4300)[RT_OF(op)]) #else #define rrt32 *((int32_t*) &r4300_regs(r4300)[RT_OF(op)] + 1) #define rrd32 *((int32_t*) &r4300_regs(r4300)[RD_OF(op)] + 1) #define rrs32 *((int32_t*) &r4300_regs(r4300)[RS_OF(op)] + 1) #define irs32 *((int32_t*) &r4300_regs(r4300)[RS_OF(op)] + 1) #define irt32 *((int32_t*) &r4300_regs(r4300)[RT_OF(op)] + 1) #endif // two functions are defined from the macros above but never used // these prototype declarations will prevent a warning #if defined(__GNUC__) static void JR_IDLE(struct r4300_core*, uint32_t) __attribute__((used)); static void JALR_IDLE(struct r4300_core*, uint32_t) __attribute__((used)); #endif #include "mips_instructions.def" void InterpretOpcode(struct r4300_core* r4300) { uint32_t* op_address = fast_mem_access(r4300, *r4300_pc(r4300)); if (op_address == NULL) return; uint32_t op = *op_address; switch ((op >> 26) & 0x3F) { case 0: /* SPECIAL prefix */ switch (op & 0x3F) { case 0: /* SPECIAL opcode 0: SLL */ if (RD_OF(op) != 0) SLL(r4300, op); else NOP(r4300, 0); break; case 2: /* SPECIAL opcode 2: SRL */ if (RD_OF(op) != 0) SRL(r4300, op); else NOP(r4300, 0); break; case 3: /* SPECIAL opcode 3: SRA */ if (RD_OF(op) != 0) SRA(r4300, op); else NOP(r4300, 0); break; case 4: /* SPECIAL opcode 4: SLLV */ if (RD_OF(op) != 0) SLLV(r4300, op); else NOP(r4300, 0); break; case 6: /* SPECIAL opcode 6: SRLV */ if (RD_OF(op) != 0) SRLV(r4300, op); else NOP(r4300, 0); break; case 7: /* SPECIAL opcode 7: SRAV */ if (RD_OF(op) != 0) SRAV(r4300, op); else NOP(r4300, 0); break; case 8: JR(r4300, op); break; case 9: /* SPECIAL opcode 9: JALR */ /* Note: This can omit the check for Rd == 0 because the JALR * function checks for link_register != &r4300_regs(4300)[0]. If you're * using this as a reference for a JIT, do check Rd == 0 in it. */ JALR(r4300, op); break; case 12: SYSCALL(r4300, op); break; case 13: /* SPECIAL opcode 13: BREAK */ BREAK(r4300, op); break; case 15: SYNC(r4300, op); break; case 16: /* SPECIAL opcode 16: MFHI */ if (RD_OF(op) != 0) MFHI(r4300, op); else NOP(r4300, 0); break; case 17: MTHI(r4300, op); break; case 18: /* SPECIAL opcode 18: MFLO */ if (RD_OF(op) != 0) MFLO(r4300, op); else NOP(r4300, 0); break; case 19: MTLO(r4300, op); break; case 20: /* SPECIAL opcode 20: DSLLV */ if (RD_OF(op) != 0) DSLLV(r4300, op); else NOP(r4300, 0); break; case 22: /* SPECIAL opcode 22: DSRLV */ if (RD_OF(op) != 0) DSRLV(r4300, op); else NOP(r4300, 0); break; case 23: /* SPECIAL opcode 23: DSRAV */ if (RD_OF(op) != 0) DSRAV(r4300, op); else NOP(r4300, 0); break; case 24: MULT(r4300, op); break; case 25: MULTU(r4300, op); break; case 26: DIV(r4300, op); break; case 27: DIVU(r4300, op); break; case 28: DMULT(r4300, op); break; case 29: DMULTU(r4300, op); break; case 30: DDIV(r4300, op); break; case 31: DDIVU(r4300, op); break; case 32: /* SPECIAL opcode 32: ADD */ if (RD_OF(op) != 0) ADD(r4300, op); else NOP(r4300, 0); break; case 33: /* SPECIAL opcode 33: ADDU */ if (RD_OF(op) != 0) ADDU(r4300, op); else NOP(r4300, 0); break; case 34: /* SPECIAL opcode 34: SUB */ if (RD_OF(op) != 0) SUB(r4300, op); else NOP(r4300, 0); break; case 35: /* SPECIAL opcode 35: SUBU */ if (RD_OF(op) != 0) SUBU(r4300, op); else NOP(r4300, 0); break; case 36: /* SPECIAL opcode 36: AND */ if (RD_OF(op) != 0) AND(r4300, op); else NOP(r4300, 0); break; case 37: /* SPECIAL opcode 37: OR */ if (RD_OF(op) != 0) OR(r4300, op); else NOP(r4300, 0); break; case 38: /* SPECIAL opcode 38: XOR */ if (RD_OF(op) != 0) XOR(r4300, op); else NOP(r4300, 0); break; case 39: /* SPECIAL opcode 39: NOR */ if (RD_OF(op) != 0) NOR(r4300, op); else NOP(r4300, 0); break; case 42: /* SPECIAL opcode 42: SLT */ if (RD_OF(op) != 0) SLT(r4300, op); else NOP(r4300, 0); break; case 43: /* SPECIAL opcode 43: SLTU */ if (RD_OF(op) != 0) SLTU(r4300, op); else NOP(r4300, 0); break; case 44: /* SPECIAL opcode 44: DADD */ if (RD_OF(op) != 0) DADD(r4300, op); else NOP(r4300, 0); break; case 45: /* SPECIAL opcode 45: DADDU */ if (RD_OF(op) != 0) DADDU(r4300, op); else NOP(r4300, 0); break; case 46: /* SPECIAL opcode 46: DSUB */ if (RD_OF(op) != 0) DSUB(r4300, op); else NOP(r4300, 0); break; case 47: /* SPECIAL opcode 47: DSUBU */ if (RD_OF(op) != 0) DSUBU(r4300, op); else NOP(r4300, 0); break; case 48: TGE(r4300, op); break; case 49: TGEU(r4300, op); break; case 50: TLT(r4300, op); break; case 51: TLTU(r4300, op); break; case 52: TEQ(r4300, op); break; case 54: TNE(r4300, op); break; case 56: /* SPECIAL opcode 56: DSLL */ if (RD_OF(op) != 0) DSLL(r4300, op); else NOP(r4300, 0); break; case 58: /* SPECIAL opcode 58: DSRL */ if (RD_OF(op) != 0) DSRL(r4300, op); else NOP(r4300, 0); break; case 59: /* SPECIAL opcode 59: DSRA */ if (RD_OF(op) != 0) DSRA(r4300, op); else NOP(r4300, 0); break; case 60: /* SPECIAL opcode 60: DSLL32 */ if (RD_OF(op) != 0) DSLL32(r4300, op); else NOP(r4300, 0); break; case 62: /* SPECIAL opcode 62: DSRL32 */ if (RD_OF(op) != 0) DSRL32(r4300, op); else NOP(r4300, 0); break; case 63: /* SPECIAL opcode 63: DSRA32 */ if (RD_OF(op) != 0) DSRA32(r4300, op); else NOP(r4300, 0); break; default: /* SPECIAL opcodes 1, 5, 10, 11, 14, 21, 40, 41, 53, 55, 57, 61: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch (op & 0x3F) for the SPECIAL prefix */ break; case 1: /* REGIMM prefix */ switch ((op >> 16) & 0x1F) { case 0: /* REGIMM opcode 0: BLTZ */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BLTZ_IDLE(r4300, op); else BLTZ(r4300, op); break; case 1: /* REGIMM opcode 1: BGEZ */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BGEZ_IDLE(r4300, op); else BGEZ(r4300, op); break; case 2: /* REGIMM opcode 2: BLTZL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BLTZL_IDLE(r4300, op); else BLTZL(r4300, op); break; case 3: /* REGIMM opcode 3: BGEZL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BGEZL_IDLE(r4300, op); else BGEZL(r4300, op); break; case 8: TGEI(r4300, op); break; case 9: TGEIU(r4300, op); break; case 10: TLTI(r4300, op); break; case 11: TLTIU(r4300, op); break; case 12: TEQI(r4300, op); break; case 14: TNEI(r4300, op); break; case 16: /* REGIMM opcode 16: BLTZAL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BLTZAL_IDLE(r4300, op); else BLTZAL(r4300, op); break; case 17: /* REGIMM opcode 17: BGEZAL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BGEZAL_IDLE(r4300, op); else BGEZAL(r4300, op); break; case 18: /* REGIMM opcode 18: BLTZALL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BLTZALL_IDLE(r4300, op); else BLTZALL(r4300, op); break; case 19: /* REGIMM opcode 19: BGEZALL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BGEZALL_IDLE(r4300, op); else BGEZALL(r4300, op); break; default: /* REGIMM opcodes 4..7, 13, 15, 20..31: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch ((op >> 16) & 0x1F) for the REGIMM prefix */ break; case 2: /* Major opcode 2: J */ if (IS_ABSOLUTE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) J_IDLE(r4300, op); else J(r4300, op); break; case 3: /* Major opcode 3: JAL */ if (IS_ABSOLUTE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) JAL_IDLE(r4300, op); else JAL(r4300, op); break; case 4: /* Major opcode 4: BEQ */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BEQ_IDLE(r4300, op); else BEQ(r4300, op); break; case 5: /* Major opcode 5: BNE */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BNE_IDLE(r4300, op); else BNE(r4300, op); break; case 6: /* Major opcode 6: BLEZ */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BLEZ_IDLE(r4300, op); else BLEZ(r4300, op); break; case 7: /* Major opcode 7: BGTZ */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BGTZ_IDLE(r4300, op); else BGTZ(r4300, op); break; case 8: /* Major opcode 8: ADDI */ if (RT_OF(op) != 0) ADDI(r4300, op); else NOP(r4300, 0); break; case 9: /* Major opcode 9: ADDIU */ if (RT_OF(op) != 0) ADDIU(r4300, op); else NOP(r4300, 0); break; case 10: /* Major opcode 10: SLTI */ if (RT_OF(op) != 0) SLTI(r4300, op); else NOP(r4300, 0); break; case 11: /* Major opcode 11: SLTIU */ if (RT_OF(op) != 0) SLTIU(r4300, op); else NOP(r4300, 0); break; case 12: /* Major opcode 12: ANDI */ if (RT_OF(op) != 0) ANDI(r4300, op); else NOP(r4300, 0); break; case 13: /* Major opcode 13: ORI */ if (RT_OF(op) != 0) ORI(r4300, op); else NOP(r4300, 0); break; case 14: /* Major opcode 14: XORI */ if (RT_OF(op) != 0) XORI(r4300, op); else NOP(r4300, 0); break; case 15: /* Major opcode 15: LUI */ if (RT_OF(op) != 0) LUI(r4300, op); else NOP(r4300, 0); break; case 16: /* Coprocessor 0 prefix */ switch ((op >> 21) & 0x1F) { case 0: /* Coprocessor 0 opcode 0: MFC0 */ if (RT_OF(op) != 0) MFC0(r4300, op); else NOP(r4300, 0); break; case 1: /* Coprocessor 0 opcode 1: DMFC0 */ if (RT_OF(op) != 0) DMFC0(r4300, op); else NOP(r4300, 0); break; case 4: /* Coprocessor 0 opcode 4: MTC0 */ case 5: /* Coprocessor 0 opcode 5: DMTC0 */ MTC0(r4300, op); break; case 16: /* Coprocessor 0 opcode 16: TLB */ switch (op & 0x3F) { case 1: TLBR(r4300, op); break; case 2: TLBWI(r4300, op); break; case 6: TLBWR(r4300, op); break; case 8: TLBP(r4300, op); break; case 24: ERET(r4300, op); break; default: /* TLB sub-opcodes 0, 3..5, 7, 9..23, 25..63: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch (op & 0x3F) for Coprocessor 0 TLB opcodes */ break; default: /* Coprocessor 0 opcodes 2..3, 5..15, 17..31: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch ((op >> 21) & 0x1F) for the Coprocessor 0 prefix */ break; case 17: /* Coprocessor 1 prefix */ switch ((op >> 21) & 0x1F) { case 0: /* Coprocessor 1 opcode 0: MFC1 */ if (RT_OF(op) != 0) MFC1(r4300, op); else NOP(r4300, 0); break; case 1: /* Coprocessor 1 opcode 1: DMFC1 */ if (RT_OF(op) != 0) DMFC1(r4300, op); else NOP(r4300, 0); break; case 2: /* Coprocessor 1 opcode 2: CFC1 */ if (RT_OF(op) != 0) CFC1(r4300, op); else NOP(r4300, 0); break; case 3: /* Coprocessor 1 opcode 2: DCFC1 */ if (RT_OF(op) != 0) DCFC1(r4300, op); else NOP(r4300, 0); break; case 4: MTC1(r4300, op); break; case 5: DMTC1(r4300, op); break; case 6: CTC1(r4300, op); break; case 7: DCTC1(r4300, op); break; case 8: /* Coprocessor 1 opcode 8: Branch on C1 condition... */ switch ((op >> 16) & 0x3) { case 0: /* opcode 0: BC1F */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BC1F_IDLE(r4300, op); else BC1F(r4300, op); break; case 1: /* opcode 1: BC1T */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BC1T_IDLE(r4300, op); else BC1T(r4300, op); break; case 2: /* opcode 2: BC1FL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BC1FL_IDLE(r4300, op); else BC1FL(r4300, op); break; case 3: /* opcode 3: BC1TL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BC1TL_IDLE(r4300, op); else BC1TL(r4300, op); break; } /* switch ((op >> 16) & 0x3) for branches on C1 condition */ break; case 16: /* Coprocessor 1 S-format opcodes */ switch (op & 0x3F) { case 0: ADD_S(r4300, op); break; case 1: SUB_S(r4300, op); break; case 2: MUL_S(r4300, op); break; case 3: DIV_S(r4300, op); break; case 4: SQRT_S(r4300, op); break; case 5: ABS_S(r4300, op); break; case 6: MOV_S(r4300, op); break; case 7: NEG_S(r4300, op); break; case 8: ROUND_L_S(r4300, op); break; case 9: TRUNC_L_S(r4300, op); break; case 10: CEIL_L_S(r4300, op); break; case 11: FLOOR_L_S(r4300, op); break; case 12: ROUND_W_S(r4300, op); break; case 13: TRUNC_W_S(r4300, op); break; case 14: CEIL_W_S(r4300, op); break; case 15: FLOOR_W_S(r4300, op); break; case 33: CVT_D_S(r4300, op); break; case 36: CVT_W_S(r4300, op); break; case 37: CVT_L_S(r4300, op); break; case 48: C_F_S(r4300, op); break; case 49: C_UN_S(r4300, op); break; case 50: C_EQ_S(r4300, op); break; case 51: C_UEQ_S(r4300, op); break; case 52: C_OLT_S(r4300, op); break; case 53: C_ULT_S(r4300, op); break; case 54: C_OLE_S(r4300, op); break; case 55: C_ULE_S(r4300, op); break; case 56: C_SF_S(r4300, op); break; case 57: C_NGLE_S(r4300, op); break; case 58: C_SEQ_S(r4300, op); break; case 59: C_NGL_S(r4300, op); break; case 60: C_LT_S(r4300, op); break; case 61: C_NGE_S(r4300, op); break; case 62: C_LE_S(r4300, op); break; case 63: C_NGT_S(r4300, op); break; default: /* Coprocessor 1 S-format opcodes 16..32, 34..35, 38..47: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch (op & 0x3F) for Coprocessor 1 S-format opcodes */ break; case 17: /* Coprocessor 1 D-format opcodes */ switch (op & 0x3F) { case 0: ADD_D(r4300, op); break; case 1: SUB_D(r4300, op); break; case 2: MUL_D(r4300, op); break; case 3: DIV_D(r4300, op); break; case 4: SQRT_D(r4300, op); break; case 5: ABS_D(r4300, op); break; case 6: MOV_D(r4300, op); break; case 7: NEG_D(r4300, op); break; case 8: ROUND_L_D(r4300, op); break; case 9: TRUNC_L_D(r4300, op); break; case 10: CEIL_L_D(r4300, op); break; case 11: FLOOR_L_D(r4300, op); break; case 12: ROUND_W_D(r4300, op); break; case 13: TRUNC_W_D(r4300, op); break; case 14: CEIL_W_D(r4300, op); break; case 15: FLOOR_W_D(r4300, op); break; case 32: CVT_S_D(r4300, op); break; case 36: CVT_W_D(r4300, op); break; case 37: CVT_L_D(r4300, op); break; case 48: C_F_D(r4300, op); break; case 49: C_UN_D(r4300, op); break; case 50: C_EQ_D(r4300, op); break; case 51: C_UEQ_D(r4300, op); break; case 52: C_OLT_D(r4300, op); break; case 53: C_ULT_D(r4300, op); break; case 54: C_OLE_D(r4300, op); break; case 55: C_ULE_D(r4300, op); break; case 56: C_SF_D(r4300, op); break; case 57: C_NGLE_D(r4300, op); break; case 58: C_SEQ_D(r4300, op); break; case 59: C_NGL_D(r4300, op); break; case 60: C_LT_D(r4300, op); break; case 61: C_NGE_D(r4300, op); break; case 62: C_LE_D(r4300, op); break; case 63: C_NGT_D(r4300, op); break; default: /* Coprocessor 1 D-format opcodes 16..31, 33..35, 38..47: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch (op & 0x3F) for Coprocessor 1 D-format opcodes */ break; case 20: /* Coprocessor 1 W-format opcodes */ switch (op & 0x3F) { case 32: CVT_S_W(r4300, op); break; case 33: CVT_D_W(r4300, op); break; default: /* Coprocessor 1 W-format opcodes 0..31, 34..63: Reserved Instructions */ RESERVED(r4300, op); break; } break; case 21: /* Coprocessor 1 L-format opcodes */ switch (op & 0x3F) { case 32: CVT_S_L(r4300, op); break; case 33: CVT_D_L(r4300, op); break; default: /* Coprocessor 1 L-format opcodes 0..31, 34..63: Reserved Instructions */ RESERVED(r4300, op); break; } break; default: /* Coprocessor 1 opcodes 9..15, 18..19, 22..31: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch ((op >> 21) & 0x1F) for the Coprocessor 1 prefix */ break; case 18: /* Coprocessor 2 prefix */ switch ((op >> 21) & 0x1F) { case 0: /* Coprocessor 2 opcode 0: MFC2 */ if (RT_OF(op) != 0) MFC2(r4300, op); else NOP(r4300, 0); break; case 1: /* Coprocessor 2 opcode 1: DMFC2 */ if (RT_OF(op) != 0) DMFC2(r4300, op); else NOP(r4300, 0); break; case 2: /* Coprocessor 2 opcode 2: CFC2 */ if (RT_OF(op) != 0) CFC2(r4300, op); else NOP(r4300, 0); break; case 4: MTC2(r4300, op); break; case 5: DMTC2(r4300, op); break; case 6: CTC2(r4300, op); break; default: RESERVED_COP2(r4300, op); break; } break; case 20: /* Major opcode 20: BEQL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BEQL_IDLE(r4300, op); else BEQL(r4300, op); break; case 21: /* Major opcode 21: BNEL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BNEL_IDLE(r4300, op); else BNEL(r4300, op); break; case 22: /* Major opcode 22: BLEZL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BLEZL_IDLE(r4300, op); else BLEZL(r4300, op); break; case 23: /* Major opcode 23: BGTZL */ if (IS_RELATIVE_IDLE_LOOP(r4300, op, *r4300_pc(r4300))) BGTZL_IDLE(r4300, op); else BGTZL(r4300, op); break; case 24: /* Major opcode 24: DADDI */ if (RT_OF(op) != 0) DADDI(r4300, op); else NOP(r4300, 0); break; case 25: /* Major opcode 25: DADDIU */ if (RT_OF(op) != 0) DADDIU(r4300, op); else NOP(r4300, 0); break; case 26: /* Major opcode 26: LDL */ if (RT_OF(op) != 0) LDL(r4300, op); else NOP(r4300, 0); break; case 27: /* Major opcode 27: LDR */ if (RT_OF(op) != 0) LDR(r4300, op); else NOP(r4300, 0); break; case 32: /* Major opcode 32: LB */ if (RT_OF(op) != 0) LB(r4300, op); else NOP(r4300, 0); break; case 33: /* Major opcode 33: LH */ if (RT_OF(op) != 0) LH(r4300, op); else NOP(r4300, 0); break; case 34: /* Major opcode 34: LWL */ if (RT_OF(op) != 0) LWL(r4300, op); else NOP(r4300, 0); break; case 35: /* Major opcode 35: LW */ if (RT_OF(op) != 0) LW(r4300, op); else NOP(r4300, 0); break; case 36: /* Major opcode 36: LBU */ if (RT_OF(op) != 0) LBU(r4300, op); else NOP(r4300, 0); break; case 37: /* Major opcode 37: LHU */ if (RT_OF(op) != 0) LHU(r4300, op); else NOP(r4300, 0); break; case 38: /* Major opcode 38: LWR */ if (RT_OF(op) != 0) LWR(r4300, op); else NOP(r4300, 0); break; case 39: /* Major opcode 39: LWU */ if (RT_OF(op) != 0) LWU(r4300, op); else NOP(r4300, 0); break; case 40: SB(r4300, op); break; case 41: SH(r4300, op); break; case 42: SWL(r4300, op); break; case 43: SW(r4300, op); break; case 44: SDL(r4300, op); break; case 45: SDR(r4300, op); break; case 46: SWR(r4300, op); break; case 47: CACHE(r4300, op); break; case 48: /* Major opcode 48: LL */ if (RT_OF(op) != 0) LL(r4300, op); else NOP(r4300, 0); break; case 49: LWC1(r4300, op); break; case 52: /* Major opcode 52: LLD (Not implemented) */ NI(r4300, op); break; case 53: LDC1(r4300, op); break; case 55: /* Major opcode 55: LD */ if (RT_OF(op) != 0) LD(r4300, op); else NOP(r4300, 0); break; case 56: /* Major opcode 56: SC */ if (RT_OF(op) != 0) SC(r4300, op); else NOP(r4300, 0); break; case 57: SWC1(r4300, op); break; case 60: /* Major opcode 60: SCD (Not implemented) */ NI(r4300, op); break; case 61: SDC1(r4300, op); break; case 63: SD(r4300, op); break; default: /* Major opcodes 18..19, 28..31, 50..51, 54, 58..59, 62: Reserved Instructions */ RESERVED(r4300, op); break; } /* switch ((op >> 26) & 0x3F) */ } void run_pure_interpreter(struct r4300_core* r4300) { *r4300_stop(r4300) = 0; *r4300_pc_struct(r4300) = &r4300->interp_PC; *r4300_pc(r4300) = r4300->cp0.last_addr = r4300->start_address; while (!*r4300_stop(r4300)) { #ifdef COMPARE_CORE CoreCompareCallback(); #endif #ifdef DBG if (g_DebuggerActive) update_debugger(*r4300_pc(r4300)); #endif InterpretOpcode(r4300); } } mupen64plus-core-src-2.6.0/src/device/r4300/pure_interp.h000066400000000000000000000033161464506436200227540ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - pure_interp.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_PURE_INTERP_H #define M64P_DEVICE_R4300_PURE_INTERP_H struct r4300_core; void run_pure_interpreter(struct r4300_core* r4300); #endif /* M64P_DEVICE_R4300_PURE_INTERP_H */ mupen64plus-core-src-2.6.0/src/device/r4300/r4300_core.c000066400000000000000000000327121464506436200221750ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - r4300_core.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "r4300_core.h" #include "cached_interp.h" #if defined(COUNT_INSTR) #include "instr_counters.h" #endif #include "new_dynarec/new_dynarec.h" #include "pure_interp.h" #include "recomp.h" #include "api/callbacks.h" #include "api/debugger.h" #include "api/m64p_types.h" #ifdef DBG #include "debugger/dbg_debugger.h" #endif #include "main/main.h" #include #include #include void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers, unsigned int emumode, unsigned int count_per_op, unsigned int count_per_op_denom_pot, int no_compiled_jump, int randomize_interrupt, uint32_t start_address) { struct new_dynarec_hot_state* new_dynarec_hot_state = #ifdef NEW_DYNAREC &r4300->new_dynarec_hot_state; #else NULL; #endif r4300->emumode = emumode; init_cp0(&r4300->cp0, count_per_op, count_per_op_denom_pot, new_dynarec_hot_state, interrupt_handlers); init_cp1(&r4300->cp1, new_dynarec_hot_state); init_cp2(&r4300->cp2, new_dynarec_hot_state); #ifndef NEW_DYNAREC r4300->recomp.no_compiled_jump = no_compiled_jump; #endif r4300->mem = mem; r4300->mi = mi; r4300->rdram = rdram; r4300->randomize_interrupt = randomize_interrupt; r4300->start_address = start_address; srand((unsigned int) time(NULL)); } void poweron_r4300(struct r4300_core* r4300) { /* clear registers */ memset(r4300_regs(r4300), 0, 32*sizeof(int64_t)); *r4300_mult_hi(r4300) = 0; *r4300_mult_lo(r4300) = 0; r4300->llbit = 0; *r4300_pc_struct(r4300) = NULL; r4300->delay_slot = 0; r4300->skip_jump = 0; r4300->reset_hard_job = 0; /* recomp init */ #ifndef NEW_DYNAREC r4300->recomp.delay_slot_compiled = 0; r4300->recomp.fast_memory = 1; r4300->recomp.local_rs = 0; r4300->recomp.dyna_interp = 0; r4300->recomp.jumps_table = NULL; r4300->recomp.jumps_number = 0; r4300->recomp.max_jumps_number = 0; r4300->recomp.jump_start8 = 0; r4300->recomp.jump_start32 = 0; #if defined(__x86_64__) r4300->recomp.riprel_table = NULL; r4300->recomp.riprel_number = 0; r4300->recomp.max_riprel_number = 0; #endif #if defined(__x86_64__) r4300->recomp.save_rsp = 0; r4300->recomp.save_rip = 0; #else r4300->recomp.save_ebp = 0; r4300->recomp.save_ebx = 0; r4300->recomp.save_esi = 0; r4300->recomp.save_edi = 0; r4300->recomp.save_esp = 0; r4300->recomp.save_eip = 0; #endif r4300->recomp.branch_taken = 0; #endif /* !NEW_DYNAREC */ /* setup CP0 registers */ poweron_cp0(&r4300->cp0); /* setup CP1 registers */ poweron_cp1(&r4300->cp1); /* setup CP2 registers */ poweron_cp2(&r4300->cp2); } void run_r4300(struct r4300_core* r4300) { #ifdef OSAL_SSE //Save FTZ/DAZ mode unsigned int daz = _MM_GET_DENORMALS_ZERO_MODE(); unsigned int ftz = _MM_GET_FLUSH_ZERO_MODE(); _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF); #endif *r4300_stop(r4300) = 0; g_rom_pause = 0; /* clear instruction counters */ #if defined(COUNT_INSTR) memset(instr_count, 0, 131*sizeof(instr_count[0])); #endif if (r4300->emumode == EMUMODE_PURE_INTERPRETER) { DebugMessage(M64MSG_INFO, "Starting R4300 emulator: Pure Interpreter"); r4300->emumode = EMUMODE_PURE_INTERPRETER; run_pure_interpreter(r4300); } #if defined(DYNAREC) else if (r4300->emumode >= 2) { DebugMessage(M64MSG_INFO, "Starting R4300 emulator: Dynamic Recompiler"); r4300->emumode = EMUMODE_DYNAREC; init_blocks(&r4300->cached_interp); #ifdef NEW_DYNAREC new_dynarec_init(); new_dyna_start(); new_dynarec_cleanup(); #else r4300->cached_interp.fin_block = dynarec_fin_block; r4300->cached_interp.not_compiled = dynarec_notcompiled; r4300->cached_interp.not_compiled2 = dynarec_notcompiled2; r4300->cached_interp.init_block = dynarec_init_block; r4300->cached_interp.free_block = dynarec_free_block; r4300->cached_interp.recompile_block = dynarec_recompile_block; dyna_start(dynarec_setup_code); (*r4300_pc_struct(r4300))++; #if defined(PROFILE_R4300) profile_write_end_of_code_blocks(r4300); #endif #endif free_blocks(&r4300->cached_interp); } #endif else /* if (r4300->emumode == EMUMODE_INTERPRETER) */ { DebugMessage(M64MSG_INFO, "Starting R4300 emulator: Cached Interpreter"); r4300->emumode = EMUMODE_INTERPRETER; r4300->cached_interp.fin_block = cached_interp_FIN_BLOCK; r4300->cached_interp.not_compiled = cached_interp_NOTCOMPILED; r4300->cached_interp.not_compiled2 = cached_interp_NOTCOMPILED2; r4300->cached_interp.init_block = cached_interp_init_block; r4300->cached_interp.free_block = cached_interp_free_block; r4300->cached_interp.recompile_block = cached_interp_recompile_block; init_blocks(&r4300->cached_interp); cached_interpreter_jump_to(r4300, r4300->start_address); /* Prevent segfault on failed cached_interpreter_jump_to */ if (!r4300->cached_interp.actual->block) { return; } r4300->cp0.last_addr = *r4300_pc(r4300); run_cached_interpreter(r4300); free_blocks(&r4300->cached_interp); } DebugMessage(M64MSG_INFO, "R4300 emulator finished."); /* print instruction counts */ #if defined(COUNT_INSTR) if (r4300->emumode == EMUMODE_DYNAREC) instr_counters_print(); #endif #ifdef OSAL_SSE //Restore FTZ/DAZ mode _MM_SET_DENORMALS_ZERO_MODE(daz); _MM_SET_FLUSH_ZERO_MODE(ftz); #endif } int64_t* r4300_regs(struct r4300_core* r4300) { #ifndef NEW_DYNAREC return r4300->regs; #else return r4300->new_dynarec_hot_state.regs; #endif } int64_t* r4300_mult_hi(struct r4300_core* r4300) { #ifndef NEW_DYNAREC return &r4300->hi; #else return &r4300->new_dynarec_hot_state.hi; #endif } int64_t* r4300_mult_lo(struct r4300_core* r4300) { #ifndef NEW_DYNAREC return &r4300->lo; #else return &r4300->new_dynarec_hot_state.lo; #endif } unsigned int* r4300_llbit(struct r4300_core* r4300) { return &r4300->llbit; } uint32_t* r4300_pc(struct r4300_core* r4300) { #ifdef NEW_DYNAREC return (r4300->emumode == EMUMODE_DYNAREC) ? (uint32_t*)&r4300->new_dynarec_hot_state.pcaddr : &(*r4300_pc_struct(r4300))->addr; #else return &(*r4300_pc_struct(r4300))->addr; #endif } struct precomp_instr** r4300_pc_struct(struct r4300_core* r4300) { #ifndef NEW_DYNAREC return &r4300->pc; #else return &r4300->new_dynarec_hot_state.pc; #endif } int* r4300_stop(struct r4300_core* r4300) { #ifndef NEW_DYNAREC return &r4300->stop; #else return &r4300->new_dynarec_hot_state.stop; #endif } unsigned int get_r4300_emumode(struct r4300_core* r4300) { return r4300->emumode; } uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address) { /* This code is performance critical, specially on pure interpreter mode. * Removing error checking saves some time, but the emulator may crash. */ if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) { address = virtual_to_physical_address(r4300, address, 2); if (address == 0) // TLB exception return NULL; } address &= UINT32_C(0x1ffffffc); return mem_base_u32(r4300->mem->base, address); } /* Read aligned word from memory. * address may not be word-aligned for byte or hword accesses. * Alignment is taken care of when calling mem handler. */ int r4300_read_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t* value) { if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) { address = virtual_to_physical_address(r4300, address, 0); if (address == 0) { return 0; } } address &= UINT32_C(0x1ffffffc); mem_read32(mem_get_handler(r4300->mem, address), address & ~UINT32_C(3), value); return 1; } /* Read aligned dword from memory */ int r4300_read_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t* value) { uint32_t w[2]; /* XXX: unaligned dword accesses should trigger a address error, * but inaccurate timing of the core can lead to unaligned address on reset * so just emit a warning and keep going */ if ((address & 0x7) != 0) { DebugMessage(M64MSG_WARNING, "Unaligned dword read %08x", address); } if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) { address = virtual_to_physical_address(r4300, address, 0); if (address == 0) { return 0; } } address &= UINT32_C(0x1ffffffc); const struct mem_handler* handler = mem_get_handler(r4300->mem, address); mem_read32(handler, address + 0, &w[0]); mem_read32(handler, address + 4, &w[1]); *value = ((uint64_t)w[0] << 32) | w[1]; return 1; } /* Write aligned word to memory. * address may not be word-aligned for byte or hword accesses. * Alignment is taken care of when calling mem handler. */ int r4300_write_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t mask) { if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) { invalidate_r4300_cached_code(r4300, address, 4); address = virtual_to_physical_address(r4300, address, 1); if (address == 0) { return 0; } } invalidate_r4300_cached_code(r4300, address, 4); invalidate_r4300_cached_code(r4300, address ^ UINT32_C(0x20000000), 4); address &= UINT32_C(0x1ffffffc); mem_write32(mem_get_handler(r4300->mem, address), address & ~UINT32_C(3), value, mask); return 1; } /* Write aligned dword to memory */ int r4300_write_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t value, uint64_t mask) { /* XXX: unaligned dword accesses should trigger a address error, * but inaccurate timing of the core can lead to unaligned address on reset * so just emit a warning and keep going */ if ((address & 0x7) != 0) { DebugMessage(M64MSG_WARNING, "Unaligned dword write %08x", address); } if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) { invalidate_r4300_cached_code(r4300, address, 8); address = virtual_to_physical_address(r4300, address, 1); if (address == 0) { return 0; } } invalidate_r4300_cached_code(r4300, address, 8); invalidate_r4300_cached_code(r4300, address ^ UINT32_C(0x20000000), 8); address &= UINT32_C(0x1ffffffc); const struct mem_handler* handler = mem_get_handler(r4300->mem, address); mem_write32(handler, address + 0, value >> 32, mask >> 32); mem_write32(handler, address + 4, (uint32_t) value, (uint32_t) mask ); return 1; } void invalidate_r4300_cached_code(struct r4300_core* r4300, uint32_t address, size_t size) { if (r4300->emumode != EMUMODE_PURE_INTERPRETER) { #ifdef NEW_DYNAREC if (r4300->emumode == EMUMODE_DYNAREC) { invalidate_cached_code_new_dynarec(r4300, address, size); } else #endif { invalidate_cached_code_hacktarux(r4300, address, size); } } } void generic_jump_to(struct r4300_core* r4300, uint32_t address) { switch(r4300->emumode) { case EMUMODE_PURE_INTERPRETER: *r4300_pc(r4300) = address; break; case EMUMODE_INTERPRETER: cached_interpreter_jump_to(r4300, address); break; #ifndef NO_ASM case EMUMODE_DYNAREC: #ifdef NEW_DYNAREC r4300->new_dynarec_hot_state.pcaddr = address; r4300->new_dynarec_hot_state.pending_exception = 1; #else dynarec_jump_to(r4300, address); #endif break; #endif default: /* should not happen */ break; } } /* XXX: not really a good interface but it gets the job done... */ void savestates_load_set_pc(struct r4300_core* r4300, uint32_t pc) { generic_jump_to(r4300, pc); invalidate_r4300_cached_code(r4300, 0, 0); } mupen64plus-core-src-2.6.0/src/device/r4300/r4300_core.h000066400000000000000000000207361464506436200222050ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - r4300_core.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_R4300_CORE_H #define M64P_DEVICE_R4300_R4300_CORE_H #include #include #if defined(PROFILE_R4300) #include #endif #include "cp0.h" #include "cp1.h" #include "cp2.h" #include "recomp_types.h" /* for precomp_instr, regcache_state */ #include "new_dynarec/new_dynarec.h" #include "osal/preproc.h" struct memory; struct mi_controller; struct rdram; struct jump_table; struct cached_interp { char invalid_code[0x100000]; struct precomp_block* blocks[0x100000]; struct precomp_block* actual; void (*fin_block)(void); void (*not_compiled)(void); void (*not_compiled2)(void); void (*init_block)(struct r4300_core* r4300, uint32_t address); void (*free_block)(struct precomp_block* block); void (*recompile_block)(struct r4300_core* r4300, const uint32_t* source, struct precomp_block* block, uint32_t func); }; enum { EMUMODE_PURE_INTERPRETER = 0, EMUMODE_INTERPRETER = 1, EMUMODE_DYNAREC = 2, }; struct r4300_core { #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ int64_t regs[32]; int64_t hi; int64_t lo; #endif unsigned int llbit; struct precomp_instr* pc; unsigned int delay_slot; uint32_t skip_jump; #ifndef NEW_DYNAREC /* New dynarec uses a different memory layout */ int stop; #endif /* When reset_hard_job is set, next interrupt will cause hard reset */ int reset_hard_job; /* from pure_interp.c */ struct precomp_instr interp_PC; /* from cached_interp.c. * XXX: more work is needed to correctly encapsulate these */ struct cached_interp cached_interp; #ifndef NEW_DYNAREC /* from recomp.c. * XXX: more work is needed to correctly encapsulate these */ struct recomp { int init_length; int code_length; /* current real recompiled code length */ struct precomp_block *dst_block; /* the current block that we are recompiling */ struct precomp_instr* dst; /* destination structure for the recompiled instruction */ const uint32_t *SRC; /* currently recompiled instruction in the input stream */ uint32_t src; /* the current recompiled instruction */ int delay_slot_compiled; struct regcache_state regcache_state; struct jump_table* jumps_table; size_t jumps_number; size_t max_jumps_number; unsigned int jump_start8; unsigned int jump_start32; #if defined(__x86_64__) struct riprelative_table* riprel_table; size_t riprel_number; size_t max_riprel_number; #endif #if defined(__x86_64__) long long save_rsp; long long save_rip; /* that's where the dynarec will restart when going back from a C function */ unsigned long long* return_address; #else long save_ebp; long save_ebx; long save_esi; long save_edi; long save_esp; long save_eip; /* that's where the dynarec will restart when going back from a C function */ unsigned long* return_address; #endif int branch_taken; struct precomp_instr fake_instr; #ifdef COMPARE_CORE #if defined(__x86_64__) long long debug_reg_storage[8]; #else int eax, ebx, ecx, edx, esp, ebp, esi, edi; #endif #endif unsigned char **inst_pointer; /* output buffer for recompiled code */ int max_code_length; /* current recompiled code's buffer length */ int fast_memory; int no_compiled_jump; /* use cached interpreter instead of recompiler for jumps */ uint32_t jump_to_address; int64_t local_rs; unsigned int dyna_interp; #if defined(__x86_64__) unsigned long long shift; #else unsigned int shift; #endif #if defined(PROFILE_R4300) FILE* pfProfile; #endif /* Memory accesses variables */ uint64_t* rdword; uint32_t wmask; uint32_t address; uint32_t wword; uint64_t wdword; } recomp; #else /* FIXME: better put that near linkage_arm code * to help generate call beyond the +/-32MB range. */ ALIGN(4096, char extra_memory[33554432]); struct new_dynarec_hot_state new_dynarec_hot_state; #endif /* NEW_DYNAREC */ unsigned int emumode; struct cp0 cp0; struct cp1 cp1; struct cp2 cp2; struct memory* mem; struct mi_controller* mi; struct rdram* rdram; uint32_t randomize_interrupt; uint32_t start_address; }; #define R4300_KSEG0 UINT32_C(0x80000000) #define R4300_KSEG1 UINT32_C(0xa0000000) #ifndef NEW_DYNAREC #define R4300_REGS_OFFSET \ offsetof(struct r4300_core, regs) #else #define R4300_REGS_OFFSET (\ offsetof(struct r4300_core, new_dynarec_hot_state) + \ offsetof(struct new_dynarec_hot_state, regs)) #endif void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers, unsigned int emumode, unsigned int count_per_op, unsigned int count_per_op_denom_pot, int no_compiled_jump, int randomize_interrupt, uint32_t start_address); void poweron_r4300(struct r4300_core* r4300); void run_r4300(struct r4300_core* r4300); int64_t* r4300_regs(struct r4300_core* r4300); int64_t* r4300_mult_hi(struct r4300_core* r4300); int64_t* r4300_mult_lo(struct r4300_core* r4300); unsigned int* r4300_llbit(struct r4300_core* r4300); uint32_t* r4300_pc(struct r4300_core* r4300); struct precomp_instr** r4300_pc_struct(struct r4300_core* r4300); int* r4300_stop(struct r4300_core* r4300); unsigned int get_r4300_emumode(struct r4300_core* r4300); /* Returns a pointer to a block of contiguous memory * Can access RDRAM, SP_DMEM, SP_IMEM and ROM, using TLB if necessary * Useful for getting fast access to a zone with executable code. */ uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address); int r4300_read_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t* value); int r4300_read_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t* value); int r4300_write_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t mask); int r4300_write_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t value, uint64_t mask); /* Allow cached/dynarec r4300 implementations to invalidate * their cached code at [address, address+size] * * If size == 0, r4300 implementation should invalidate * all cached code. */ void invalidate_r4300_cached_code(struct r4300_core* r4300, uint32_t address, size_t size); /* Jump to the given address. This works for all r4300 emulator, but is slower. * Use this for common code which can be executed from any r4300 emulator. */ void generic_jump_to(struct r4300_core* r4300, unsigned int address); void savestates_load_set_pc(struct r4300_core* r4300, uint32_t pc); #endif mupen64plus-core-src-2.6.0/src/device/r4300/recomp.c000066400000000000000000001076341464506436200217100ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - recomp.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "recomp.h" #include #include #include #define __STDC_FORMAT_MACROS #include #if defined(__GNUC__) #include #ifndef __MINGW32__ #include #endif #endif #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/r4300/cached_interp.h" #include "device/r4300/cp0.h" #include "device/r4300/idec.h" #include "device/r4300/recomp_types.h" #include "device/r4300/tlb.h" #include "main/main.h" #if defined(PROFILE) #include "main/profile.h" #endif #if defined(__x86_64__) #include "x86_64/regcache.h" #else #include "x86/regcache.h" #endif static void *malloc_exec(size_t size); static void free_exec(void *ptr, size_t length); /* defined in /assemble.c */ void init_assembler(struct r4300_core* r4300, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number); void free_assembler(struct r4300_core* r4300, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number); void passe2(struct r4300_core* r4300, struct precomp_instr *dest, int start, int end, struct precomp_block* block); /* defined in /dynarec.c */ void genlink_subblock(struct r4300_core* r4300); void genni(struct r4300_core* r4300); void gennotcompiled(struct r4300_core* r4300); void genfin_block(struct r4300_core* r4300); #ifdef COMPARE_CORE void gendebug(struct r4300_core* r4300); #endif void gen_RESERVED(struct r4300_core* r4300); void gen_ADD(struct r4300_core* r4300); void gen_ADDI(struct r4300_core* r4300); void gen_ADDIU(struct r4300_core* r4300); void gen_ADDU(struct r4300_core* r4300); void gen_AND(struct r4300_core* r4300); void gen_ANDI(struct r4300_core* r4300); void gen_BC1F(struct r4300_core* r4300); void gen_BC1F_IDLE(struct r4300_core* r4300); void gen_BC1F_OUT(struct r4300_core* r4300); void gen_BC1FL(struct r4300_core* r4300); void gen_BC1FL_IDLE(struct r4300_core* r4300); void gen_BC1FL_OUT(struct r4300_core* r4300); void gen_BC1T(struct r4300_core* r4300); void gen_BC1T_IDLE(struct r4300_core* r4300); void gen_BC1T_OUT(struct r4300_core* r4300); void gen_BC1TL(struct r4300_core* r4300); void gen_BC1TL_IDLE(struct r4300_core* r4300); void gen_BC1TL_OUT(struct r4300_core* r4300); void gen_BEQ(struct r4300_core* r4300); void gen_BEQ_IDLE(struct r4300_core* r4300); void gen_BEQ_OUT(struct r4300_core* r4300); void gen_BEQL(struct r4300_core* r4300); void gen_BEQL_IDLE(struct r4300_core* r4300); void gen_BEQL_OUT(struct r4300_core* r4300); void gen_BGEZ(struct r4300_core* r4300); void gen_BGEZ_IDLE(struct r4300_core* r4300); void gen_BGEZ_OUT(struct r4300_core* r4300); void gen_BGEZAL(struct r4300_core* r4300); void gen_BGEZAL_IDLE(struct r4300_core* r4300); void gen_BGEZAL_OUT(struct r4300_core* r4300); void gen_BGEZALL(struct r4300_core* r4300); void gen_BGEZALL_IDLE(struct r4300_core* r4300); void gen_BGEZALL_OUT(struct r4300_core* r4300); void gen_BGEZL(struct r4300_core* r4300); void gen_BGEZL_IDLE(struct r4300_core* r4300); void gen_BGEZL_OUT(struct r4300_core* r4300); void gen_BGTZ(struct r4300_core* r4300); void gen_BGTZ_IDLE(struct r4300_core* r4300); void gen_BGTZ_OUT(struct r4300_core* r4300); void gen_BGTZL(struct r4300_core* r4300); void gen_BGTZL_IDLE(struct r4300_core* r4300); void gen_BGTZL_OUT(struct r4300_core* r4300); void gen_BLEZ(struct r4300_core* r4300); void gen_BLEZ_IDLE(struct r4300_core* r4300); void gen_BLEZ_OUT(struct r4300_core* r4300); void gen_BLEZL(struct r4300_core* r4300); void gen_BLEZL_IDLE(struct r4300_core* r4300); void gen_BLEZL_OUT(struct r4300_core* r4300); void gen_BLTZAL(struct r4300_core* r4300); void gen_BLTZAL_IDLE(struct r4300_core* r4300); void gen_BLTZAL_OUT(struct r4300_core* r4300); void gen_BLTZALL(struct r4300_core* r4300); void gen_BLTZALL_IDLE(struct r4300_core* r4300); void gen_BLTZALL_OUT(struct r4300_core* r4300); void gen_BLTZ(struct r4300_core* r4300); void gen_BLTZ_IDLE(struct r4300_core* r4300); void gen_BLTZ_OUT(struct r4300_core* r4300); void gen_BLTZL(struct r4300_core* r4300); void gen_BLTZL_IDLE(struct r4300_core* r4300); void gen_BLTZL_OUT(struct r4300_core* r4300); void gen_BNE(struct r4300_core* r4300); void gen_BNE_IDLE(struct r4300_core* r4300); void gen_BNE_OUT(struct r4300_core* r4300); void gen_BNEL(struct r4300_core* r4300); void gen_BNEL_IDLE(struct r4300_core* r4300); void gen_BNEL_OUT(struct r4300_core* r4300); void gen_CACHE(struct r4300_core* r4300); void gen_CFC1(struct r4300_core* r4300); void gen_CP1_ABS_D(struct r4300_core* r4300); void gen_CP1_ABS_S(struct r4300_core* r4300); void gen_CP1_ADD_D(struct r4300_core* r4300); void gen_CP1_ADD_S(struct r4300_core* r4300); void gen_CP1_CEIL_L_D(struct r4300_core* r4300); void gen_CP1_CEIL_L_S(struct r4300_core* r4300); void gen_CP1_CEIL_W_D(struct r4300_core* r4300); void gen_CP1_CEIL_W_S(struct r4300_core* r4300); void gen_CP1_C_EQ_D(struct r4300_core* r4300); void gen_CP1_C_EQ_S(struct r4300_core* r4300); void gen_CP1_C_F_D(struct r4300_core* r4300); void gen_CP1_C_F_S(struct r4300_core* r4300); void gen_CP1_C_LE_D(struct r4300_core* r4300); void gen_CP1_C_LE_S(struct r4300_core* r4300); void gen_CP1_C_LT_D(struct r4300_core* r4300); void gen_CP1_C_LT_S(struct r4300_core* r4300); void gen_CP1_C_NGE_D(struct r4300_core* r4300); void gen_CP1_C_NGE_S(struct r4300_core* r4300); void gen_CP1_C_NGL_D(struct r4300_core* r4300); void gen_CP1_C_NGLE_D(struct r4300_core* r4300); void gen_CP1_C_NGLE_S(struct r4300_core* r4300); void gen_CP1_C_NGL_S(struct r4300_core* r4300); void gen_CP1_C_NGT_D(struct r4300_core* r4300); void gen_CP1_C_NGT_S(struct r4300_core* r4300); void gen_CP1_C_OLE_D(struct r4300_core* r4300); void gen_CP1_C_OLE_S(struct r4300_core* r4300); void gen_CP1_C_OLT_D(struct r4300_core* r4300); void gen_CP1_C_OLT_S(struct r4300_core* r4300); void gen_CP1_C_SEQ_D(struct r4300_core* r4300); void gen_CP1_C_SEQ_S(struct r4300_core* r4300); void gen_CP1_C_SF_D(struct r4300_core* r4300); void gen_CP1_C_SF_S(struct r4300_core* r4300); void gen_CP1_C_UEQ_D(struct r4300_core* r4300); void gen_CP1_C_UEQ_S(struct r4300_core* r4300); void gen_CP1_C_ULE_D(struct r4300_core* r4300); void gen_CP1_C_ULE_S(struct r4300_core* r4300); void gen_CP1_C_ULT_D(struct r4300_core* r4300); void gen_CP1_C_ULT_S(struct r4300_core* r4300); void gen_CP1_C_UN_D(struct r4300_core* r4300); void gen_CP1_C_UN_S(struct r4300_core* r4300); void gen_CP1_CVT_D_L(struct r4300_core* r4300); void gen_CP1_CVT_D_S(struct r4300_core* r4300); void gen_CP1_CVT_D_W(struct r4300_core* r4300); void gen_CP1_CVT_L_D(struct r4300_core* r4300); void gen_CP1_CVT_L_S(struct r4300_core* r4300); void gen_CP1_CVT_S_D(struct r4300_core* r4300); void gen_CP1_CVT_S_L(struct r4300_core* r4300); void gen_CP1_CVT_S_W(struct r4300_core* r4300); void gen_CP1_CVT_W_D(struct r4300_core* r4300); void gen_CP1_CVT_W_S(struct r4300_core* r4300); void gen_CP1_DIV_D(struct r4300_core* r4300); void gen_CP1_DIV_S(struct r4300_core* r4300); void gen_CP1_FLOOR_L_D(struct r4300_core* r4300); void gen_CP1_FLOOR_L_S(struct r4300_core* r4300); void gen_CP1_FLOOR_W_D(struct r4300_core* r4300); void gen_CP1_FLOOR_W_S(struct r4300_core* r4300); void gen_CP1_MOV_D(struct r4300_core* r4300); void gen_CP1_MOV_S(struct r4300_core* r4300); void gen_CP1_MUL_D(struct r4300_core* r4300); void gen_CP1_MUL_S(struct r4300_core* r4300); void gen_CP1_NEG_D(struct r4300_core* r4300); void gen_CP1_NEG_S(struct r4300_core* r4300); void gen_CP1_ROUND_L_D(struct r4300_core* r4300); void gen_CP1_ROUND_L_S(struct r4300_core* r4300); void gen_CP1_ROUND_W_D(struct r4300_core* r4300); void gen_CP1_ROUND_W_S(struct r4300_core* r4300); void gen_CP1_SQRT_D(struct r4300_core* r4300); void gen_CP1_SQRT_S(struct r4300_core* r4300); void gen_CP1_SUB_D(struct r4300_core* r4300); void gen_CP1_SUB_S(struct r4300_core* r4300); void gen_CP1_TRUNC_L_D(struct r4300_core* r4300); void gen_CP1_TRUNC_L_S(struct r4300_core* r4300); void gen_CP1_TRUNC_W_D(struct r4300_core* r4300); void gen_CP1_TRUNC_W_S(struct r4300_core* r4300); void gen_CTC1(struct r4300_core* r4300); void gen_DADD(struct r4300_core* r4300); void gen_DADDI(struct r4300_core* r4300); void gen_DADDIU(struct r4300_core* r4300); void gen_DADDU(struct r4300_core* r4300); void gen_DDIV(struct r4300_core* r4300); void gen_DDIVU(struct r4300_core* r4300); void gen_DIV(struct r4300_core* r4300); void gen_DIVU(struct r4300_core* r4300); void gen_DMFC1(struct r4300_core* r4300); void gen_DMTC1(struct r4300_core* r4300); void gen_DMULT(struct r4300_core* r4300); void gen_DMULTU(struct r4300_core* r4300); void gen_DSLL32(struct r4300_core* r4300); void gen_DSLL(struct r4300_core* r4300); void gen_DSLLV(struct r4300_core* r4300); void gen_DSRA32(struct r4300_core* r4300); void gen_DSRA(struct r4300_core* r4300); void gen_DSRAV(struct r4300_core* r4300); void gen_DSRL32(struct r4300_core* r4300); void gen_DSRL(struct r4300_core* r4300); void gen_DSRLV(struct r4300_core* r4300); void gen_DSUB(struct r4300_core* r4300); void gen_DSUBU(struct r4300_core* r4300); void gen_ERET(struct r4300_core* r4300); void gen_J(struct r4300_core* r4300); void gen_J_IDLE(struct r4300_core* r4300); void gen_J_OUT(struct r4300_core* r4300); void gen_JAL(struct r4300_core* r4300); void gen_JAL_IDLE(struct r4300_core* r4300); void gen_JAL_OUT(struct r4300_core* r4300); void gen_JALR(struct r4300_core* r4300); void gen_JR(struct r4300_core* r4300); void gen_LB(struct r4300_core* r4300); void gen_LBU(struct r4300_core* r4300); void gen_LDC1(struct r4300_core* r4300); void gen_LDL(struct r4300_core* r4300); void gen_LDR(struct r4300_core* r4300); void gen_LD(struct r4300_core* r4300); void gen_LH(struct r4300_core* r4300); void gen_LHU(struct r4300_core* r4300); void gen_LL(struct r4300_core* r4300); void gen_LUI(struct r4300_core* r4300); void gen_LWC1(struct r4300_core* r4300); void gen_LWL(struct r4300_core* r4300); void gen_LWR(struct r4300_core* r4300); void gen_LW(struct r4300_core* r4300); void gen_LWU(struct r4300_core* r4300); void gen_MFC0(struct r4300_core* r4300); void gen_MFC1(struct r4300_core* r4300); void gen_MFHI(struct r4300_core* r4300); void gen_MFLO(struct r4300_core* r4300); void gen_MTC0(struct r4300_core* r4300); void gen_MTC1(struct r4300_core* r4300); void gen_MTHI(struct r4300_core* r4300); void gen_MTLO(struct r4300_core* r4300); void gen_MULT(struct r4300_core* r4300); void gen_MULTU(struct r4300_core* r4300); void gen_NOP(struct r4300_core* r4300); void gen_NOR(struct r4300_core* r4300); void gen_ORI(struct r4300_core* r4300); void gen_OR(struct r4300_core* r4300); void gen_SB(struct r4300_core* r4300); void gen_SC(struct r4300_core* r4300); void gen_SDC1(struct r4300_core* r4300); void gen_SDL(struct r4300_core* r4300); void gen_SDR(struct r4300_core* r4300); void gen_SD(struct r4300_core* r4300); void gen_SH(struct r4300_core* r4300); void gen_SLL(struct r4300_core* r4300); void gen_SLLV(struct r4300_core* r4300); void gen_SLTI(struct r4300_core* r4300); void gen_SLTIU(struct r4300_core* r4300); void gen_SLT(struct r4300_core* r4300); void gen_SLTU(struct r4300_core* r4300); void gen_SRA(struct r4300_core* r4300); void gen_SRAV(struct r4300_core* r4300); void gen_SRL(struct r4300_core* r4300); void gen_SRLV(struct r4300_core* r4300); void gen_SUB(struct r4300_core* r4300); void gen_SUBU(struct r4300_core* r4300); void gen_SWC1(struct r4300_core* r4300); void gen_SWL(struct r4300_core* r4300); void gen_SWR(struct r4300_core* r4300); void gen_SW(struct r4300_core* r4300); void gen_SYNC(struct r4300_core* r4300); void gen_SYSCALL(struct r4300_core* r4300); void gen_TGE(struct r4300_core* r4300); void gen_TGEU(struct r4300_core* r4300); void gen_TGEI(struct r4300_core* r4300); void gen_TGEIU(struct r4300_core* r4300); void gen_TLT(struct r4300_core* r4300); void gen_TLTU(struct r4300_core* r4300); void gen_TLTI(struct r4300_core* r4300); void gen_TLTIU(struct r4300_core* r4300); void gen_TEQ(struct r4300_core* r4300); void gen_TEQI(struct r4300_core* r4300); void gen_TNE(struct r4300_core* r4300); void gen_TNEI(struct r4300_core* r4300); void gen_TLBP(struct r4300_core* r4300); void gen_TLBR(struct r4300_core* r4300); void gen_TLBWI(struct r4300_core* r4300); void gen_TLBWR(struct r4300_core* r4300); void gen_XORI(struct r4300_core* r4300); void gen_XOR(struct r4300_core* r4300); #define GENCP1_S_D(func) \ static void gen_CP1_##func(struct r4300_core* r4300) \ { \ unsigned fmt = (r4300->recomp.src >> 21) & 0x1f; \ switch(fmt) \ { \ case 0x10: gen_CP1_##func##_S(r4300); break; \ case 0x11: gen_CP1_##func##_D(r4300); break; \ default: gen_RESERVED(r4300); \ } \ } GENCP1_S_D(ABS) GENCP1_S_D(ADD) GENCP1_S_D(CEIL_L) GENCP1_S_D(CEIL_W) GENCP1_S_D(C_EQ) GENCP1_S_D(C_F) GENCP1_S_D(C_LE) GENCP1_S_D(C_LT) GENCP1_S_D(C_NGE) GENCP1_S_D(C_NGL) GENCP1_S_D(C_NGLE) GENCP1_S_D(C_NGT) GENCP1_S_D(C_OLE) GENCP1_S_D(C_OLT) GENCP1_S_D(C_SEQ) GENCP1_S_D(C_SF) GENCP1_S_D(C_UEQ) GENCP1_S_D(C_ULE) GENCP1_S_D(C_ULT) GENCP1_S_D(C_UN) GENCP1_S_D(CVT_L) GENCP1_S_D(CVT_W) GENCP1_S_D(DIV) GENCP1_S_D(FLOOR_L) GENCP1_S_D(FLOOR_W) GENCP1_S_D(MOV) GENCP1_S_D(MUL) GENCP1_S_D(NEG) GENCP1_S_D(ROUND_L) GENCP1_S_D(ROUND_W) GENCP1_S_D(SQRT) GENCP1_S_D(SUB) GENCP1_S_D(TRUNC_L) GENCP1_S_D(TRUNC_W) static void gen_CP1_CVT_D(struct r4300_core* r4300) { unsigned fmt = (r4300->recomp.src >> 21) & 0x1f; switch(fmt) { case 0x10: gen_CP1_CVT_D_S(r4300); break; case 0x14: gen_CP1_CVT_D_W(r4300); break; case 0x15: gen_CP1_CVT_D_L(r4300); break; default: gen_RESERVED(r4300); } } static void gen_CP1_CVT_S(struct r4300_core* r4300) { unsigned fmt = (r4300->recomp.src >> 21) & 0x1f; switch(fmt) { case 0x11: gen_CP1_CVT_S_D(r4300); break; case 0x14: gen_CP1_CVT_S_W(r4300); break; case 0x15: gen_CP1_CVT_S_L(r4300); break; default: gen_RESERVED(r4300); } } /* TODO: implement them properly */ #define gen_BC0F genni #define gen_BC0F_IDLE genni #define gen_BC0F_OUT genni #define gen_BC0FL genni #define gen_BC0FL_IDLE genni #define gen_BC0FL_OUT genni #define gen_BC0T genni #define gen_BC0T_IDLE genni #define gen_BC0T_OUT genni #define gen_BC0TL genni #define gen_BC0TL_IDLE genni #define gen_BC0TL_OUT genni #define gen_BC2F genni #define gen_BC2F_IDLE genni #define gen_BC2F_OUT genni #define gen_BC2FL genni #define gen_BC2FL_IDLE genni #define gen_BC2FL_OUT genni #define gen_BC2T genni #define gen_BC2T_IDLE genni #define gen_BC2T_OUT genni #define gen_BC2TL genni #define gen_BC2TL_IDLE genni #define gen_BC2TL_OUT genni #define gen_BREAK genni #define gen_CFC0 genni #define gen_CFC2 genni #define gen_CTC0 genni #define gen_CTC2 genni #define gen_DMFC0 genni #define gen_DMFC2 genni #define gen_DMTC0 genni #define gen_DMTC2 genni #define gen_JR_IDLE genni #define gen_JR_OUT gen_JR #define gen_JALR_IDLE genni #define gen_JALR_OUT gen_JALR #define gen_LDC2 genni #define gen_LWC2 genni #define gen_LLD genni #define gen_MFC2 genni #define gen_MTC2 genni #define gen_SCD genni #define gen_SDC2 genni #define gen_SWC2 genni #define gen_DCFC1 genni #define gen_DCFC2 genni #define gen_DCTC1 genni #define gen_DCTC2 genni #define X(op) gen_##op static void (*const recomp_funcs[R4300_OPCODES_COUNT])(struct r4300_core* r4300) = { #include "opcodes.md" }; #undef X /********************************************************************** ******************** initialize an empty block *********************** **********************************************************************/ void dynarec_init_block(struct r4300_core* r4300, uint32_t address) { int i, length, already_exist = 1; #if defined(PROFILE) timed_section_start(TIMED_SECTION_COMPILER); #endif struct precomp_block** block = &r4300->cached_interp.blocks[address >> 12]; /* allocate block */ if (*block == NULL) { *block = malloc(sizeof(struct precomp_block)); (*block)->block = NULL; (*block)->start = address & ~UINT32_C(0xfff); (*block)->end = (address & ~UINT32_C(0xfff)) + 0x1000; (*block)->code = NULL; (*block)->jumps_table = NULL; (*block)->riprel_table = NULL; } struct precomp_block* b = *block; length = get_block_length(b); #ifdef DBG DebugMessage(M64MSG_INFO, "init block %" PRIX32 " - %" PRIX32, b->start, b->end); #endif /* allocate block instructions */ if (!b->block) { size_t memsize = get_block_memsize(b); b->block = (struct precomp_instr *) malloc_exec(memsize); if (!b->block) { DebugMessage(M64MSG_ERROR, "Memory error: couldn't allocate executable memory for dynamic recompiler. Try to use an interpreter mode."); return; } memset(b->block, 0, memsize); already_exist = 0; } if (!b->code) { #if defined(PROFILE_R4300) r4300->recomp.max_code_length = 524288; /* allocate so much code space that we'll never have to realloc(), because this may */ /* cause instruction locations to move, and break our profiling data */ #else r4300->recomp.max_code_length = 32768; #endif b->code = (unsigned char *) malloc_exec(r4300->recomp.max_code_length); } else { r4300->recomp.max_code_length = b->max_code_length; } r4300->recomp.code_length = 0; r4300->recomp.inst_pointer = &b->code; if (b->jumps_table) { free(b->jumps_table); b->jumps_table = NULL; } if (b->riprel_table) { free(b->riprel_table); b->riprel_table = NULL; } init_assembler(r4300, NULL, 0, NULL, 0); init_cache(r4300, b->block); if (!already_exist) { #if defined(PROFILE_R4300) r4300->recomp.pfProfile = osal_file_open("instructionaddrs.dat", "ab"); long x86addr = (long) b->code; int mipsop = -2; /* -2 == NOTCOMPILED block at beginning of x86 code */ if (fwrite(&mipsop, 1, 4, r4300->recomp.pfProfile) != 4 || // write 4-byte MIPS opcode fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) // write pointer to dynamically generated x86 code for this MIPS instruction DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); #endif for (i=0; irecomp.dst = b->block + i; r4300->recomp.dst->addr = b->start + i*4; r4300->recomp.dst->reg_cache_infos.need_map = 0; r4300->recomp.dst->local_addr = r4300->recomp.code_length; #ifdef COMPARE_CORE gendebug(r4300); #endif r4300->recomp.dst->ops = dynarec_notcompiled; gennotcompiled(r4300); } #if defined(PROFILE_R4300) fclose(r4300->recomp.pfProfile); r4300->recomp.pfProfile = NULL; #endif r4300->recomp.init_length = r4300->recomp.code_length; } else { #if defined(PROFILE_R4300) r4300->recomp.code_length = b->code_length; /* leave old instructions in their place */ #else r4300->recomp.code_length = r4300->recomp.init_length; /* recompile everything, overwrite old recompiled instructions */ #endif for (i=0; irecomp.dst = b->block + i; r4300->recomp.dst->reg_cache_infos.need_map = 0; r4300->recomp.dst->local_addr = i * (r4300->recomp.init_length / length); r4300->recomp.dst->ops = r4300->cached_interp.not_compiled; } } free_all_registers(r4300); /* calling pass2 of the assembler is not necessary here because all of the code emitted by gennotcompiled() and gendebug() is position-independent and contains no jumps . */ b->code_length = r4300->recomp.code_length; b->max_code_length = r4300->recomp.max_code_length; free_assembler(r4300, &b->jumps_table, &b->jumps_number, &b->riprel_table, &b->riprel_number); /* here we're marking the block as a valid code even if it's not compiled * yet as the game should have already set up the code correctly. */ r4300->cached_interp.invalid_code[b->start>>12] = 0; if (b->end < UINT32_C(0x80000000) || b->start >= UINT32_C(0xc0000000)) { uint32_t paddr = virtual_to_physical_address(r4300, b->start, 2); r4300->cached_interp.invalid_code[paddr>>12] = 0; dynarec_init_block(r4300, paddr); paddr += b->end - b->start - 4; r4300->cached_interp.invalid_code[paddr>>12] = 0; dynarec_init_block(r4300, paddr); } else { uint32_t alt_addr = b->start ^ UINT32_C(0x20000000); if (r4300->cached_interp.invalid_code[alt_addr>>12]) { dynarec_init_block(r4300, alt_addr); } } #if defined(PROFILE) timed_section_end(TIMED_SECTION_COMPILER); #endif } void dynarec_free_block(struct precomp_block* block) { size_t memsize = get_block_memsize(block); if (block->block) { free_exec(block->block, memsize); block->block = NULL; } if (block->code) { free_exec(block->code, block->max_code_length); block->code = NULL; } if (block->jumps_table) { free(block->jumps_table); block->jumps_table = NULL; } if (block->riprel_table) { free(block->riprel_table); block->riprel_table = NULL; } } /********************************************************************** ********************* recompile a block of code ********************** **********************************************************************/ void dynarec_recompile_block(struct r4300_core* r4300, const uint32_t* iw, struct precomp_block* block, uint32_t func) { int i, length, length2, finished; enum r4300_opcode opcode; /* ??? not sure why we need these 2 different tests */ int block_start_in_tlb = ((block->start & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)); int block_not_in_tlb = (block->start >= UINT32_C(0xc0000000) || block->end < UINT32_C(0x80000000)); #if defined(PROFILE) timed_section_start(TIMED_SECTION_COMPILER); #endif length = get_block_length(block); length2 = length - 2 + (length >> 2); /* reset xxhash */ block->xxhash = 0; r4300->recomp.dst_block = block; r4300->recomp.code_length = block->code_length; r4300->recomp.max_code_length = block->max_code_length; r4300->recomp.inst_pointer = &block->code; init_assembler(r4300, block->jumps_table, block->jumps_number, block->riprel_table, block->riprel_number); init_cache(r4300, block->block + (func & 0xFFF) / 4); #if defined(PROFILE_R4300) r4300->recomp.pfProfile = osal_file_open("instructionaddrs.dat", "ab"); #endif for (i = (func & 0xFFF) / 4, finished = 0; finished != 2; ++i) { r4300->recomp.SRC = iw + i; r4300->recomp.src = iw[i]; r4300->recomp.dst = block->block + i; r4300->recomp.dst->addr = block->start + i*4; r4300->recomp.dst->reg_cache_infos.need_map = 0; r4300->recomp.dst->local_addr = r4300->recomp.code_length; if (block_start_in_tlb) { uint32_t address2 = virtual_to_physical_address(r4300, r4300->recomp.dst->addr, 0); if (r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops == r4300->cached_interp.not_compiled) { r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops = r4300->cached_interp.not_compiled2; } } #ifdef COMPARE_CORE gendebug(r4300); #endif #if defined(PROFILE_R4300) long x86addr = (long) (block->code + block->block[i].local_addr); /* write 4-byte MIPS opcode, followed by a pointer to dynamically generated x86 code for * this MIPS instruction. */ if (fwrite(iw + i, 1, 4, r4300->recomp.pfProfile) != 4 || fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) { DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); } #endif /* decode instruction */ opcode = r4300_decode(r4300->recomp.dst, r4300, r4300_get_idec(iw[i]), iw[i], iw[i+1], block); recomp_funcs[opcode](r4300); if (r4300->recomp.delay_slot_compiled) { r4300->recomp.delay_slot_compiled--; free_all_registers(r4300); } /* decode ending conditions */ if (i >= length2) { finished = 2; } if (i >= (length-1) && (block->start == UINT32_C(0xa4000000) || block_not_in_tlb)) { finished = 2; } if (opcode == R4300_OP_ERET || finished == 1) { finished = 2; } if (/*i >= length && */ (opcode == R4300_OP_J || opcode == R4300_OP_J_OUT || opcode == R4300_OP_JR || opcode == R4300_OP_JR_OUT) && !(i >= (length-1) && block_not_in_tlb)) { finished = 1; } } #if defined(PROFILE_R4300) long x86addr = (long) (block->code + r4300->recomp.code_length); int mipsop = -3; /* -3 == block-postfix */ /* write 4-byte MIPS opcode, followed by a pointer to dynamically generated x86 code for * this MIPS instruction. */ if (fwrite(&mipsop, 1, 4, r4300->recomp.pfProfile) != 4 || fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) { DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); } #endif if (i >= length) { r4300->recomp.dst = block->block + i; r4300->recomp.dst->addr = block->start + i*4; r4300->recomp.dst->reg_cache_infos.need_map = 0; r4300->recomp.dst->local_addr = r4300->recomp.code_length; #ifdef COMPARE_CORE gendebug(r4300); #endif r4300->recomp.dst->ops = dynarec_fin_block; genfin_block(r4300); ++i; if (i <= length2) // useful when last opcode is a jump { r4300->recomp.dst = block->block + i; r4300->recomp.dst->addr = block->start + i*4; r4300->recomp.dst->reg_cache_infos.need_map = 0; r4300->recomp.dst->local_addr = r4300->recomp.code_length; #ifdef COMPARE_CORE gendebug(r4300); #endif r4300->recomp.dst->ops = dynarec_fin_block; genfin_block(r4300); ++i; } } else { genlink_subblock(r4300); } free_all_registers(r4300); passe2(r4300, block->block, (func&0xFFF)/4, i, block); block->code_length = r4300->recomp.code_length; block->max_code_length = r4300->recomp.max_code_length; free_assembler(r4300, &block->jumps_table, &block->jumps_number, &block->riprel_table, &block->riprel_number); #ifdef DBG DebugMessage(M64MSG_INFO, "block recompiled (%" PRIX32 "-%" PRIX32 ")", func, block->start+i*4); #endif #if defined(PROFILE_R4300) fclose(r4300->recomp.pfProfile); r4300->recomp.pfProfile = NULL; #endif #if defined(PROFILE) timed_section_end(TIMED_SECTION_COMPILER); #endif } /********************************************************************** ************ recompile only one opcode (use for delay slot) ********** **********************************************************************/ void recompile_opcode(struct r4300_core* r4300) { r4300->recomp.SRC++; r4300->recomp.src = *r4300->recomp.SRC; r4300->recomp.dst++; r4300->recomp.dst->addr = (r4300->recomp.dst-1)->addr + 4; r4300->recomp.dst->reg_cache_infos.need_map = 0; /* we disable next_iw == NOP check by passing 1, because we are already in delay slot */ uint32_t iw = r4300->recomp.src; enum r4300_opcode opcode = r4300_decode(r4300->recomp.dst, r4300, r4300_get_idec(iw), iw, 1, r4300->recomp.dst_block); switch(opcode) { /* jumps/branches in delay slot are nopified */ #define CASE(op) case R4300_OP_##op: #define JCASE(op) CASE(op) CASE(op##_IDLE) CASE(op##_OUT) JCASE(BC0F) JCASE(BC0FL) JCASE(BC0T) JCASE(BC0TL) JCASE(BC1F) JCASE(BC1FL) JCASE(BC1T) JCASE(BC1TL) JCASE(BC2F) JCASE(BC2FL) JCASE(BC2T) JCASE(BC2TL) JCASE(BEQ) JCASE(BEQL) JCASE(BGEZ) JCASE(BGEZAL) JCASE(BGEZALL) JCASE(BGEZL) JCASE(BGTZ) JCASE(BGTZL) JCASE(BLEZ) JCASE(BLEZL) JCASE(BLTZ) JCASE(BLTZAL) JCASE(BLTZALL) JCASE(BLTZL) JCASE(BNE) JCASE(BNEL) JCASE(J) JCASE(JAL) JCASE(JALR) JCASE(JR) #undef JCASE #undef CASE r4300->recomp.dst->ops = cached_interp_NOP; gen_NOP(r4300); break; default: { #if defined(PROFILE_R4300) long x86addr = (long) ((*r4300->recomp.inst_pointer) + r4300->recomp.code_length); /* write 4-byte MIPS opcode, followed by a pointer to dynamically generated x86 code for * this MIPS instruction. */ if (fwrite(&r4300->recomp.src, 1, 4, r4300->recomp.pfProfile) != 4 || fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) { DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); } #endif recomp_funcs[opcode](r4300); } } r4300->recomp.delay_slot_compiled = 2; } #if defined(PROFILE_R4300) void profile_write_end_of_code_blocks(struct r4300_core* r4300) { size_t i; r4300->recomp.pfProfile = osal_file_open("instructionaddrs.dat", "ab"); for (i = 0; i < 0x100000; ++i) { if (r4300->cached_interp.invalid_code[i] == 0 && r4300->cached_interp.blocks[i] != NULL && r4300->cached_interp.blocks[i]->code != NULL && r4300->cached_interp.blocks[i]->block != NULL) { unsigned char *x86addr; int mipsop; // store final code length for this block mipsop = -1; /* -1 == end of x86 code block */ x86addr = r4300->cached_interp.blocks[i]->code + r4300->cached_interp.blocks[i]->code_length; if (fwrite(&mipsop, 1, 4, r4300->recomp.pfProfile) != 4 || fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); } } fclose(r4300->recomp.pfProfile); r4300->recomp.pfProfile = NULL; } #endif /* Jumps to the given address. This is for the dynarec. */ void dynarec_jump_to(struct r4300_core* r4300, uint32_t address) { cached_interpreter_jump_to(r4300, address); dyna_jump(); } void dynarec_fin_block(void) { cached_interp_FIN_BLOCK(); dyna_jump(); } void dynarec_notcompiled(void) { cached_interp_NOTCOMPILED(); dyna_jump(); } void dynarec_notcompiled2(void) { dynarec_notcompiled(); } void dynarec_setup_code(void) { struct r4300_core* r4300 = &g_dev.r4300; /* The dynarec jumps here after we call dyna_start and it prepares * Here we need to prepare the initial code block and jump to it */ dynarec_jump_to(r4300, r4300->start_address); /* Prevent segfault on failed dynarec_jump_to */ if (!r4300->cached_interp.actual->block || !r4300->cached_interp.actual->code) { dyna_stop(r4300); } } /* Parameterless version of dynarec_jump_to to ease usage in dynarec. */ void dynarec_jump_to_recomp_address(void) { struct r4300_core* r4300 = &g_dev.r4300; dynarec_jump_to(r4300, r4300->recomp.jump_to_address); } /* Parameterless version of exception_general to ease usage in dynarec. */ void dynarec_exception_general(void) { exception_general(&g_dev.r4300); } /* Parameterless version of check_cop1_unusable to ease usage in dynarec. */ int dynarec_check_cop1_unusable(void) { return check_cop1_unusable(&g_dev.r4300); } /* Parameterless version of cp0_update_count to ease usage in dynarec. */ void dynarec_cp0_update_count(void) { cp0_update_count(&g_dev.r4300); } /* Parameterless version of gen_interrupt to ease usage in dynarec. */ void dynarec_gen_interrupt(void) { gen_interrupt(&g_dev.r4300); } /* Parameterless version of read_aligned_word to ease usage in dynarec. */ int dynarec_read_aligned_word(void) { struct r4300_core* r4300 = &g_dev.r4300; uint32_t value; int result = r4300_read_aligned_word( r4300, r4300->recomp.address, &value); if (result) *r4300->recomp.rdword = value; return result; } /* Parameterless version of write_aligned_word to ease usage in dynarec. */ int dynarec_write_aligned_word(void) { struct r4300_core* r4300 = &g_dev.r4300; return r4300_write_aligned_word( r4300, r4300->recomp.address, r4300->recomp.wword, r4300->recomp.wmask); } /* Parameterless version of read_aligned_dword to ease usage in dynarec. */ int dynarec_read_aligned_dword(void) { struct r4300_core* r4300 = &g_dev.r4300; return r4300_read_aligned_dword( r4300, r4300->recomp.address, (uint64_t*)r4300->recomp.rdword); } /* Parameterless version of write_aligned_dword to ease usage in dynarec. */ int dynarec_write_aligned_dword(void) { struct r4300_core* r4300 = &g_dev.r4300; return r4300_write_aligned_dword( r4300, r4300->recomp.address, r4300->recomp.wdword, ~UINT64_C(0)); /* NOTE: in dynarec, we only need all-one masks */ } /********************************************************************** ************** allocate memory with executable bit set *************** **********************************************************************/ static void *malloc_exec(size_t size) { #if defined(WIN32) return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); #elif defined(__GNUC__) #ifndef MAP_ANONYMOUS #ifdef MAP_ANON #define MAP_ANONYMOUS MAP_ANON #endif #endif void *block = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (block == MAP_FAILED) { DebugMessage(M64MSG_ERROR, "Memory error: couldn't allocate %zi byte block of aligned RWX memory.", size); return NULL; } return block; #else return malloc(size); #endif } /********************************************************************** ************* reallocate memory with executable bit set ************** **********************************************************************/ void *realloc_exec(void *ptr, size_t oldsize, size_t newsize) { void* block = malloc_exec(newsize); if (block != NULL) { size_t copysize; copysize = (oldsize < newsize) ? oldsize : newsize; memcpy(block, ptr, copysize); } free_exec(ptr, oldsize); return block; } /********************************************************************** **************** frees memory with executable bit set **************** **********************************************************************/ static void free_exec(void *ptr, size_t length) { #if defined(WIN32) VirtualFree(ptr, 0, MEM_RELEASE); #elif defined(__GNUC__) munmap(ptr, length); #else free(ptr); #endif } mupen64plus-core-src-2.6.0/src/device/r4300/recomp.h000066400000000000000000000054241464506436200217070ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - recomp.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_RECOMP_H #define M64P_DEVICE_R4300_RECOMP_H #include #include struct r4300_core; struct precomp_block; void dynarec_init_block(struct r4300_core* r4300, uint32_t address); void dynarec_free_block(struct precomp_block* block); void dynarec_recompile_block(struct r4300_core* r4300, const uint32_t* source, struct precomp_block* block, uint32_t func); void recompile_opcode(struct r4300_core* r4300); void dyna_jump(void); void dyna_start(void (*code)(void)); void dyna_stop(struct r4300_core* r4300); void *realloc_exec(void *ptr, size_t oldsize, size_t newsize); void dynarec_jump_to(struct r4300_core* r4300, uint32_t address); void dynarec_fin_block(void); void dynarec_notcompiled(void); void dynarec_notcompiled2(void); void dynarec_setup_code(void); void dynarec_jump_to_recomp_address(void); void dynarec_exception_general(void); int dynarec_check_cop1_unusable(void); void dynarec_cp0_update_count(void); void dynarec_gen_interrupt(void); int dynarec_read_aligned_word(void); int dynarec_write_aligned_word(void); int dynarec_read_aligned_dword(void); int dynarec_write_aligned_dword(void); #if defined(PROFILE_R4300) void profile_write_end_of_code_blocks(struct r4300_core* r4300); #endif #endif /* M64P_DEVICE_R4300_RECOMP_H */ mupen64plus-core-src-2.6.0/src/device/r4300/recomp_types.h000066400000000000000000000061051464506436200231300ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - recomp_types.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_RECOMP_TYPES_H #define M64P_DEVICE_R4300_RECOMP_TYPES_H #include #include #if defined(__x86_64__) #include "x86_64/assemble_struct.h" #else #include "x86/assemble_struct.h" #endif struct precomp_instr { void (*ops)(void); union { struct { int64_t *rs; int64_t *rt; int16_t immediate; } i; struct { uint32_t inst_index; } j; struct { int64_t *rs; int64_t *rt; int64_t *rd; unsigned char sa; unsigned char nrd; } r; struct { unsigned char base; unsigned char ft; short offset; } lf; struct { unsigned char ft; unsigned char fs; unsigned char fd; } cf; } f; uint32_t addr; /* word-aligned instruction address in r4300 address space */ /* these fields are recomp specific */ unsigned int local_addr; /* byte offset to start of corresponding x86_64 instructions, from start of code block */ struct reg_cache reg_cache_infos; }; struct precomp_block { struct precomp_instr* block; uint32_t start; uint32_t end; /* these fields are recomp specific */ unsigned char *code; unsigned int code_length; unsigned int max_code_length; void *jumps_table; int jumps_number; void *riprel_table; int riprel_number; uint64_t xxhash; }; #endif /* M64P_DEVICE_R4300_RECOMP_TYPES_H */ mupen64plus-core-src-2.6.0/src/device/r4300/tlb.c000066400000000000000000000122771464506436200212020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - tlb.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "tlb.h" #include "api/m64p_types.h" #include "device/r4300/r4300_core.h" #include "device/rdram/rdram.h" #include #include void poweron_tlb(struct tlb* tlb) { /* clear TLB entries */ memset(tlb->entries, 0, 32 * sizeof(tlb->entries[0])); memset(tlb->LUT_r, 0, 0x100000 * sizeof(tlb->LUT_r[0])); memset(tlb->LUT_w, 0, 0x100000 * sizeof(tlb->LUT_w[0])); } void tlb_unmap(struct tlb* tlb, size_t entry) { unsigned int i; const struct tlb_entry* e; assert(entry < 32); e = &tlb->entries[entry]; if (e->v_even) { for (i=e->start_even; iend_even; i += 0x1000) tlb->LUT_r[i>>12] = 0; if (e->d_even) for (i=e->start_even; iend_even; i += 0x1000) tlb->LUT_w[i>>12] = 0; } if (e->v_odd) { for (i=e->start_odd; iend_odd; i += 0x1000) tlb->LUT_r[i>>12] = 0; if (e->d_odd) for (i=e->start_odd; iend_odd; i += 0x1000) tlb->LUT_w[i>>12] = 0; } } void tlb_map(struct tlb* tlb, size_t entry) { unsigned int i; const struct tlb_entry* e; assert(entry < 32); e = &tlb->entries[entry]; if (e->v_even) { if (e->start_even < e->end_even && !(e->start_even >= 0x80000000 && e->end_even < 0xC0000000) && e->phys_even < 0x20000000) { for (i=e->start_even;iend_even;i+=0x1000) tlb->LUT_r[i>>12] = UINT32_C(0x80000000) | (e->phys_even + (i - e->start_even) + 0xFFF); if (e->d_even) for (i=e->start_even;iend_even;i+=0x1000) tlb->LUT_w[i>>12] = UINT32_C(0x80000000) | (e->phys_even + (i - e->start_even) + 0xFFF); } } if (e->v_odd) { if (e->start_odd < e->end_odd && !(e->start_odd >= 0x80000000 && e->end_odd < 0xC0000000) && e->phys_odd < 0x20000000) { for (i=e->start_odd;iend_odd;i+=0x1000) tlb->LUT_r[i>>12] = UINT32_C(0x80000000) | (e->phys_odd + (i - e->start_odd) + 0xFFF); if (e->d_odd) for (i=e->start_odd;iend_odd;i+=0x1000) tlb->LUT_w[i>>12] = UINT32_C(0x80000000) | (e->phys_odd + (i - e->start_odd) + 0xFFF); } } } uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w) { const struct tlb* tlb = &r4300->cp0.tlb; unsigned int addr = address >> 12; #ifdef NEW_DYNAREC if (r4300->emumode == EMUMODE_DYNAREC) { intptr_t map = r4300->new_dynarec_hot_state.memory_map[addr]; if ((tlb->LUT_w[addr]) && (w == 1)) { assert(map == (((uintptr_t)r4300->rdram->dram + (uintptr_t)((tlb->LUT_w[addr] & 0xFFFFF000) - 0x80000000) - (address & 0xFFFFF000)) >> 2)); } else if ((tlb->LUT_r[addr]) && (w == 0)) { assert((map&~WRITE_PROTECT) == (((uintptr_t)r4300->rdram->dram + (uintptr_t)((tlb->LUT_r[addr] & 0xFFFFF000) - 0x80000000) - (address & 0xFFFFF000)) >> 2)); if (map & WRITE_PROTECT) { assert(tlb->LUT_w[addr] == 0); } } else { assert(map < 0); } } #endif if (w == 1) { if (tlb->LUT_w[addr]) return (tlb->LUT_w[addr] & UINT32_C(0xFFFFF000)) | (address & UINT32_C(0xFFF)); } else { if (tlb->LUT_r[addr]) return (tlb->LUT_r[addr] & UINT32_C(0xFFFFF000)) | (address & UINT32_C(0xFFF)); } //printf("tlb exception !!! @ %x, %x, add:%x\n", address, w, r4300->pc->addr); //getchar(); TLB_refill_exception(r4300, address, w); //return 0x80000000; return 0x00000000; } mupen64plus-core-src-2.6.0/src/device/r4300/tlb.h000066400000000000000000000046501464506436200212030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - tlb.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_TLB_H #define M64P_DEVICE_R4300_TLB_H #include #include struct r4300_core; struct tlb_entry { short mask; unsigned int vpn2; char g; unsigned char asid; unsigned int pfn_even; char c_even; char d_even; char v_even; unsigned int pfn_odd; char c_odd; char d_odd; char v_odd; char r; //int check_parity_mask; unsigned int start_even; unsigned int end_even; unsigned int phys_even; unsigned int start_odd; unsigned int end_odd; unsigned int phys_odd; }; struct tlb { struct tlb_entry entries[32]; uint32_t LUT_r[0x100000]; uint32_t LUT_w[0x100000]; }; void poweron_tlb(struct tlb* tlb); void tlb_unmap(struct tlb* tlb, size_t entry); void tlb_map(struct tlb* tlb, size_t entry); uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w); #endif /* M64P_DEVICE_R4300_TLB_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86/000077500000000000000000000000001464506436200206715ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/x86/assemble.c000066400000000000000000000122761464506436200226400ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assemble.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "assemble.h" #include "assemble_struct.h" #include "regcache.h" #include "device/r4300/recomp.h" #include "osal/preproc.h" void init_assembler(struct r4300_core* r4300, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number) { if (block_jumps_table) { r4300->recomp.jumps_table = (struct jump_table *) block_jumps_table; r4300->recomp.jumps_number = block_jumps_number; r4300->recomp.max_jumps_number = r4300->recomp.jumps_number; } else { r4300->recomp.jumps_table = (struct jump_table *) malloc(1000*sizeof(struct jump_table)); r4300->recomp.jumps_number = 0; r4300->recomp.max_jumps_number = 1000; } } void free_assembler(struct r4300_core* r4300, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number) { *block_jumps_table = r4300->recomp.jumps_table; *block_jumps_number = r4300->recomp.jumps_number; *block_riprel_table = NULL; /* RIP-relative addressing is only for x86-64 */ *block_riprel_number = 0; } void add_jump(struct r4300_core* r4300, unsigned int pc_addr, unsigned int mi_addr) { if (r4300->recomp.jumps_number == r4300->recomp.max_jumps_number) { r4300->recomp.max_jumps_number += 1000; r4300->recomp.jumps_table = (struct jump_table *) realloc(r4300->recomp.jumps_table, r4300->recomp.max_jumps_number*sizeof(struct jump_table)); } r4300->recomp.jumps_table[r4300->recomp.jumps_number].pc_addr = pc_addr; r4300->recomp.jumps_table[r4300->recomp.jumps_number].mi_addr = mi_addr; r4300->recomp.jumps_number++; } void passe2(struct r4300_core* r4300, struct precomp_instr *dest, int start, int end, struct precomp_block *block) { unsigned int real_code_length, addr_dest; size_t i; build_wrappers(r4300, dest, start, end, block); real_code_length = r4300->recomp.code_length; for (i=0; i < r4300->recomp.jumps_number; i++) { r4300->recomp.code_length = r4300->recomp.jumps_table[i].pc_addr; if (dest[(r4300->recomp.jumps_table[i].mi_addr - dest[0].addr)/4].reg_cache_infos.need_map) { addr_dest = (unsigned int)dest[(r4300->recomp.jumps_table[i].mi_addr - dest[0].addr)/4].reg_cache_infos.jump_wrapper; put32(addr_dest-((unsigned int)block->code+r4300->recomp.code_length)-4); } else { addr_dest = dest[(r4300->recomp.jumps_table[i].mi_addr - dest[0].addr)/4].local_addr; put32(addr_dest-r4300->recomp.code_length-4); } } r4300->recomp.code_length = real_code_length; } void jump_start_rel8(struct r4300_core* r4300) { r4300->recomp.jump_start8 = r4300->recomp.code_length; } void jump_start_rel32(struct r4300_core* r4300) { r4300->recomp.jump_start32 = r4300->recomp.code_length; } void jump_end_rel8(struct r4300_core* r4300) { unsigned int jump_end = r4300->recomp.code_length; int jump_vec = jump_end - r4300->recomp.jump_start8; if (jump_vec > 127 || jump_vec < -128) { DebugMessage(M64MSG_ERROR, "8-bit relative jump too long! From %x to %x", r4300->recomp.jump_start8, jump_end); OSAL_BREAKPOINT_INTERRUPT; } r4300->recomp.code_length = r4300->recomp.jump_start8 - 1; put8(jump_vec); r4300->recomp.code_length = jump_end; } void jump_end_rel32(struct r4300_core* r4300) { unsigned int jump_end = r4300->recomp.code_length; int jump_vec = jump_end - r4300->recomp.jump_start32; r4300->recomp.code_length = r4300->recomp.jump_start32 - 4; put32(jump_vec); r4300->recomp.code_length = jump_end; } mupen64plus-core-src-2.6.0/src/device/r4300/x86/assemble.h000066400000000000000000000434041464506436200226420ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assemble.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_X86_ASSEMBLE_H #define M64P_DEVICE_R4300_X86_ASSEMBLE_H #include #include #include "api/m64p_types.h" #include "api/callbacks.h" #include "device/r4300/recomp.h" #include "main/main.h" #include "osal/preproc.h" #define EAX 0 #define ECX 1 #define EDX 2 #define EBX 3 #define ESP 4 #define EBP 5 #define ESI 6 #define EDI 7 #define AX 0 #define CX 1 #define DX 2 #define BX 3 #define SP 4 #define BP 5 #define SI 6 #define DI 7 #define AL 0 #define CL 1 #define DL 2 #define BL 3 #define AH 4 #define CH 5 #define DH 6 #define BH 7 struct r4300_core; void jump_start_rel8(struct r4300_core* r4300); void jump_end_rel8(struct r4300_core* r4300); void jump_start_rel32(struct r4300_core* r4300); void jump_end_rel32(struct r4300_core* r4300); void add_jump(struct r4300_core* r4300, unsigned int pc_addr, unsigned int mi_addr); static osal_inline void put8(unsigned char octet) { struct r4300_core* r4300 = &g_dev.r4300; (*r4300->recomp.inst_pointer)[r4300->recomp.code_length] = octet; r4300->recomp.code_length++; if (r4300->recomp.code_length == r4300->recomp.max_code_length) { *r4300->recomp.inst_pointer = (unsigned char *) realloc_exec(*r4300->recomp.inst_pointer, r4300->recomp.max_code_length, r4300->recomp.max_code_length+8192); r4300->recomp.max_code_length += 8192; } } static osal_inline void put32(unsigned int dword) { struct r4300_core* r4300 = &g_dev.r4300; if ((r4300->recomp.code_length+4) >= r4300->recomp.max_code_length) { *r4300->recomp.inst_pointer = (unsigned char *) realloc_exec(*r4300->recomp.inst_pointer, r4300->recomp.max_code_length, r4300->recomp.max_code_length+8192); r4300->recomp.max_code_length += 8192; } *((unsigned int *)(&(*r4300->recomp.inst_pointer)[r4300->recomp.code_length])) = dword; r4300->recomp.code_length+=4; } static osal_inline void mov_eax_memoffs32(unsigned int *memoffs32) { put8(0xA1); put32((unsigned int)(memoffs32)); } static osal_inline void mov_memoffs32_eax(unsigned int *memoffs32) { put8(0xA3); put32((unsigned int)(memoffs32)); } static osal_inline void mov_m8_reg8(unsigned char *m8, int reg8) { put8(0x88); put8((reg8 << 3) | 5); put32((unsigned int)(m8)); } static osal_inline void mov_reg16_m16(int reg16, unsigned short *m16) { put8(0x66); put8(0x8B); put8((reg16 << 3) | 5); put32((unsigned int)(m16)); } static osal_inline void mov_m16_reg16(unsigned short *m16, int reg16) { put8(0x66); put8(0x89); put8((reg16 << 3) | 5); put32((unsigned int)(m16)); } static osal_inline void cmp_reg32_m32(int reg32, unsigned int *m32) { put8(0x3B); put8((reg32 << 3) | 5); put32((unsigned int)(m32)); } static osal_inline void cmp_reg32_reg32(int reg1, int reg2) { put8(0x39); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void cmp_reg32_imm8(int reg32, unsigned char imm8) { put8(0x83); put8(0xF8 + reg32); put8(imm8); } static osal_inline void cmp_preg32pimm32_imm8(int reg32, unsigned int imm32, unsigned char imm8) { put8(0x80); put8(0xB8 + reg32); put32(imm32); put8(imm8); } static osal_inline void cmp_reg32_imm32(int reg32, unsigned int imm32) { put8(0x81); put8(0xF8 + reg32); put32(imm32); } static osal_inline void test_reg32_imm32(int reg32, unsigned int imm32) { put8(0xF7); put8(0xC0 + reg32); put32(imm32); } static osal_inline void test_m32_imm32(unsigned int *m32, unsigned int imm32) { put8(0xF7); put8(0x05); put32((unsigned int)m32); put32(imm32); } static osal_inline void test_reg32_reg32(int reg1, int reg2) { put8(0x85); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void add_m32_reg32(unsigned int *m32, int reg32) { put8(0x01); put8((reg32 << 3) | 5); put32((unsigned int)(m32)); } static osal_inline void sub_m32_reg32(unsigned int *m32, int reg32) { put8(0x29); put8((reg32 << 3) | 5); put32((unsigned int)(m32)); } static osal_inline void sub_reg32_m32(int reg32, unsigned int *m32) { put8(0x2B); put8((reg32 << 3) | 5); put32((unsigned int)(m32)); } static osal_inline void sub_reg32_reg32(int reg1, int reg2) { put8(0x29); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void sbb_reg32_reg32(int reg1, int reg2) { put8(0x19); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void sub_reg32_imm32(int reg32, unsigned int imm32) { put8(0x81); put8(0xE8 + reg32); put32(imm32); } static osal_inline void sub_eax_imm32(unsigned int imm32) { put8(0x2D); put32(imm32); } static osal_inline void jne_rj(unsigned char saut) { put8(0x75); put8(saut); } static osal_inline void je_rj(unsigned char saut) { put8(0x74); put8(saut); } static osal_inline void jb_rj(unsigned char saut) { put8(0x72); put8(saut); } static osal_inline void jbe_rj(unsigned char saut) { put8(0x76); put8(saut); } static osal_inline void ja_rj(unsigned char saut) { put8(0x77); put8(saut); } static osal_inline void jae_rj(unsigned char saut) { put8(0x73); put8(saut); } static osal_inline void jle_rj(unsigned char saut) { put8(0x7E); put8(saut); } static osal_inline void jge_rj(unsigned char saut) { put8(0x7D); put8(saut); } static osal_inline void jg_rj(unsigned char saut) { put8(0x7F); put8(saut); } static osal_inline void jl_rj(unsigned char saut) { put8(0x7C); put8(saut); } static osal_inline void jp_rj(unsigned char saut) { put8(0x7A); put8(saut); } static osal_inline void jns_rj(unsigned char saut) { put8(0x79); put8(saut); } static osal_inline void js_rj(unsigned char saut) { put8(0x78); put8(saut); } static osal_inline void je_near_rj(unsigned int saut) { put8(0x0F); put8(0x84); put32(saut); } static osal_inline void mov_reg32_imm32(int reg32, unsigned int imm32) { put8(0xB8+reg32); put32(imm32); } static osal_inline void jmp_imm_short(char saut) { put8(0xEB); put8(saut); } static osal_inline void or_m32_imm32(unsigned int *m32, unsigned int imm32) { put8(0x81); put8(0x0D); put32((unsigned int)(m32)); put32(imm32); } static osal_inline void or_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x09); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void and_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x21); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void and_m32_imm32(unsigned int *m32, unsigned int imm32) { put8(0x81); put8(0x25); put32((unsigned int)(m32)); put32(imm32); } static osal_inline void xor_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x31); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void sub_m32_imm32(unsigned int *m32, unsigned int imm32) { put8(0x81); put8(0x2D); put32((unsigned int)(m32)); put32(imm32); } static osal_inline void add_reg32_imm32(unsigned int reg32, unsigned int imm32) { put8(0x81); put8(0xC0+reg32); put32(imm32); } static osal_inline void inc_m32(unsigned int *m32) { put8(0xFF); put8(0x05); put32((unsigned int)(m32)); } static osal_inline void cmp_m32_imm32(unsigned int *m32, unsigned int imm32) { put8(0x81); put8(0x3D); put32((unsigned int)(m32)); put32(imm32); } static osal_inline void cmp_eax_imm32(unsigned int imm32) { put8(0x3D); put32(imm32); } static osal_inline void mov_m32_imm32(unsigned int *m32, unsigned int imm32) { put8(0xC7); put8(0x05); put32((unsigned int)(m32)); put32(imm32); } static osal_inline void jmp(unsigned int mi_addr) { struct r4300_core* r4300 = &g_dev.r4300; put8(0xE9); put32(0); add_jump(r4300, r4300->recomp.code_length-4, mi_addr); } static osal_inline void cdq(void) { put8(0x99); } static osal_inline void mov_m32_reg32(unsigned int *m32, unsigned int reg32) { put8(0x89); put8((reg32 << 3) | 5); put32((unsigned int)(m32)); } static osal_inline void call_reg32(unsigned int reg32) { put8(0xFF); put8(0xD0+reg32); } static osal_inline void shr_reg32_imm8(unsigned int reg32, unsigned char imm8) { put8(0xC1); put8(0xE8+reg32); put8(imm8); } static osal_inline void shr_reg32_cl(unsigned int reg32) { put8(0xD3); put8(0xE8+reg32); } static osal_inline void sar_reg32_cl(unsigned int reg32) { put8(0xD3); put8(0xF8+reg32); } static osal_inline void shl_reg32_cl(unsigned int reg32) { put8(0xD3); put8(0xE0+reg32); } static osal_inline void shld_reg32_reg32_cl(unsigned int reg1, unsigned int reg2) { put8(0x0F); put8(0xA5); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void shld_reg32_reg32_imm8(unsigned int reg1, unsigned int reg2, unsigned char imm8) { put8(0x0F); put8(0xA4); put8(0xC0 | (reg2 << 3) | reg1); put8(imm8); } static osal_inline void shrd_reg32_reg32_cl(unsigned int reg1, unsigned int reg2) { put8(0x0F); put8(0xAD); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void sar_reg32_imm8(unsigned int reg32, unsigned char imm8) { put8(0xC1); put8(0xF8+reg32); put8(imm8); } static osal_inline void shrd_reg32_reg32_imm8(unsigned int reg1, unsigned int reg2, unsigned char imm8) { put8(0x0F); put8(0xAC); put8(0xC0 | (reg2 << 3) | reg1); put8(imm8); } static osal_inline void mul_m32(unsigned int *m32) { put8(0xF7); put8(0x25); put32((unsigned int)(m32)); } static osal_inline void imul_reg32(unsigned int reg32) { put8(0xF7); put8(0xE8+reg32); } static osal_inline void mul_reg32(unsigned int reg32) { put8(0xF7); put8(0xE0+reg32); } static osal_inline void idiv_reg32(unsigned int reg32) { put8(0xF7); put8(0xF8+reg32); } static osal_inline void div_reg32(unsigned int reg32) { put8(0xF7); put8(0xF0+reg32); } static osal_inline void add_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x01); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void adc_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x11); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void add_reg32_m32(unsigned int reg32, unsigned int *m32) { put8(0x03); put8((reg32 << 3) | 5); put32((unsigned int)(m32)); } static osal_inline void adc_reg32_imm32(unsigned int reg32, unsigned int imm32) { put8(0x81); put8(0xD0 + reg32); put32(imm32); } static osal_inline void jmp_reg32(unsigned int reg32) { put8(0xFF); put8(0xE0 + reg32); } static osal_inline void mov_reg32_preg32(unsigned int reg1, unsigned int reg2) { put8(0x8B); put8((reg1 << 3) | reg2); } static osal_inline void mov_preg32_reg32(int reg1, int reg2) { put8(0x89); put8((reg2 << 3) | reg1); } static osal_inline void mov_reg32_preg32preg32pimm32(int reg1, int reg2, int reg3, unsigned int imm32) { put8(0x8B); put8((reg1 << 3) | 0x84); put8(reg2 | (reg3 << 3)); put32(imm32); } static osal_inline void mov_reg32_preg32pimm32(int reg1, int reg2, unsigned int imm32) { put8(0x8B); put8(0x80 | (reg1 << 3) | reg2); put32(imm32); } static osal_inline void lea_reg32_preg32x2preg32(int reg1, int reg2, int reg3) { put8(0x8D); put8(0x04 | (reg1 << 3)); put8(0x40 | (reg2 << 3) | reg3); } static osal_inline void mov_reg32_preg32x4pimm32(int reg1, int reg2, unsigned int imm32) { put8(0x8B); put8((reg1 << 3) | 4); put8(0x80 | (reg2 << 3) | 5); put32(imm32); } static osal_inline void mov_preg32pimm32_reg8(int reg32, unsigned int imm32, int reg8) { put8(0x88); put8(0x80 | reg32 | (reg8 << 3)); put32(imm32); } static osal_inline void mov_preg32pimm32_imm8(int reg32, unsigned int imm32, unsigned char imm8) { put8(0xC6); put8(0x80 + reg32); put32(imm32); put8(imm8); } static osal_inline void mov_preg32pimm32_reg16(int reg32, unsigned int imm32, int reg16) { put8(0x66); put8(0x89); put8(0x80 | reg32 | (reg16 << 3)); put32(imm32); } static osal_inline void mov_preg32pimm32_reg32(int reg1, unsigned int imm32, int reg2) { put8(0x89); put8(0x80 | reg1 | (reg2 << 3)); put32(imm32); } static osal_inline void add_eax_imm32(unsigned int imm32) { put8(0x05); put32(imm32); } static osal_inline void shl_reg32_imm8(unsigned int reg32, unsigned char imm8) { put8(0xC1); put8(0xE0 + reg32); put8(imm8); } static osal_inline void mov_reg32_m32(unsigned int reg32, unsigned int* m32) { put8(0x8B); put8((reg32 << 3) | 5); put32((unsigned int)(m32)); } static osal_inline void mov_reg8_m8(int reg8, unsigned char *m8) { put8(0x8A); put8((reg8 << 3) | 5); put32((unsigned int)(m8)); } static osal_inline void and_eax_imm32(unsigned int imm32) { put8(0x25); put32(imm32); } static osal_inline void and_reg32_imm32(int reg32, unsigned int imm32) { put8(0x81); put8(0xE0 + reg32); put32(imm32); } static osal_inline void or_reg32_imm32(int reg32, unsigned int imm32) { put8(0x81); put8(0xC8 + reg32); put32(imm32); } static osal_inline void xor_reg32_imm32(int reg32, unsigned int imm32) { put8(0x81); put8(0xF0 + reg32); put32(imm32); } static osal_inline void xor_reg8_imm8(int reg8, unsigned char imm8) { put8(0x80); put8(0xF0 + reg8); put8(imm8); } static osal_inline void mov_reg32_reg32(unsigned int reg1, unsigned int reg2) { if (reg1 == reg2) return; put8(0x89); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void not_reg32(unsigned int reg32) { put8(0xF7); put8(0xD0 + reg32); } static osal_inline void movsx_reg32_m8(int reg32, unsigned char *m8) { put8(0x0F); put8(0xBE); put8((reg32 << 3) | 5); put32((unsigned int)(m8)); } static osal_inline void movsx_reg32_8preg32pimm32(int reg1, int reg2, unsigned int imm32) { put8(0x0F); put8(0xBE); put8((reg1 << 3) | reg2 | 0x80); put32(imm32); } static osal_inline void movsx_reg32_16preg32pimm32(int reg1, int reg2, unsigned int imm32) { put8(0x0F); put8(0xBF); put8((reg1 << 3) | reg2 | 0x80); put32(imm32); } static osal_inline void movsx_reg32_m16(int reg32, unsigned short *m16) { put8(0x0F); put8(0xBF); put8((reg32 << 3) | 5); put32((unsigned int)(m16)); } static osal_inline void fldcw_m16(unsigned short *m16) { put8(0xD9); put8(0x2D); put32((unsigned int)(m16)); } static osal_inline void fld_preg32_dword(int reg32) { put8(0xD9); put8(reg32); } static osal_inline void fdiv_preg32_dword(int reg32) { put8(0xD8); put8(0x30 + reg32); } static osal_inline void fstp_preg32_dword(int reg32) { put8(0xD9); put8(0x18 + reg32); } static osal_inline void fchs(void) { put8(0xD9); put8(0xE0); } static osal_inline void fstp_preg32_qword(int reg32) { put8(0xDD); put8(0x18 + reg32); } static osal_inline void fadd_preg32_dword(int reg32) { put8(0xD8); put8(reg32); } static osal_inline void fsub_preg32_dword(int reg32) { put8(0xD8); put8(0x20 + reg32); } static osal_inline void fmul_preg32_dword(int reg32) { put8(0xD8); put8(0x08 + reg32); } static osal_inline void fistp_preg32_dword(int reg32) { put8(0xDB); put8(0x18 + reg32); } static osal_inline void fistp_preg32_qword(int reg32) { put8(0xDF); put8(0x38 + reg32); } static osal_inline void fld_preg32_qword(int reg32) { put8(0xDD); put8(reg32); } static osal_inline void fild_preg32_qword(int reg32) { put8(0xDF); put8(0x28+reg32); } static osal_inline void fild_preg32_dword(int reg32) { put8(0xDB); put8(reg32); } static osal_inline void fadd_preg32_qword(int reg32) { put8(0xDC); put8(reg32); } static osal_inline void fdiv_preg32_qword(int reg32) { put8(0xDC); put8(0x30 + reg32); } static osal_inline void fsub_preg32_qword(int reg32) { put8(0xDC); put8(0x20 + reg32); } static osal_inline void fmul_preg32_qword(int reg32) { put8(0xDC); put8(0x08 + reg32); } static osal_inline void fsqrt(void) { put8(0xD9); put8(0xFA); } static osal_inline void fabs_(void) { put8(0xD9); put8(0xE1); } static osal_inline void fcomip_fpreg(int fpreg) { put8(0xDF); put8(0xF0 + fpreg); } static osal_inline void fucomip_fpreg(int fpreg) { put8(0xDF); put8(0xE8 + fpreg); } static osal_inline void ffree_fpreg(int fpreg) { put8(0xDD); put8(0xC0 + fpreg); } #endif /* M64P_DEVICE_R4300_X86_ASSEMBLE_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86/assemble_struct.h000066400000000000000000000041151464506436200242420ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assemble_struct.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_X86_ASSEMBLE_STRUCT_H #define M64P_DEVICE_R4300_X86_ASSEMBLE_STRUCT_H struct precomp_instr; struct regcache_state { unsigned int* reg_content[8]; struct precomp_instr* last_access[8]; struct precomp_instr* free_since[8]; int dirty[8]; int r64[8]; unsigned int* r0; }; struct reg_cache { int need_map; void *needed_registers[8]; unsigned char jump_wrapper[62]; int need_cop1_check; }; struct jump_table { unsigned int mi_addr; unsigned int pc_addr; }; #endif /* M64P_DEVICE_R4300_X86_ASSEMBLE_STRUCT_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86/dyna_start.asm000066400000000000000000000106761464506436200235550ustar00rootroot00000000000000;Mupen64plus - dyna_start.asm ;Mupen64Plus homepage: https://mupen64plus.org/ ;Copyright (C) 2007 Richard Goedeken (Richard42) ;Copyright (C) 2002 Hacktarux ; ;This program is free software; you can redistribute it and/or modify ;it under the terms of the GNU General Public License as published by ;the Free Software Foundation; either version 2 of the License, or ;(at your option) any later version. ; ;This program is distributed in the hope that it will be useful, ;but WITHOUT ANY WARRANTY; without even the implied warranty of ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;GNU General Public License for more details. ; ;You should have received a copy of the GNU General Public License ;along with this program; if not, write to the ;Free Software Foundation, Inc., ;51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. %include "asm_defines_nasm.h" %ifidn __OUTPUT_FORMAT__,elf section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf32 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf64 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifdef LEADING_UNDERSCORE %macro cglobal 1 global _%1 %define %1 _%1 %endmacro %macro cextern 1 extern _%1 %define %1 _%1 %endmacro %else %macro cglobal 1 global %1 %endmacro %macro cextern 1 extern %1 %endmacro %endif %macro get_GOT 0 call %%getgot %%getgot: pop ebx add ebx,_GLOBAL_OFFSET_TABLE_+$$-%%getgot wrt ..gotpc %endmacro %ifdef PIC %define get_got_address get_GOT %define store_ebx %define load_ebx %define find_local_data(a) ebx + a wrt ..gotoff %define find_external_data(a) ebx + a wrt ..got %else %define get_got_address %define store_ebx mov [g_dev_r4300_recomp_save_ebx], ebx %define load_ebx mov ebx, [g_dev_r4300_recomp_save_ebx] %define find_local_data(a) a %define find_extern_data(a) a %endif %define g_dev_r4300_recomp_save_ebp (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_ebp) %define g_dev_r4300_recomp_save_esp (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_esp) %define g_dev_r4300_recomp_save_ebx (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_ebx) %define g_dev_r4300_recomp_save_esi (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_esi) %define g_dev_r4300_recomp_save_edi (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_edi) %define g_dev_r4300_recomp_save_eip (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_eip) %define g_dev_r4300_recomp_return_address (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_return_address) cglobal dyna_start cextern g_dev %ifdef PIC cextern _GLOBAL_OFFSET_TABLE_ %endif section .bss align 4 section .rodata section .text dyna_start: get_got_address store_ebx mov [find_local_data(g_dev_r4300_recomp_save_ebp)], ebp mov [find_local_data(g_dev_r4300_recomp_save_esp)], esp mov [find_local_data(g_dev_r4300_recomp_save_esi)], esi mov [find_local_data(g_dev_r4300_recomp_save_edi)], edi call point1 jmp point2 point1: pop eax mov [find_local_data(g_dev_r4300_recomp_save_eip)], eax mov eax, [esp+4] sub esp, 0x10 and esp, 0xfffffff0 mov [find_local_data(g_dev_r4300_recomp_return_address)], esp sub DWORD [find_local_data(g_dev_r4300_recomp_return_address)], 4 call eax point2: get_got_address load_ebx mov ebp, [find_local_data(g_dev_r4300_recomp_save_ebp)] mov esp, [find_local_data(g_dev_r4300_recomp_save_esp)] mov esi, [find_local_data(g_dev_r4300_recomp_save_esi)] mov edi, [find_local_data(g_dev_r4300_recomp_save_edi)] mov DWORD [find_local_data(g_dev_r4300_recomp_save_ebx)], 0 mov DWORD [find_local_data(g_dev_r4300_recomp_save_ebp)], 0 mov DWORD [find_local_data(g_dev_r4300_recomp_save_esp)], 0 mov DWORD [find_local_data(g_dev_r4300_recomp_save_esi)], 0 mov DWORD [find_local_data(g_dev_r4300_recomp_save_edi)], 0 mov DWORD [find_local_data(g_dev_r4300_recomp_save_eip)], 0 ret mupen64plus-core-src-2.6.0/src/device/r4300/x86/dynarec.c000066400000000000000000005714631464506436200225020ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dynarec.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "assemble.h" #include "interpret.h" #include "regcache.h" #include "api/callbacks.h" #include "api/debugger.h" #include "api/m64p_types.h" #include "device/memory/memory.h" #include "device/r4300/cached_interp.h" #include "device/r4300/cp0.h" #include "device/r4300/cp1.h" #include "device/r4300/interrupt.h" #include "device/r4300/recomp.h" #include "device/rdram/rdram.h" #include "main/main.h" #include #include #include /* These are constants with addresses so that FLDCW can read them */ static const uint16_t trunc_mode = 0xf3f; static const uint16_t round_mode = 0x33f; static const uint16_t ceil_mode = 0xb3f; static const uint16_t floor_mode = 0x73f; static const unsigned int precomp_instr_size = sizeof(struct precomp_instr); /* Dynarec control functions */ void dyna_jump(void) { struct r4300_core* r4300 = &g_dev.r4300; if (*r4300_stop(r4300) == 1) { dyna_stop(r4300); return; } if ((*r4300_pc_struct(r4300))->reg_cache_infos.need_map) { *r4300->recomp.return_address = (unsigned long) ((*r4300_pc_struct(r4300))->reg_cache_infos.jump_wrapper); } else { *r4300->recomp.return_address = (unsigned long) (r4300->cached_interp.actual->code + (*r4300_pc_struct(r4300))->local_addr); } } void dyna_stop(struct r4300_core* r4300) { if (r4300->recomp.save_eip == 0) { DebugMessage(M64MSG_WARNING, "instruction pointer is 0 at dyna_stop()"); } else { *r4300->recomp.return_address = (unsigned long)r4300->recomp.save_eip; } } /* M64P Pseudo instructions */ static void gencallinterp(struct r4300_core* r4300, uintptr_t addr, int jump) { free_all_registers(r4300); simplify_access(r4300); if (jump) { mov_m32_imm32((unsigned int*)(&r4300->recomp.dyna_interp), 1); } mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst)); mov_reg32_imm32(EAX, addr); call_reg32(EAX); if (jump) { mov_m32_imm32((unsigned int*)(&r4300->recomp.dyna_interp), 0); mov_reg32_imm32(EAX, (unsigned int)dyna_jump); call_reg32(EAX); } } static void gencheck_cop1_unusable(struct r4300_core* r4300) { free_all_registers(r4300); simplify_access(r4300); test_m32_imm32((unsigned int*)&r4300_cp0_regs(&r4300->cp0)[CP0_STATUS_REG], CP0_STATUS_CU1); jne_rj(0); jump_start_rel8(r4300); gencallinterp(r4300, (unsigned int)dynarec_check_cop1_unusable, 0); jump_end_rel8(r4300); } static void gencp0_update_count(struct r4300_core* r4300, unsigned int addr) { #if !defined(COMPARE_CORE) && !defined(DBG) mov_reg32_imm32(EAX, addr); sub_reg32_m32(EAX, (unsigned int*)(&r4300->cp0.last_addr)); shr_reg32_imm8(EAX, 2); mov_reg32_m32(EDX, &r4300->cp0.count_per_op); mul_reg32(EDX); if (r4300->cp0.count_per_op_denom_pot) { add_reg32_imm32(EAX, (1 << g_dev.r4300.cp0.count_per_op_denom_pot) - 1); shr_reg32_imm8(EAX, g_dev.r4300.cp0.count_per_op_denom_pot); } add_m32_reg32((unsigned int*)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), EAX); add_m32_reg32((unsigned int*)r4300_cp0_cycle_count(&r4300->cp0), EAX); #else mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); mov_reg32_imm32(EAX, (unsigned int)dynarec_cp0_update_count); call_reg32(EAX); #endif } static void gencheck_interrupt(struct r4300_core* r4300, unsigned int instr_structure) { mov_eax_memoffs32((unsigned int*)r4300_cp0_cycle_count(&r4300->cp0)); test_reg32_reg32(EAX, EAX); js_rj(17); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), instr_structure); // 10 mov_reg32_imm32(EAX, (unsigned int)dynarec_gen_interrupt); // 5 call_reg32(EAX); // 2 } static void gencheck_interrupt_out(struct r4300_core* r4300, unsigned int addr) { mov_eax_memoffs32((unsigned int*)r4300_cp0_cycle_count(&r4300->cp0)); test_reg32_reg32(EAX, EAX); js_rj(27); mov_m32_imm32((unsigned int*)(&r4300->recomp.fake_instr.addr), addr); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(&r4300->recomp.fake_instr)); mov_reg32_imm32(EAX, (unsigned int)dynarec_gen_interrupt); call_reg32(EAX); } static void gencheck_interrupt_reg(struct r4300_core* r4300) // addr is in EAX { mov_reg32_m32(EBX, (unsigned int*)r4300_cp0_cycle_count(&r4300->cp0)); test_reg32_reg32(EBX, EBX); js_rj(22); mov_memoffs32_eax((unsigned int*)(&r4300->recomp.fake_instr.addr)); // 5 mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(&r4300->recomp.fake_instr)); // 10 mov_reg32_imm32(EAX, (unsigned int)dynarec_gen_interrupt); // 5 call_reg32(EAX); // 2 } static void gendelayslot(struct r4300_core* r4300) { mov_m32_imm32(&r4300->delay_slot, 1); recompile_opcode(r4300); free_all_registers(r4300); gencp0_update_count(r4300, r4300->recomp.dst->addr+4); mov_m32_imm32(&r4300->delay_slot, 0); } #ifdef COMPARE_CORE extern unsigned int op; /* api/debugger.c */ void gendebug(struct r4300_core* r4300) { free_all_registers(r4300); mov_m32_reg32((unsigned int*)&r4300->recomp.eax, EAX); mov_m32_reg32((unsigned int*)&r4300->recomp.ebx, EBX); mov_m32_reg32((unsigned int*)&r4300->recomp.ecx, ECX); mov_m32_reg32((unsigned int*)&r4300->recomp.edx, EDX); mov_m32_reg32((unsigned int*)&r4300->recomp.esp, ESP); mov_m32_reg32((unsigned int*)&r4300->recomp.ebp, EBP); mov_m32_reg32((unsigned int*)&r4300->recomp.esi, ESI); mov_m32_reg32((unsigned int*)&r4300->recomp.edi, EDI); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst)); mov_m32_imm32((unsigned int*)(&op), (unsigned int)(r4300->recomp.src)); mov_reg32_imm32(EAX, (unsigned int) CoreCompareCallback); call_reg32(EAX); mov_reg32_m32(EAX, (unsigned int*)&r4300->recomp.eax); mov_reg32_m32(EBX, (unsigned int*)&r4300->recomp.ebx); mov_reg32_m32(ECX, (unsigned int*)&r4300->recomp.ecx); mov_reg32_m32(EDX, (unsigned int*)&r4300->recomp.edx); mov_reg32_m32(ESP, (unsigned int*)&r4300->recomp.esp); mov_reg32_m32(EBP, (unsigned int*)&r4300->recomp.ebp); mov_reg32_m32(ESI, (unsigned int*)&r4300->recomp.esi); mov_reg32_m32(EDI, (unsigned int*)&r4300->recomp.edi); } #endif void genni(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_NI, 0); } void gennotcompiled(struct r4300_core* r4300) { free_all_registers(r4300); simplify_access(r4300); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst)); mov_reg32_imm32(EAX, (unsigned int)dynarec_notcompiled); call_reg32(EAX); } void genlink_subblock(struct r4300_core* r4300) { free_all_registers(r4300); jmp(r4300->recomp.dst->addr+4); } void genfin_block(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)dynarec_fin_block, 0); } /* Reserved */ void gen_RESERVED(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_RESERVED, 0); } /* Load instructions */ void gen_LB(struct r4300_core* r4300) { #ifdef INTERPRET_LB gencallinterp(r4300, (unsigned int)cached_interp_LB, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); jump_end_rel8(r4300); } je_rj(95); mov_m32_imm32((unsigned int *)&(*r4300_pc_struct(r4300)), (unsigned int)(r4300->recomp.dst+1)); // 10 /* if non RDRAM read, * compute shift (ECX) and address (EBX) to perform a regular read * Save ECX content to memory as ECX can be overwritten when calling read32 function */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 3); // 6 xor_reg32_imm32(ECX, 3); // 6 shl_reg32_imm8(ECX, 3); // 3 mov_m32_reg32((unsigned int *)&r4300->recomp.shift, ECX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.rdword), (unsigned int)r4300->recomp.dst->f.i.rt); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_word); // 5 call_reg32(EBX); // 2 and_reg32_reg32(EAX, EAX); // 2 je_rj(51); // 2 mov_reg32_m32(EAX, (unsigned int *)r4300->recomp.dst->f.i.rt); // 6 mov_reg32_m32(ECX, (unsigned int *)&r4300->recomp.shift); // 6 shr_reg32_cl(EAX); // 2 and_reg32_imm32(EAX, 0xff); // 6 mov_m32_reg32((unsigned int*)r4300->recomp.dst->f.i.rt, EAX); // 6 movsx_reg32_m8(EAX, (unsigned char *)r4300->recomp.dst->f.i.rt); // 7 jmp_imm_short(16); // 2 /* else (RDRAM read), read byte */ and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 3); // 3 movsx_reg32_8preg32pimm32(EAX, EBX, (unsigned int)r4300->rdram->dram); // 7 set_register_state(r4300, EAX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1); #endif } void gen_LBU(struct r4300_core* r4300) { #ifdef INTERPRET_LBU gencallinterp(r4300, (unsigned int)cached_interp_LBU, 0); #else free_all_registers(r4300); simplify_access(r4300); /* get address in both EAX and EBX */ mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); jump_end_rel8(r4300); } je_rj(76); mov_m32_imm32((unsigned int *)&(*r4300_pc_struct(r4300)), (unsigned int)(r4300->recomp.dst+1)); // 10 /* if non RDRAM read, * compute shift (ECX) and address (EBX) to perform a regular read * Save ECX content to memory as ECX can be overwritten when calling read32 function */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 3); // 6 xor_reg32_imm32(ECX, 3); // 6 shl_reg32_imm8(ECX, 3); // 3 mov_m32_reg32((unsigned int *)&r4300->recomp.shift, ECX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.rdword), (unsigned int)r4300->recomp.dst->f.i.rt); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_word); // 5 call_reg32(EBX); // 2 and_reg32_reg32(EAX, EAX); // 2 je_rj(31); // 2 mov_reg32_m32(EAX, (unsigned int *)r4300->recomp.dst->f.i.rt); // 6 mov_reg32_m32(ECX, (unsigned int *)&r4300->recomp.shift); // 6 shr_reg32_cl(EAX); // 2 jmp_imm_short(15); // 2 /* else (RDRAM read), read byte */ and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 3); // 3 mov_reg32_preg32pimm32(EAX, EBX, (unsigned int)r4300->rdram->dram); // 6 and_eax_imm32(0xFF); set_register_state(r4300, EAX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1); #endif } void gen_LH(struct r4300_core* r4300) { #ifdef INTERPRET_LH gencallinterp(r4300, (unsigned int)cached_interp_LH, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); jump_end_rel8(r4300); } je_rj(95); mov_m32_imm32((unsigned int *)&(*r4300_pc_struct(r4300)), (unsigned int)(r4300->recomp.dst+1)); // 10 /* if non RDRAM read, * compute shift (ECX) and address (EBX) to perform a regular read * Save ECX content to memory as ECX can be overwritten when calling read32 function */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 2); // 6 xor_reg32_imm32(ECX, 2); // 6 shl_reg32_imm8(ECX, 3); // 3 mov_m32_reg32((unsigned int *)&r4300->recomp.shift, ECX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.rdword), (unsigned int)r4300->recomp.dst->f.i.rt); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_word); // 5 call_reg32(EBX); // 2 and_reg32_reg32(EAX, EAX); // 2 je_rj(51); // 2 mov_reg32_m32(EAX, (unsigned int *)r4300->recomp.dst->f.i.rt); // 6 mov_reg32_m32(ECX, (unsigned int *)&r4300->recomp.shift); // 6 shr_reg32_cl(EAX); // 2 and_reg32_imm32(EAX, 0xffff); // 6 mov_m32_reg32((unsigned int*)r4300->recomp.dst->f.i.rt, EAX); // 6 movsx_reg32_m16(EAX, (unsigned short *)r4300->recomp.dst->f.i.rt); // 7 jmp_imm_short(16); // 2 /* else (RDRAM read), read hword */ and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 2); // 3 movsx_reg32_16preg32pimm32(EAX, EBX, (unsigned int)r4300->rdram->dram); // 7 set_register_state(r4300, EAX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1); #endif } void gen_LHU(struct r4300_core* r4300) { #ifdef INTERPRET_LHU gencallinterp(r4300, (unsigned int)cached_interp_LHU, 0); #else free_all_registers(r4300); simplify_access(r4300); /* get address in both EAX and EBX */ mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); jump_end_rel8(r4300); } je_rj(76); mov_m32_imm32((unsigned int *)&(*r4300_pc_struct(r4300)), (unsigned int)(r4300->recomp.dst+1)); // 10 /* if non RDRAM read, * compute shift (ECX) and address (EBX) to perform a regular read * Save ECX content to memory as ECX can be overwritten when calling read32 function */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 2); // 6 xor_reg32_imm32(ECX, 2); // 6 shl_reg32_imm8(ECX, 3); // 3 mov_m32_reg32((unsigned int *)&r4300->recomp.shift, ECX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.rdword), (unsigned int)r4300->recomp.dst->f.i.rt); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_word); // 5 call_reg32(EBX); // 2 and_reg32_reg32(EAX, EAX); // 2 je_rj(31); // 2 mov_reg32_m32(EAX, (unsigned int *)r4300->recomp.dst->f.i.rt); // 6 mov_reg32_m32(ECX, (unsigned int *)&r4300->recomp.shift); // 6 shr_reg32_cl(EAX); // 2 jmp_imm_short(15); // 2 /* else (RDRAM read), read hword */ and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 2); // 3 mov_reg32_preg32pimm32(EAX, EBX, (unsigned int)r4300->rdram->dram); // 6 and_eax_imm32(0xFFFF); set_register_state(r4300, EAX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1); #endif } void gen_LL(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_LL, 0); } void gen_LW(struct r4300_core* r4300) { #ifdef INTERPRET_LW gencallinterp(r4300, (unsigned int)cached_interp_LW, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); jump_end_rel8(r4300); } je_rj(40); mov_m32_imm32((unsigned int *)&(*r4300_pc_struct(r4300)), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.rdword), (unsigned int)r4300->recomp.dst->f.i.rt); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_word); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(r4300->recomp.dst->f.i.rt)); // 5 jmp_imm_short(12); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg32_preg32pimm32(EAX, EBX, (unsigned int)r4300->rdram->dram); // 6 set_register_state(r4300, EAX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1); #endif } void gen_LWU(struct r4300_core* r4300) { #ifdef INTERPRET_LWU gencallinterp(r4300, (unsigned int)cached_interp_LWU, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); jump_end_rel8(r4300); } je_rj(40); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.rdword), (unsigned int)r4300->recomp.dst->f.i.rt); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_word); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(r4300->recomp.dst->f.i.rt)); // 5 jmp_imm_short(12); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg32_preg32pimm32(EAX, EBX, (unsigned int)r4300->rdram->dram); // 6 xor_reg32_reg32(EBX, EBX); set_64_register_state(r4300, EAX, EBX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1); #endif } void gen_LWL(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_LWL, 0); } void gen_LWR(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_LWR, 0); } void gen_LD(struct r4300_core* r4300) { #ifdef INTERPRET_LD gencallinterp(r4300, (unsigned int)cached_interp_LD, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); jump_end_rel8(r4300); } je_rj(46); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.rdword), (unsigned int)r4300->recomp.dst->f.i.rt); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_dword); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(r4300->recomp.dst->f.i.rt)); // 5 mov_reg32_m32(ECX, (unsigned int *)(r4300->recomp.dst->f.i.rt)+1); // 6 jmp_imm_short(18); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg32_preg32pimm32(EAX, EBX, ((unsigned int)r4300->rdram->dram)+4); // 6 mov_reg32_preg32pimm32(ECX, EBX, ((unsigned int)r4300->rdram->dram)); // 6 set_64_register_state(r4300, EAX, ECX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1); #endif } void gen_LDL(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_LDL, 0); } void gen_LDR(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_LDR, 0); } /* Store instructions */ void gen_SB(struct r4300_core* r4300) { #ifdef INTERPRET_SB gencallinterp(r4300, (unsigned int)cached_interp_SB, 0); #else free_all_registers(r4300); simplify_access(r4300); /* get value in EDX */ xor_reg32_reg32(EDX, EDX); mov_reg8_m8(DL, (unsigned char *)r4300->recomp.dst->f.i.rt); /* get address in both EAX and EBX */ mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].write32); cmp_reg32_imm32(EAX, (unsigned int)write_rdram_dram); jump_end_rel8(r4300); } je_rj(68); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 /* if non RDRAM write, * compute shift (ECX), word (EDX), wmask (EDX) and address (EBX) to perform a regular write */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 3); // 6 xor_reg32_imm32(ECX, 3); // 6 shl_reg32_imm8(ECX, 3); // 3 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 shl_reg32_cl(EDX); // 2 mov_m32_reg32((unsigned int *)(&r4300->recomp.wword), EDX); // 6 mov_reg32_imm32(EDX, 0xff); // 5 shl_reg32_cl(EDX); // 2 mov_m32_reg32((unsigned int *)(&r4300->recomp.wmask), EDX); // 6 mov_reg32_imm32(EBX, (unsigned int)dynarec_write_aligned_word); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(&r4300->recomp.address)); // 5 jmp_imm_short(17); // 2 /* else (RDRAM write), write byte */ mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 3); // 3 mov_preg32pimm32_reg8(EBX, (unsigned int)r4300->rdram->dram, DL); // 6 mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg32pimm32_imm8(EBX, (unsigned int)r4300->cached_interp.invalid_code, 0); jne_rj(54); mov_reg32_reg32(ECX, EBX); // 2 shl_reg32_imm8(EBX, 2); // 3 mov_reg32_preg32pimm32(EBX, EBX, (unsigned int)r4300->cached_interp.blocks); // 6 mov_reg32_preg32pimm32(EBX, EBX, (int)&r4300->cached_interp.actual->block - (int)r4300->cached_interp.actual); // 6 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg32_preg32preg32pimm32(EAX, EAX, EBX, (int)&r4300->recomp.dst->ops - (int)r4300->recomp.dst); // 7 cmp_reg32_imm32(EAX, (unsigned int)dynarec_notcompiled); // 6 je_rj(7); // 2 mov_preg32pimm32_imm8(ECX, (unsigned int)r4300->cached_interp.invalid_code, 1); // 7 #endif } void gen_SH(struct r4300_core* r4300) { #ifdef INTERPRET_SH gencallinterp(r4300, (unsigned int)cached_interp_SH, 0); #else free_all_registers(r4300); simplify_access(r4300); /* get value in EDX */ xor_reg32_reg32(EDX, EDX); mov_reg16_m16(DX, (unsigned short *)r4300->recomp.dst->f.i.rt); /* get address in both EAX and EBX */ mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].write32); cmp_reg32_imm32(EAX, (unsigned int)write_rdram_dram); jump_end_rel8(r4300); } je_rj(68); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 /* if non RDRAM write, * compute shift (ECX), word (EDX), wmask (EDX) and address (EBX) to perform a regular write */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 2); // 6 xor_reg32_imm32(ECX, 2); // 6 shl_reg32_imm8(ECX, 3); // 3 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 shl_reg32_cl(EDX); // 2 mov_m32_reg32((unsigned int *)(&r4300->recomp.wword), EDX); // 6 mov_reg32_imm32(EDX, 0xffff); // 5 shl_reg32_cl(EDX); // 2 mov_m32_reg32((unsigned int *)(&r4300->recomp.wmask), EDX); // 6 mov_reg32_imm32(EBX, (unsigned int)dynarec_write_aligned_word); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(&r4300->recomp.address)); // 5 jmp_imm_short(18); // 2 /* else (RDRAM write), write hword */ mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 2); // 3 mov_preg32pimm32_reg16(EBX, (unsigned int)r4300->rdram->dram, DX); // 7 mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg32pimm32_imm8(EBX, (unsigned int)r4300->cached_interp.invalid_code, 0); jne_rj(54); mov_reg32_reg32(ECX, EBX); // 2 shl_reg32_imm8(EBX, 2); // 3 mov_reg32_preg32pimm32(EBX, EBX, (unsigned int)r4300->cached_interp.blocks); // 6 mov_reg32_preg32pimm32(EBX, EBX, (int)&r4300->cached_interp.actual->block - (int)r4300->cached_interp.actual); // 6 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg32_preg32preg32pimm32(EAX, EAX, EBX, (int)&r4300->recomp.dst->ops - (int)r4300->recomp.dst); // 7 cmp_reg32_imm32(EAX, (unsigned int)dynarec_notcompiled); // 6 je_rj(7); // 2 mov_preg32pimm32_imm8(ECX, (unsigned int)r4300->cached_interp.invalid_code, 1); // 7 #endif } void gen_SC(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_SC, 0); } void gen_SW(struct r4300_core* r4300) { #ifdef INTERPRET_SW gencallinterp(r4300, (unsigned int)cached_interp_SW, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_reg32_m32(ECX, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].write32); cmp_reg32_imm32(EAX, (unsigned int)write_rdram_dram); jump_end_rel8(r4300); } je_rj(46); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.wword), ECX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.wmask), ~UINT32_C(0)); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_write_aligned_word); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(&r4300->recomp.address)); // 5 jmp_imm_short(14); // 2 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg32pimm32_reg32(EBX, (unsigned int)r4300->rdram->dram, ECX); // 6 mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg32pimm32_imm8(EBX, (unsigned int)r4300->cached_interp.invalid_code, 0); jne_rj(54); mov_reg32_reg32(ECX, EBX); // 2 shl_reg32_imm8(EBX, 2); // 3 mov_reg32_preg32pimm32(EBX, EBX, (unsigned int)r4300->cached_interp.blocks); // 6 mov_reg32_preg32pimm32(EBX, EBX, (int)&r4300->cached_interp.actual->block - (int)r4300->cached_interp.actual); // 6 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg32_preg32preg32pimm32(EAX, EAX, EBX, (int)&r4300->recomp.dst->ops - (int)r4300->recomp.dst); // 7 cmp_reg32_imm32(EAX, (unsigned int)dynarec_notcompiled); // 6 je_rj(7); // 2 mov_preg32pimm32_imm8(ECX, (unsigned int)r4300->cached_interp.invalid_code, 1); // 7 #endif } void gen_SWL(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_SWL, 0); } void gen_SWR(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_SWR, 0); } void gen_SD(struct r4300_core* r4300) { #ifdef INTERPRET_SD gencallinterp(r4300, (unsigned int)cached_interp_SD, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_reg32_m32(ECX, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_m32(EDX, ((unsigned int *)r4300->recomp.dst->f.i.rt)+1); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].write32); cmp_reg32_imm32(EAX, (unsigned int)write_rdram_dram); jump_end_rel8(r4300); } je_rj(42); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.wdword), ECX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.wdword)+1, EDX); // 6 mov_reg32_imm32(EBX, (unsigned int)dynarec_write_aligned_dword); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(&r4300->recomp.address)); // 5 jmp_imm_short(20); // 2 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg32pimm32_reg32(EBX, ((unsigned int)r4300->rdram->dram)+4, ECX); // 6 mov_preg32pimm32_reg32(EBX, ((unsigned int)r4300->rdram->dram)+0, EDX); // 6 mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg32pimm32_imm8(EBX, (unsigned int)r4300->cached_interp.invalid_code, 0); jne_rj(54); mov_reg32_reg32(ECX, EBX); // 2 shl_reg32_imm8(EBX, 2); // 3 mov_reg32_preg32pimm32(EBX, EBX, (unsigned int)r4300->cached_interp.blocks); // 6 mov_reg32_preg32pimm32(EBX, EBX, (int)&r4300->cached_interp.actual->block - (int)r4300->cached_interp.actual); // 6 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg32_preg32preg32pimm32(EAX, EAX, EBX, (int)&r4300->recomp.dst->ops - (int)r4300->recomp.dst); // 7 cmp_reg32_imm32(EAX, (unsigned int)dynarec_notcompiled); // 6 je_rj(7); // 2 mov_preg32pimm32_imm8(ECX, (unsigned int)r4300->cached_interp.invalid_code, 1); // 7 #endif } void gen_SDL(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_SDL, 0); } void gen_SDR(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_SDR, 0); } /* Computational instructions */ void gen_ADD(struct r4300_core* r4300) { #ifdef INTERPRET_ADD gencallinterp(r4300, (unsigned int)cached_interp_ADD, 0); #else int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(rd, rs); add_reg32_reg32(rd, rt); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs); add_reg32_reg32(temp, rt); mov_reg32_reg32(rd, temp); } #endif } void gen_ADDU(struct r4300_core* r4300) { #ifdef INTERPRET_ADDU gencallinterp(r4300, (unsigned int)cached_interp_ADDU, 0); #else int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(rd, rs); add_reg32_reg32(rd, rt); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs); add_reg32_reg32(temp, rt); mov_reg32_reg32(rd, temp); } #endif } void gen_ADDI(struct r4300_core* r4300) { #ifdef INTERPRET_ADDI gencallinterp(r4300, (unsigned int)cached_interp_ADDI, 0); #else int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt, rs); add_reg32_imm32(rt,(int)r4300->recomp.dst->f.i.immediate); #endif } void gen_ADDIU(struct r4300_core* r4300) { #ifdef INTERPRET_ADDIU gencallinterp(r4300, (unsigned int)cached_interp_ADDIU, 0); #else int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt, rs); add_reg32_imm32(rt,(int)r4300->recomp.dst->f.i.immediate); #endif } void gen_DADD(struct r4300_core* r4300) { #ifdef INTERPRET_DADD gencallinterp(r4300, (unsigned int)cached_interp_DADD, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); add_reg32_reg32(rd1, rt1); adc_reg32_reg32(rd2, rt2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); add_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); adc_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif } void gen_DADDU(struct r4300_core* r4300) { #ifdef INTERPRET_DADDU gencallinterp(r4300, (unsigned int)cached_interp_DADDU, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); add_reg32_reg32(rd1, rt1); adc_reg32_reg32(rd2, rt2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); add_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); adc_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif } void gen_DADDI(struct r4300_core* r4300) { #ifdef INTERPRET_DADDI gencallinterp(r4300, (unsigned int)cached_interp_DADDI, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); int rt2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt1, rs1); mov_reg32_reg32(rt2, rs2); add_reg32_imm32(rt1, r4300->recomp.dst->f.i.immediate); adc_reg32_imm32(rt2, (int)r4300->recomp.dst->f.i.immediate>>31); #endif } void gen_DADDIU(struct r4300_core* r4300) { #ifdef INTERPRET_DADDIU gencallinterp(r4300, (unsigned int)cached_interp_DADDIU, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); int rt2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt1, rs1); mov_reg32_reg32(rt2, rs2); add_reg32_imm32(rt1, r4300->recomp.dst->f.i.immediate); adc_reg32_imm32(rt2, (int)r4300->recomp.dst->f.i.immediate>>31); #endif } void gen_SUB(struct r4300_core* r4300) { #ifdef INTERPRET_SUB gencallinterp(r4300, (unsigned int)cached_interp_SUB, 0); #else int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs); sub_reg32_reg32(temp, rt); mov_reg32_reg32(rd, temp); } #endif } void gen_SUBU(struct r4300_core* r4300) { #ifdef INTERPRET_SUBU gencallinterp(r4300, (unsigned int)cached_interp_SUBU, 0); #else int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt != rd && rs != rd) { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs); sub_reg32_reg32(temp, rt); mov_reg32_reg32(rd, temp); } #endif } void gen_DSUB(struct r4300_core* r4300) { #ifdef INTERPRET_DSUB gencallinterp(r4300, (unsigned int)cached_interp_DSUB, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); sub_reg32_reg32(rd1, rt1); sbb_reg32_reg32(rd2, rt2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); sub_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); sbb_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif } void gen_DSUBU(struct r4300_core* r4300) { #ifdef INTERPRET_DSUBU gencallinterp(r4300, (unsigned int)cached_interp_DSUBU, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); sub_reg32_reg32(rd1, rt1); sbb_reg32_reg32(rd2, rt2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); sub_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); sbb_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif } void gen_SLT(struct r4300_core* r4300) { #ifdef INTERPRET_SLT gencallinterp(r4300, (unsigned int)cached_interp_SLT, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); cmp_reg32_reg32(rs2, rt2); jl_rj(13); jne_rj(4); // 2 cmp_reg32_reg32(rs1, rt1); // 2 jl_rj(7); // 2 mov_reg32_imm32(rd, 0); // 5 jmp_imm_short(5); // 2 mov_reg32_imm32(rd, 1); // 5 #endif } void gen_SLTU(struct r4300_core* r4300) { #ifdef INTERPRET_SLTU gencallinterp(r4300, (unsigned int)cached_interp_SLTU, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); cmp_reg32_reg32(rs2, rt2); jb_rj(13); jne_rj(4); // 2 cmp_reg32_reg32(rs1, rt1); // 2 jb_rj(7); // 2 mov_reg32_imm32(rd, 0); // 5 jmp_imm_short(5); // 2 mov_reg32_imm32(rd, 1); // 5 #endif } void gen_SLTI(struct r4300_core* r4300) { #ifdef INTERPRET_SLTI gencallinterp(r4300, (unsigned int)cached_interp_SLTI, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); long long imm = (long long)r4300->recomp.dst->f.i.immediate; cmp_reg32_imm32(rs2, (unsigned int)(imm >> 32)); jl_rj(17); jne_rj(8); // 2 cmp_reg32_imm32(rs1, (unsigned int)imm); // 6 jl_rj(7); // 2 mov_reg32_imm32(rt, 0); // 5 jmp_imm_short(5); // 2 mov_reg32_imm32(rt, 1); // 5 #endif } void gen_SLTIU(struct r4300_core* r4300) { #ifdef INTERPRET_SLTIU gencallinterp(r4300, (unsigned int)cached_interp_SLTIU, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); long long imm = (long long)r4300->recomp.dst->f.i.immediate; cmp_reg32_imm32(rs2, (unsigned int)(imm >> 32)); jb_rj(17); jne_rj(8); // 2 cmp_reg32_imm32(rs1, (unsigned int)imm); // 6 jb_rj(7); // 2 mov_reg32_imm32(rt, 0); // 5 jmp_imm_short(5); // 2 mov_reg32_imm32(rt, 1); // 5 #endif } void gen_AND(struct r4300_core* r4300) { #ifdef INTERPRET_AND gencallinterp(r4300, (unsigned int)cached_interp_AND, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); and_reg32_reg32(rd1, rt1); and_reg32_reg32(rd2, rt2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); and_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); and_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif } void gen_ANDI(struct r4300_core* r4300) { #ifdef INTERPRET_ANDI gencallinterp(r4300, (unsigned int)cached_interp_ANDI, 0); #else int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt, rs); and_reg32_imm32(rt, (unsigned short)r4300->recomp.dst->f.i.immediate); #endif } void gen_OR(struct r4300_core* r4300) { #ifdef INTERPRET_OR gencallinterp(r4300, (unsigned int)cached_interp_OR, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); or_reg32_reg32(rd1, rt1); or_reg32_reg32(rd2, rt2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); or_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); or_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif } void gen_ORI(struct r4300_core* r4300) { #ifdef INTERPRET_ORI gencallinterp(r4300, (unsigned int)cached_interp_ORI, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); int rt2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt1, rs1); mov_reg32_reg32(rt2, rs2); or_reg32_imm32(rt1, (unsigned short)r4300->recomp.dst->f.i.immediate); #endif } void gen_XOR(struct r4300_core* r4300) { #ifdef INTERPRET_XOR gencallinterp(r4300, (unsigned int)cached_interp_XOR, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); xor_reg32_reg32(rd1, rt1); xor_reg32_reg32(rd2, rt2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); xor_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); xor_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); } #endif } void gen_XORI(struct r4300_core* r4300) { #ifdef INTERPRET_XORI gencallinterp(r4300, (unsigned int)cached_interp_XORI, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); int rt2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt1, rs1); mov_reg32_reg32(rt2, rs2); xor_reg32_imm32(rt1, (unsigned short)r4300->recomp.dst->f.i.immediate); #endif } void gen_NOR(struct r4300_core* r4300) { #ifdef INTERPRET_NOR gencallinterp(r4300, (unsigned int)cached_interp_NOR, 0); #else int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rt1 != rd1 && rs1 != rd1) { mov_reg32_reg32(rd1, rs1); mov_reg32_reg32(rd2, rs2); or_reg32_reg32(rd1, rt1); or_reg32_reg32(rd2, rt2); not_reg32(rd1); not_reg32(rd2); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rs1); or_reg32_reg32(temp, rt1); mov_reg32_reg32(rd1, temp); mov_reg32_reg32(temp, rs2); or_reg32_reg32(temp, rt2); mov_reg32_reg32(rd2, temp); not_reg32(rd1); not_reg32(rd2); } #endif } void gen_LUI(struct r4300_core* r4300) { #ifdef INTERPRET_LUI gencallinterp(r4300, (unsigned int)cached_interp_LUI, 0); #else int rt = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_imm32(rt, (unsigned int)r4300->recomp.dst->f.i.immediate << 16); #endif } /* Shift instructions */ void gen_NOP(struct r4300_core* r4300) { } void gen_SLL(struct r4300_core* r4300) { #ifdef INTERPRET_SLL gencallinterp(r4300, (unsigned int)cached_interp_SLL, 0); #else int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd, rt); shl_reg32_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_SLLV(struct r4300_core* r4300) { #ifdef INTERPRET_SLLV gencallinterp(r4300, (unsigned int)cached_interp_SLLV, 0); #else int rt, rd; allocate_register_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg32_reg32(rd, rt); shl_reg32_cl(rd); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rt); shl_reg32_cl(temp); mov_reg32_reg32(rd, temp); } #endif } void gen_DSLL(struct r4300_core* r4300) { #ifdef INTERPRET_DSLL gencallinterp(r4300, (unsigned int)cached_interp_DSLL, 0); #else int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shld_reg32_reg32_imm8(rd2, rd1, r4300->recomp.dst->f.r.sa); shl_reg32_imm8(rd1, r4300->recomp.dst->f.r.sa); if (r4300->recomp.dst->f.r.sa & 0x20) { mov_reg32_reg32(rd2, rd1); xor_reg32_reg32(rd1, rd1); } #endif } void gen_DSLLV(struct r4300_core* r4300) { #ifdef INTERPRET_DSLLV gencallinterp(r4300, (unsigned int)cached_interp_DSLLV, 0); #else int rt1, rt2, rd1, rd2; allocate_register_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd1 != ECX && rd2 != ECX) { mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shld_reg32_reg32_cl(rd2,rd1); shl_reg32_cl(rd1); test_reg32_imm32(ECX, 0x20); je_rj(4); mov_reg32_reg32(rd2, rd1); // 2 xor_reg32_reg32(rd1, rd1); // 2 } else { int temp1, temp2; temp1 = lru_register(r4300); temp2 = lru_register_exc1(r4300, temp1); free_register(r4300, temp1); free_register(r4300, temp2); mov_reg32_reg32(temp1, rt1); mov_reg32_reg32(temp2, rt2); shld_reg32_reg32_cl(temp2, temp1); shl_reg32_cl(temp1); test_reg32_imm32(ECX, 0x20); je_rj(4); mov_reg32_reg32(temp2, temp1); // 2 xor_reg32_reg32(temp1, temp1); // 2 mov_reg32_reg32(rd1, temp1); mov_reg32_reg32(rd2, temp2); } #endif } void gen_DSLL32(struct r4300_core* r4300) { #ifdef INTERPRET_DSLL32 gencallinterp(r4300, (unsigned int)cached_interp_DSLL32, 0); #else int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd2, rt1); shl_reg32_imm8(rd2, r4300->recomp.dst->f.r.sa); xor_reg32_reg32(rd1, rd1); #endif } void gen_SRL(struct r4300_core* r4300) { #ifdef INTERPRET_SRL gencallinterp(r4300, (unsigned int)cached_interp_SRL, 0); #else int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd, rt); shr_reg32_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_SRLV(struct r4300_core* r4300) { #ifdef INTERPRET_SRLV gencallinterp(r4300, (unsigned int)cached_interp_SRLV, 0); #else int rt, rd; allocate_register_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg32_reg32(rd, rt); shr_reg32_cl(rd); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rt); shr_reg32_cl(temp); mov_reg32_reg32(rd, temp); } #endif } void gen_DSRL(struct r4300_core* r4300) { #ifdef INTERPRET_DSRL gencallinterp(r4300, (unsigned int)cached_interp_DSRL, 0); #else int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shrd_reg32_reg32_imm8(rd1, rd2, r4300->recomp.dst->f.r.sa); shr_reg32_imm8(rd2, r4300->recomp.dst->f.r.sa); if (r4300->recomp.dst->f.r.sa & 0x20) { mov_reg32_reg32(rd1, rd2); xor_reg32_reg32(rd2, rd2); } #endif } void gen_DSRLV(struct r4300_core* r4300) { #ifdef INTERPRET_DSRLV gencallinterp(r4300, (unsigned int)cached_interp_DSRLV, 0); #else int rt1, rt2, rd1, rd2; allocate_register_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd1 != ECX && rd2 != ECX) { mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shrd_reg32_reg32_cl(rd1,rd2); shr_reg32_cl(rd2); test_reg32_imm32(ECX, 0x20); je_rj(4); mov_reg32_reg32(rd1, rd2); // 2 xor_reg32_reg32(rd2, rd2); // 2 } else { int temp1, temp2; temp1 = lru_register(r4300); temp2 = lru_register_exc1(r4300, temp1); free_register(r4300, temp1); free_register(r4300, temp2); mov_reg32_reg32(temp1, rt1); mov_reg32_reg32(temp2, rt2); shrd_reg32_reg32_cl(temp1, temp2); shr_reg32_cl(temp2); test_reg32_imm32(ECX, 0x20); je_rj(4); mov_reg32_reg32(temp1, temp2); // 2 xor_reg32_reg32(temp2, temp2); // 2 mov_reg32_reg32(rd1, temp1); mov_reg32_reg32(rd2, temp2); } #endif } void gen_DSRL32(struct r4300_core* r4300) { #ifdef INTERPRET_DSRL32 gencallinterp(r4300, (unsigned int)cached_interp_DSRL32, 0); #else int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd1, rt2); shr_reg32_imm8(rd1, r4300->recomp.dst->f.r.sa); xor_reg32_reg32(rd2, rd2); #endif } void gen_SRA(struct r4300_core* r4300) { #ifdef INTERPRET_SRA gencallinterp(r4300, (unsigned int)cached_interp_SRA, 0); #else int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd, rt); sar_reg32_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_SRAV(struct r4300_core* r4300) { #ifdef INTERPRET_SRAV gencallinterp(r4300, (unsigned int)cached_interp_SRAV, 0); #else int rt, rd; allocate_register_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg32_reg32(rd, rt); sar_reg32_cl(rd); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rt); sar_reg32_cl(temp); mov_reg32_reg32(rd, temp); } #endif } void gen_DSRA(struct r4300_core* r4300) { #ifdef INTERPRET_DSRA gencallinterp(r4300, (unsigned int)cached_interp_DSRA, 0); #else int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shrd_reg32_reg32_imm8(rd1, rd2, r4300->recomp.dst->f.r.sa); sar_reg32_imm8(rd2, r4300->recomp.dst->f.r.sa); if (r4300->recomp.dst->f.r.sa & 0x20) { mov_reg32_reg32(rd1, rd2); sar_reg32_imm8(rd2, 31); } #endif } void gen_DSRAV(struct r4300_core* r4300) { #ifdef INTERPRET_DSRAV gencallinterp(r4300, (unsigned int)cached_interp_DSRAV, 0); #else int rt1, rt2, rd1, rd2; allocate_register_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd1 = allocate_64_register1_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); rd2 = allocate_64_register2_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd1 != ECX && rd2 != ECX) { mov_reg32_reg32(rd1, rt1); mov_reg32_reg32(rd2, rt2); shrd_reg32_reg32_cl(rd1,rd2); sar_reg32_cl(rd2); test_reg32_imm32(ECX, 0x20); je_rj(5); mov_reg32_reg32(rd1, rd2); // 2 sar_reg32_imm8(rd2, 31); // 3 } else { int temp1, temp2; temp1 = lru_register(r4300); temp2 = lru_register_exc1(r4300, temp1); free_register(r4300, temp1); free_register(r4300, temp2); mov_reg32_reg32(temp1, rt1); mov_reg32_reg32(temp2, rt2); shrd_reg32_reg32_cl(temp1, temp2); sar_reg32_cl(temp2); test_reg32_imm32(ECX, 0x20); je_rj(5); mov_reg32_reg32(temp1, temp2); // 2 sar_reg32_imm8(temp2, 31); // 3 mov_reg32_reg32(rd1, temp1); mov_reg32_reg32(rd2, temp2); } #endif } void gen_DSRA32(struct r4300_core* r4300) { #ifdef INTERPRET_DSRA32 gencallinterp(r4300, (unsigned int)cached_interp_DSRA32, 0); #else int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd, rt2); sar_reg32_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } /* Multiply / Divide instructions */ void gen_MULT(struct r4300_core* r4300) { #ifdef INTERPRET_MULT gencallinterp(r4300, (unsigned int)cached_interp_MULT, 0); #else int rs, rt; allocate_register_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300), 0); allocate_register_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300), 0); rs = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); mov_reg32_reg32(EAX, rs); imul_reg32(rt); #endif } void gen_MULTU(struct r4300_core* r4300) { #ifdef INTERPRET_MULTU gencallinterp(r4300, (unsigned int)cached_interp_MULTU, 0); #else int rs, rt; allocate_register_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300), 0); allocate_register_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300), 0); rs = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); mov_reg32_reg32(EAX, rs); mul_reg32(rt); #endif } void gen_DMULT(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_DMULT, 0); } void gen_DMULTU(struct r4300_core* r4300) { #ifdef INTERPRET_DMULTU gencallinterp(r4300, (unsigned int)cached_interp_DMULTU, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.r.rs); mul_m32((unsigned int *)r4300->recomp.dst->f.r.rt); // EDX:EAX = temp1 mov_memoffs32_eax((unsigned int *)(r4300_mult_lo(r4300))); mov_reg32_reg32(EBX, EDX); // EBX = temp1>>32 mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.r.rs); mul_m32((unsigned int *)(r4300->recomp.dst->f.r.rt)+1); add_reg32_reg32(EBX, EAX); adc_reg32_imm32(EDX, 0); mov_reg32_reg32(ECX, EDX); // ECX:EBX = temp2 mov_eax_memoffs32((unsigned int *)(r4300->recomp.dst->f.r.rs)+1); mul_m32((unsigned int *)r4300->recomp.dst->f.r.rt); // EDX:EAX = temp3 add_reg32_reg32(EBX, EAX); adc_reg32_imm32(ECX, 0); // ECX:EBX = result2 mov_m32_reg32((unsigned int*)(r4300_mult_lo(r4300))+1, EBX); mov_reg32_reg32(ESI, EDX); // ESI = temp3>>32 mov_eax_memoffs32((unsigned int *)(r4300->recomp.dst->f.r.rs)+1); mul_m32((unsigned int *)(r4300->recomp.dst->f.r.rt)+1); add_reg32_reg32(EAX, ESI); adc_reg32_imm32(EDX, 0); // EDX:EAX = temp4 add_reg32_reg32(EAX, ECX); adc_reg32_imm32(EDX, 0); // EDX:EAX = result3 mov_memoffs32_eax((unsigned int *)(r4300_mult_hi(r4300))); mov_m32_reg32((unsigned int *)(r4300_mult_hi(r4300))+1, EDX); #endif } void gen_DIV(struct r4300_core* r4300) { #ifdef INTERPRET_DIV gencallinterp(r4300, (unsigned int)cached_interp_DIV, 0); #else int rs, rt; allocate_register_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300), 0); allocate_register_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300), 0); rs = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); cmp_reg32_imm32(rt, 0); je_rj((rs == EAX ? 0 : 2) + 1 + 2); mov_reg32_reg32(EAX, rs); // 0 or 2 cdq(); // 1 idiv_reg32(rt); // 2 #endif } void gen_DIVU(struct r4300_core* r4300) { #ifdef INTERPRET_DIVU gencallinterp(r4300, (unsigned int)cached_interp_DIVU, 0); #else int rs, rt; allocate_register_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300), 0); allocate_register_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300), 0); rs = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); cmp_reg32_imm32(rt, 0); je_rj((rs == EAX ? 0 : 2) + 2 + 2); mov_reg32_reg32(EAX, rs); // 0 or 2 xor_reg32_reg32(EDX, EDX); // 2 div_reg32(rt); // 2 #endif } void gen_DDIV(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_DDIV, 0); } void gen_DDIVU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_DDIVU, 0); } void gen_MFHI(struct r4300_core* r4300) { #ifdef INTERPRET_MFHI gencallinterp(r4300, (unsigned int)cached_interp_MFHI, 0); #else int rd1 = allocate_64_register1_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rd); int hi1 = allocate_64_register1(r4300, (unsigned int*)r4300_mult_hi(r4300)); int hi2 = allocate_64_register2(r4300, (unsigned int*)r4300_mult_hi(r4300)); mov_reg32_reg32(rd1, hi1); mov_reg32_reg32(rd2, hi2); #endif } void gen_MTHI(struct r4300_core* r4300) { #ifdef INTERPRET_MTHI gencallinterp(r4300, (unsigned int)cached_interp_MTHI, 0); #else int hi1 = allocate_64_register1_w(r4300, (unsigned int*)r4300_mult_hi(r4300)); int hi2 = allocate_64_register2_w(r4300, (unsigned int*)r4300_mult_hi(r4300)); int rs1 = allocate_64_register1(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); mov_reg32_reg32(hi1, rs1); mov_reg32_reg32(hi2, rs2); #endif } void gen_MFLO(struct r4300_core* r4300) { #ifdef INTERPRET_MFLO gencallinterp(r4300, (unsigned int)cached_interp_MFLO, 0); #else int rd1 = allocate_64_register1_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rd); int rd2 = allocate_64_register2_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rd); int lo1 = allocate_64_register1(r4300, (unsigned int*)r4300_mult_lo(r4300)); int lo2 = allocate_64_register2(r4300, (unsigned int*)r4300_mult_lo(r4300)); mov_reg32_reg32(rd1, lo1); mov_reg32_reg32(rd2, lo2); #endif } void gen_MTLO(struct r4300_core* r4300) { #ifdef INTERPRET_MTLO gencallinterp(r4300, (unsigned int)cached_interp_MTLO, 0); #else int lo1 = allocate_64_register1_w(r4300, (unsigned int*)r4300_mult_lo(r4300)); int lo2 = allocate_64_register2_w(r4300, (unsigned int*)r4300_mult_lo(r4300)); int rs1 = allocate_64_register1(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); int rs2 = allocate_64_register2(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); mov_reg32_reg32(lo1, rs1); mov_reg32_reg32(lo2, rs2); #endif } /* Jump & Branch instructions */ static void gentest(struct r4300_core* r4300) { cmp_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt(r4300, (unsigned int)(r4300->recomp.dst + (r4300->recomp.dst-1)->f.i.immediate)); jmp(r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); jump_end_rel32(r4300); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned int)(r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void gentest_out(struct r4300_core* r4300) { cmp_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt_out(r4300, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_m32_imm32(&r4300->recomp.jump_to_address, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); mov_reg32_imm32(EAX, (unsigned int)dynarec_jump_to_recomp_address); call_reg32(EAX); jump_end_rel32(r4300); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned int)(r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void gentest_idle(struct r4300_core* r4300) { int reg; reg = lru_register(r4300); free_register(r4300, reg); cmp_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); mov_reg32_m32(reg, (unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(reg, reg); jns_rj(16); sub_m32_reg32((unsigned int *)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), reg); // 6 mov_m32_imm32((unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0)), 0); //10 jump_end_rel32(r4300); } static void gentestl(struct r4300_core* r4300) { cmp_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); gendelayslot(r4300); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt(r4300, (unsigned int)(r4300->recomp.dst + (r4300->recomp.dst-1)->f.i.immediate)); jmp(r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); jump_end_rel32(r4300); gencp0_update_count(r4300, r4300->recomp.dst->addr+4); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned int)(r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void gentestl_out(struct r4300_core* r4300) { cmp_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); gendelayslot(r4300); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt_out(r4300, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_m32_imm32(&r4300->recomp.jump_to_address, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); mov_reg32_imm32(EAX, (unsigned int)dynarec_jump_to_recomp_address); call_reg32(EAX); jump_end_rel32(r4300); gencp0_update_count(r4300, r4300->recomp.dst->addr+4); mov_m32_imm32(&r4300->cp0.last_addr, r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned int)(r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void genbranchlink(struct r4300_core* r4300) { int r31_64bit = is64(r4300, (unsigned int*)&r4300_regs(r4300)[31]); if (!r31_64bit) { int r31 = allocate_register_w(r4300, (unsigned int *)&r4300_regs(r4300)[31]); mov_reg32_imm32(r31, r4300->recomp.dst->addr+8); } else if (r31_64bit == -1) { mov_m32_imm32((unsigned int *)&r4300_regs(r4300)[31], r4300->recomp.dst->addr + 8); if (r4300->recomp.dst->addr & 0x80000000) { mov_m32_imm32(((unsigned int *)&r4300_regs(r4300)[31])+1, 0xFFFFFFFF); } else { mov_m32_imm32(((unsigned int *)&r4300_regs(r4300)[31])+1, 0); } } else { int r311 = allocate_64_register1_w(r4300, (unsigned int *)&r4300_regs(r4300)[31]); int r312 = allocate_64_register2_w(r4300, (unsigned int *)&r4300_regs(r4300)[31]); mov_reg32_imm32(r311, r4300->recomp.dst->addr+8); if (r4300->recomp.dst->addr & 0x80000000) { mov_reg32_imm32(r312, 0xFFFFFFFF); } else { mov_reg32_imm32(r312, 0); } } } void gen_J(struct r4300_core* r4300) { #ifdef INTERPRET_J gencallinterp(r4300, (unsigned int)cached_interp_J, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_J, 1); return; } gendelayslot(r4300); naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32_imm32(&r4300->cp0.last_addr, naddr); gencheck_interrupt(r4300, (unsigned int)&r4300->cached_interp.actual->block[(naddr-r4300->cached_interp.actual->start)/4]); jmp(naddr); #endif } void gen_J_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_J_OUT gencallinterp(r4300, (unsigned int)cached_interp_J_OUT, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_J_OUT, 1); return; } gendelayslot(r4300); naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32_imm32(&r4300->cp0.last_addr, naddr); gencheck_interrupt_out(r4300, naddr); mov_m32_imm32(&r4300->recomp.jump_to_address, naddr); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); mov_reg32_imm32(EAX, (unsigned int)dynarec_jump_to_recomp_address); call_reg32(EAX); #endif } void gen_J_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_J_IDLE gencallinterp(r4300, (unsigned int)cached_interp_J_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_J_IDLE, 1); return; } mov_eax_memoffs32((unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(EAX, EAX); jns_rj(16); sub_m32_reg32((unsigned int *)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), EAX); // 6 mov_m32_imm32((unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0)), 0); //10 gen_J(r4300); #endif } void gen_JAL(struct r4300_core* r4300) { #ifdef INTERPRET_JAL gencallinterp(r4300, (unsigned int)cached_interp_JAL, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_JAL, 1); return; } gendelayslot(r4300); mov_m32_imm32((unsigned int *)(r4300_regs(r4300) + 31), r4300->recomp.dst->addr + 4); if (((r4300->recomp.dst->addr + 4) & 0x80000000)) { mov_m32_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0xFFFFFFFF); } else { mov_m32_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0); } naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32_imm32(&r4300->cp0.last_addr, naddr); gencheck_interrupt(r4300, (unsigned int)&r4300->cached_interp.actual->block[(naddr-r4300->cached_interp.actual->start)/4]); jmp(naddr); #endif } void gen_JAL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_JAL_OUT gencallinterp(r4300, (unsigned int)cached_interp_JAL_OUT, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_JAL_OUT, 1); return; } gendelayslot(r4300); mov_m32_imm32((unsigned int *)(r4300_regs(r4300) + 31), r4300->recomp.dst->addr + 4); if (((r4300->recomp.dst->addr + 4) & 0x80000000)) { mov_m32_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0xFFFFFFFF); } else { mov_m32_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0); } naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32_imm32(&r4300->cp0.last_addr, naddr); gencheck_interrupt_out(r4300, naddr); mov_m32_imm32(&r4300->recomp.jump_to_address, naddr); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); mov_reg32_imm32(EAX, (unsigned int)dynarec_jump_to_recomp_address); call_reg32(EAX); #endif } void gen_JAL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_JAL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_JAL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_JAL_IDLE, 1); return; } mov_eax_memoffs32((unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(EAX, EAX); jns_rj(16); sub_m32_reg32((unsigned int *)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), EAX); // 6 mov_m32_imm32((unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0)), 0); //10 gen_JAL(r4300); #endif } void gen_JR(struct r4300_core* r4300) { #ifdef INTERPRET_JR gencallinterp(r4300, (unsigned int)cached_interp_JR_OUT, 1); #else unsigned int diff = (unsigned int)(&r4300->recomp.dst->local_addr) - (unsigned int)(r4300->recomp.dst); unsigned int diff_need = (unsigned int)(&r4300->recomp.dst->reg_cache_infos.need_map) - (unsigned int)(r4300->recomp.dst); unsigned int diff_wrap = (unsigned int)(&r4300->recomp.dst->reg_cache_infos.jump_wrapper) - (unsigned int)(r4300->recomp.dst); if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_JR_OUT, 1); return; } free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.i.rs); mov_memoffs32_eax((unsigned int *)&r4300->recomp.local_rs); gendelayslot(r4300); mov_eax_memoffs32((unsigned int *)&r4300->recomp.local_rs); mov_memoffs32_eax((unsigned int *)&r4300->cp0.last_addr); gencheck_interrupt_reg(r4300); mov_eax_memoffs32((unsigned int *)&r4300->recomp.local_rs); mov_reg32_reg32(EBX, EAX); and_eax_imm32(0xFFFFF000); cmp_eax_imm32(r4300->recomp.dst_block->start & 0xFFFFF000); je_near_rj(0); jump_start_rel32(r4300); mov_m32_reg32(&r4300->recomp.jump_to_address, EBX); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); mov_reg32_imm32(EAX, (unsigned int)dynarec_jump_to_recomp_address); call_reg32(EAX); jump_end_rel32(r4300); mov_reg32_reg32(EAX, EBX); sub_eax_imm32(r4300->recomp.dst_block->start); shr_reg32_imm8(EAX, 2); mul_m32((unsigned int *)(&precomp_instr_size)); mov_reg32_preg32pimm32(EBX, EAX, (unsigned int)(r4300->recomp.dst_block->block)+diff_need); cmp_reg32_imm32(EBX, 1); jne_rj(7); add_eax_imm32((unsigned int)(r4300->recomp.dst_block->block)+diff_wrap); // 5 jmp_reg32(EAX); // 2 mov_reg32_preg32pimm32(EAX, EAX, (unsigned int)(r4300->recomp.dst_block->block)+diff); add_reg32_m32(EAX, (unsigned int *)(&r4300->recomp.dst_block->code)); jmp_reg32(EAX); #endif } void gen_JALR(struct r4300_core* r4300) { #ifdef INTERPRET_JALR gencallinterp(r4300, (unsigned int)cached_interp_JALR_OUT, 0); #else unsigned int diff = (unsigned int)(&r4300->recomp.dst->local_addr) - (unsigned int)(r4300->recomp.dst); unsigned int diff_need = (unsigned int)(&r4300->recomp.dst->reg_cache_infos.need_map) - (unsigned int)(r4300->recomp.dst); unsigned int diff_wrap = (unsigned int)(&r4300->recomp.dst->reg_cache_infos.jump_wrapper) - (unsigned int)(r4300->recomp.dst); if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_JALR_OUT, 1); return; } free_all_registers(r4300); simplify_access(r4300); mov_eax_memoffs32((unsigned int *)r4300->recomp.dst->f.r.rs); mov_memoffs32_eax((unsigned int *)&r4300->recomp.local_rs); gendelayslot(r4300); mov_m32_imm32((unsigned int *)(r4300->recomp.dst-1)->f.r.rd, r4300->recomp.dst->addr+4); if ((r4300->recomp.dst->addr+4) & 0x80000000) { mov_m32_imm32(((unsigned int *)(r4300->recomp.dst-1)->f.r.rd)+1, 0xFFFFFFFF); } else { mov_m32_imm32(((unsigned int *)(r4300->recomp.dst-1)->f.r.rd)+1, 0); } mov_eax_memoffs32((unsigned int *)&r4300->recomp.local_rs); mov_memoffs32_eax((unsigned int *)&r4300->cp0.last_addr); gencheck_interrupt_reg(r4300); mov_eax_memoffs32((unsigned int *)&r4300->recomp.local_rs); mov_reg32_reg32(EBX, EAX); and_eax_imm32(0xFFFFF000); cmp_eax_imm32(r4300->recomp.dst_block->start & 0xFFFFF000); je_near_rj(0); jump_start_rel32(r4300); mov_m32_reg32(&r4300->recomp.jump_to_address, EBX); mov_m32_imm32((unsigned int*)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); mov_reg32_imm32(EAX, (unsigned int)dynarec_jump_to_recomp_address); call_reg32(EAX); jump_end_rel32(r4300); mov_reg32_reg32(EAX, EBX); sub_eax_imm32(r4300->recomp.dst_block->start); shr_reg32_imm8(EAX, 2); mul_m32((unsigned int *)(&precomp_instr_size)); mov_reg32_preg32pimm32(EBX, EAX, (unsigned int)(r4300->recomp.dst_block->block)+diff_need); cmp_reg32_imm32(EBX, 1); jne_rj(7); add_eax_imm32((unsigned int)(r4300->recomp.dst_block->block)+diff_wrap); // 5 jmp_reg32(EAX); // 2 mov_reg32_preg32pimm32(EAX, EAX, (unsigned int)(r4300->recomp.dst_block->block)+diff); add_reg32_m32(EAX, (unsigned int *)(&r4300->recomp.dst_block->code)); jmp_reg32(EAX); #endif } static void genbeq_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); if (!rs_64bit && !rt_64bit) { int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); cmp_reg32_reg32(rs, rt); jne_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else if (rs_64bit == -1) { int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); cmp_reg32_m32(rt1, (unsigned int *)r4300->recomp.dst->f.i.rs); jne_rj(20); cmp_reg32_m32(rt2, ((unsigned int *)r4300->recomp.dst->f.i.rs)+1); // 6 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else if (rt_64bit == -1) { int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_m32(rs1, (unsigned int *)r4300->recomp.dst->f.i.rt); jne_rj(20); cmp_reg32_m32(rs2, ((unsigned int *)r4300->recomp.dst->f.i.rt)+1); // 6 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else { int rs1, rs2, rt1, rt2; if (!rs_64bit) { rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); } else { rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); } cmp_reg32_reg32(rs1, rt1); jne_rj(16); cmp_reg32_reg32(rs2, rt2); // 2 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } } void gen_BEQ(struct r4300_core* r4300) { #ifdef INTERPRET_BEQ gencallinterp(r4300, (unsigned int)cached_interp_BEQ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BEQ, 1); return; } genbeq_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BEQ_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BEQ_OUT gencallinterp(r4300, (unsigned int)cached_interp_BEQ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BEQ_OUT, 1); return; } genbeq_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BEQ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BEQ_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BEQ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BEQ_IDLE, 1); return; } genbeq_test(r4300); gentest_idle(r4300); gen_BEQ(r4300); #endif } void gen_BEQL(struct r4300_core* r4300) { #ifdef INTERPRET_BEQL gencallinterp(r4300, (unsigned int)cached_interp_BEQL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BEQL, 1); return; } genbeq_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BEQL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BEQL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BEQL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BEQL_OUT, 1); return; } genbeq_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BEQL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BEQL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BEQL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BEQL_IDLE, 1); return; } genbeq_test(r4300); gentest_idle(r4300); gen_BEQL(r4300); #endif } static void genbne_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); if (!rs_64bit && !rt_64bit) { int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); cmp_reg32_reg32(rs, rt); je_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else if (rs_64bit == -1) { int rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); int rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); cmp_reg32_m32(rt1, (unsigned int *)r4300->recomp.dst->f.i.rs); jne_rj(20); cmp_reg32_m32(rt2, ((unsigned int *)r4300->recomp.dst->f.i.rs)+1); // 6 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 } else if (rt_64bit == -1) { int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_m32(rs1, (unsigned int *)r4300->recomp.dst->f.i.rt); jne_rj(20); cmp_reg32_m32(rs2, ((unsigned int *)r4300->recomp.dst->f.i.rt)+1); // 6 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 } else { int rs1, rs2, rt1, rt2; if (!rs_64bit) { rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); } else { rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); rt1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); rt2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); } cmp_reg32_reg32(rs1, rt1); jne_rj(16); cmp_reg32_reg32(rs2, rt2); // 2 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 } } void gen_BNE(struct r4300_core* r4300) { #ifdef INTERPRET_BNE gencallinterp(r4300, (unsigned int)cached_interp_BNE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BNE, 1); return; } genbne_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BNE_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BNE_OUT gencallinterp(r4300, (unsigned int)cached_interp_BNE_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BNE_OUT, 1); return; } genbne_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BNE_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BNE_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BNE_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BNE_IDLE, 1); return; } genbne_test(r4300); gentest_idle(r4300); gen_BNE(r4300); #endif } void gen_BNEL(struct r4300_core* r4300) { #ifdef INTERPRET_BNEL gencallinterp(r4300, (unsigned int)cached_interp_BNEL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BNEL, 1); return; } genbne_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BNEL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BNEL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BNEL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BNEL_OUT, 1); return; } genbne_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BNEL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BNEL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BNEL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BNEL_IDLE, 1); return; } genbne_test(r4300); gentest_idle(r4300); gen_BNEL(r4300); #endif } static void genblez_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (!rs_64bit) { int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); jg_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else if (rs_64bit == -1) { cmp_m32_imm32(((unsigned int *)r4300->recomp.dst->f.i.rs)+1, 0); jg_rj(14); jne_rj(24); // 2 cmp_m32_imm32((unsigned int *)r4300->recomp.dst->f.i.rs, 0); // 10 je_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 } else { int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs2, 0); jg_rj(10); jne_rj(20); // 2 cmp_reg32_imm32(rs1, 0); // 6 je_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 } } void gen_BLEZ(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZ gencallinterp(r4300, (unsigned int)cached_interp_BLEZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLEZ, 1); return; } genblez_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BLEZ_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZ_OUT gencallinterp(r4300, (unsigned int)cached_interp_BLEZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLEZ_OUT, 1); return; } genblez_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BLEZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZ_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BLEZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLEZ_IDLE, 1); return; } genblez_test(r4300); gentest_idle(r4300); gen_BLEZ(r4300); #endif } void gen_BLEZL(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZL gencallinterp(r4300, (unsigned int)cached_interp_BLEZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLEZL, 1); return; } genblez_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BLEZL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BLEZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLEZL_OUT, 1); return; } genblez_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BLEZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BLEZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLEZL_IDLE, 1); return; } genblez_test(r4300); gentest_idle(r4300); gen_BLEZL(r4300); #endif } static void genbgtz_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (!rs_64bit) { int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); jle_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else if (rs_64bit == -1) { cmp_m32_imm32(((unsigned int *)r4300->recomp.dst->f.i.rs)+1, 0); jl_rj(14); jne_rj(24); // 2 cmp_m32_imm32((unsigned int *)r4300->recomp.dst->f.i.rs, 0); // 10 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 } else { int rs1 = allocate_64_register1(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs2, 0); jl_rj(10); jne_rj(20); // 2 cmp_reg32_imm32(rs1, 0); // 6 jne_rj(12); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 } } void gen_BGTZ(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZ gencallinterp(r4300, (unsigned int)cached_interp_BGTZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGTZ, 1); return; } genbgtz_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BGTZ_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZ_OUT gencallinterp(r4300, (unsigned int)cached_interp_BGTZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGTZ_OUT, 1); return; } genbgtz_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BGTZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZ_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BGTZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGTZ_IDLE, 1); return; } genbgtz_test(r4300); gentest_idle(r4300); gen_BGTZ(r4300); #endif } void gen_BGTZL(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZL gencallinterp(r4300, (unsigned int)cached_interp_BGTZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGTZL, 1); return; } genbgtz_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BGTZL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BGTZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGTZL_OUT, 1); return; } genbgtz_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BGTZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BGTZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGTZL_IDLE, 1); return; } genbgtz_test(r4300); gentest_idle(r4300); gen_BGTZL(r4300); #endif } static void genbltz_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (!rs_64bit) { int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); jge_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else if (rs_64bit == -1) { cmp_m32_imm32(((unsigned int *)r4300->recomp.dst->f.i.rs)+1, 0); jge_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else { int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs2, 0); jge_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } } void gen_BLTZ(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZ gencallinterp(r4300, (unsigned int)cached_interp_BLTZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZ, 1); return; } genbltz_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BLTZ_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZ_OUT gencallinterp(r4300, (unsigned int)cached_interp_BLTZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZ_OUT, 1); return; } genbltz_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BLTZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZ_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BLTZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZ_IDLE, 1); return; } genbltz_test(r4300); gentest_idle(r4300); gen_BLTZ(r4300); #endif } void gen_BLTZAL(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZAL gencallinterp(r4300, (unsigned int)cached_interp_BLTZAL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZAL, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BLTZAL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZAL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BLTZAL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZAL_OUT, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BLTZAL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZAL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BLTZAL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZAL_IDLE, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BLTZAL(r4300); #endif } void gen_BLTZL(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZL gencallinterp(r4300, (unsigned int)cached_interp_BLTZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZL, 1); return; } genbltz_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BLTZL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BLTZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZL_OUT, 1); return; } genbltz_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BLTZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BLTZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZL_IDLE, 1); return; } genbltz_test(r4300); gentest_idle(r4300); gen_BLTZL(r4300); #endif } void gen_BLTZALL(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZALL gencallinterp(r4300, (unsigned int)cached_interp_BLTZALL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZALL, 1); return; } genbltz_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BLTZALL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZALL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BLTZALL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZALL_OUT, 1); return; } genbltz_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BLTZALL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZALL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BLTZALL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BLTZALL_IDLE, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BLTZALL(r4300); #endif } static void genbgez_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (!rs_64bit) { int rs = allocate_register(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); jl_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else if (rs_64bit == -1) { cmp_m32_imm32(((unsigned int *)r4300->recomp.dst->f.i.rs)+1, 0); jl_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } else { int rs2 = allocate_64_register2(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs2, 0); jl_rj(12); mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); // 10 } } void gen_BGEZ(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZ gencallinterp(r4300, (unsigned int)cached_interp_BGEZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZ, 1); return; } genbgez_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BGEZ_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZ_OUT gencallinterp(r4300, (unsigned int)cached_interp_BGEZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZ_OUT, 1); return; } genbgez_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BGEZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZ_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BGEZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZ_IDLE, 1); return; } genbgez_test(r4300); gentest_idle(r4300); gen_BGEZ(r4300); #endif } void gen_BGEZAL(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZAL gencallinterp(r4300, (unsigned int)cached_interp_BGEZAL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZAL, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BGEZAL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZAL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BGEZAL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZAL_OUT, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BGEZAL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZAL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BGEZAL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZAL_IDLE, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BGEZAL(r4300); #endif } void gen_BGEZL(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZL gencallinterp(r4300, (unsigned int)cached_interp_BGEZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZL, 1); return; } genbgez_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BGEZL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BGEZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZL_OUT, 1); return; } genbgez_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BGEZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BGEZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZL_IDLE, 1); return; } genbgez_test(r4300); gentest_idle(r4300); gen_BGEZL(r4300); #endif } void gen_BGEZALL(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZALL gencallinterp(r4300, (unsigned int)cached_interp_BGEZALL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZALL, 1); return; } genbgez_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BGEZALL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZALL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BGEZALL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZALL_OUT, 1); return; } genbgez_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BGEZALL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZALL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BGEZALL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BGEZALL_IDLE, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BGEZALL(r4300); #endif } static void genbc1f_test(struct r4300_core* r4300) { test_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); jne_rj(12); mov_m32_imm32((unsigned int*)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int*)(&r4300->recomp.branch_taken), 0); // 10 } void gen_BC1F(struct r4300_core* r4300) { #ifdef INTERPRET_BC1F gencallinterp(r4300, (unsigned int)cached_interp_BC1F, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1F, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BC1F_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BC1F_OUT gencallinterp(r4300, (unsigned int)cached_interp_BC1F_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1F_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BC1F_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1F_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BC1F_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1F_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gentest_idle(r4300); gen_BC1F(r4300); #endif } void gen_BC1FL(struct r4300_core* r4300) { #ifdef INTERPRET_BC1FL gencallinterp(r4300, (unsigned int)cached_interp_BC1FL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1FL, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BC1FL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BC1FL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BC1FL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1FL_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BC1FL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1FL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BC1FL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1FL_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gentest_idle(r4300); gen_BC1FL(r4300); #endif } static void genbc1t_test(struct r4300_core* r4300) { test_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); je_rj(12); mov_m32_imm32((unsigned int*)(&r4300->recomp.branch_taken), 1); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int*)(&r4300->recomp.branch_taken), 0); // 10 } void gen_BC1T(struct r4300_core* r4300) { #ifdef INTERPRET_BC1T gencallinterp(r4300, (unsigned int)cached_interp_BC1T, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1T, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BC1T_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BC1T_OUT gencallinterp(r4300, (unsigned int)cached_interp_BC1T_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1T_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BC1T_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1T_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BC1T_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1T_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gentest_idle(r4300); gen_BC1T(r4300); #endif } void gen_BC1TL(struct r4300_core* r4300) { #ifdef INTERPRET_BC1TL gencallinterp(r4300, (unsigned int)cached_interp_BC1TL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1TL, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BC1TL_OUT(struct r4300_core* r4300) { #ifdef INTERPRET_BC1TL_OUT gencallinterp(r4300, (unsigned int)cached_interp_BC1TL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1TL_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BC1TL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1TL_IDLE gencallinterp(r4300, (unsigned int)cached_interp_BC1TL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned int)cached_interp_BC1TL_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gentest_idle(r4300); gen_BC1TL(r4300); #endif } /* Special instructions */ void gen_CACHE(struct r4300_core* r4300) { } void gen_ERET(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_ERET, 1); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); genupdate_system(r4300, 0); mov_reg32_imm32(EAX, (unsigned int)(ERET)); call_reg32(EAX); mov_reg32_imm32(EAX, (unsigned int)(jump_code)); jmp_reg32(EAX); #endif } void gen_SYNC(struct r4300_core* r4300) { } void gen_SYSCALL(struct r4300_core* r4300) { #ifdef INTERPRET_SYSCALL gencallinterp(r4300, (unsigned int)cached_interp_SYSCALL, 0); #else free_all_registers(r4300); simplify_access(r4300); mov_m32_imm32(&r4300_cp0_regs(&r4300->cp0)[CP0_CAUSE_REG], 8 << 2); gencallinterp(r4300, (unsigned int)dynarec_exception_general, 0); #endif } /* Trap instructions */ void gen_TGE(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TGE, 0); } void gen_TGEU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TGEU, 0); } void gen_TGEI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TGEI, 0); } void gen_TGEIU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TGEIU, 0); } void gen_TLT(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLT, 0); } void gen_TLTU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLTU, 0); } void gen_TLTI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLTI, 0); } void gen_TLTIU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLTIU, 0); } void gen_TEQ(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TEQ, 0); } void gen_TEQI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TEQI, 0); } void gen_TNE(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TNE, 0); } void gen_TNEI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TNEI, 0); } /* TLB instructions */ void gen_TLBP(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLBP, 0); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); mov_reg32_imm32(EAX, (unsigned int)(TLBP)); call_reg32(EAX); genupdate_system(r4300, 0); #endif } void gen_TLBR(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLBR, 0); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); mov_reg32_imm32(EAX, (unsigned int)(TLBR)); call_reg32(EAX); genupdate_system(r4300, 0); #endif } void gen_TLBWR(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLBWR, 0); } void gen_TLBWI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_TLBWI, 0); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); mov_reg32_imm32(EAX, (unsigned int)(TLBWI)); call_reg32(EAX); genupdate_system(r4300, 0); #endif } /* CP0 load/store instructions */ void gen_MFC0(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_MFC0, 0); } void gen_MTC0(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned int)cached_interp_MTC0, 0); } /* CP1 load/store instructions */ void gen_LWC1(struct r4300_core* r4300) { #ifdef INTERPRET_LWC1 gencallinterp(r4300, (unsigned int)cached_interp_LWC1, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); if (r4300->recomp.fast_memory) { and_eax_imm32(0xDF800000); cmp_eax_imm32(0x80000000); } else { shr_reg32_imm8(EAX, 16); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); } je_rj(37); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_reg32_m32(EDX, (unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.rdword), EDX); // 6 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_word); // 5 call_reg32(EBX); // 2 jmp_imm_short(20); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg32_preg32pimm32(EAX, EBX, (unsigned int)r4300->rdram->dram); // 6 mov_reg32_m32(EBX, (unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 6 mov_preg32_reg32(EBX, EAX); // 2 #endif } void gen_LDC1(struct r4300_core* r4300) { #ifdef INTERPRET_LDC1 gencallinterp(r4300, (unsigned int)cached_interp_LDC1, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); if (r4300->recomp.fast_memory) { and_eax_imm32(0xDF800000); cmp_eax_imm32(0x80000000); } else { shr_reg32_imm8(EAX, 16); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].read32); cmp_reg32_imm32(EAX, (unsigned int)read_rdram_dram); } je_rj(37); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_reg32_m32(EDX, (unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.rdword), EDX); // 6 mov_reg32_imm32(EBX, (unsigned int)dynarec_read_aligned_dword); // 5 call_reg32(EBX); // 2 jmp_imm_short(32); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg32_preg32pimm32(EAX, EBX, ((unsigned int)r4300->rdram->dram)+4); // 6 mov_reg32_preg32pimm32(ECX, EBX, ((unsigned int)r4300->rdram->dram)); // 6 mov_reg32_m32(EBX, (unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 6 mov_preg32_reg32(EBX, EAX); // 2 mov_preg32pimm32_reg32(EBX, 4, ECX); // 6 #endif } void gen_SWC1(struct r4300_core* r4300) { #ifdef INTERPRET_SWC1 gencallinterp(r4300, (unsigned int)cached_interp_SWC1, 0); #else gencheck_cop1_unusable(r4300); mov_reg32_m32(EDX, (unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); mov_reg32_preg32(ECX, EDX); mov_eax_memoffs32((unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].write32); cmp_reg32_imm32(EAX, (unsigned int)write_rdram_dram); jump_end_rel8(r4300); } je_rj(46); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.wword), ECX); // 6 mov_m32_imm32((unsigned int *)(&r4300->recomp.wmask), ~UINT32_C(0)); // 10 mov_reg32_imm32(EBX, (unsigned int)dynarec_write_aligned_word); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(&r4300->recomp.address)); // 5 jmp_imm_short(14); // 2 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg32pimm32_reg32(EBX, (unsigned int)r4300->rdram->dram, ECX); // 6 mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg32pimm32_imm8(EBX, (unsigned int)r4300->cached_interp.invalid_code, 0); jne_rj(54); mov_reg32_reg32(ECX, EBX); // 2 shl_reg32_imm8(EBX, 2); // 3 mov_reg32_preg32pimm32(EBX, EBX, (unsigned int)r4300->cached_interp.blocks); // 6 mov_reg32_preg32pimm32(EBX, EBX, (int)&r4300->cached_interp.actual->block - (int)r4300->cached_interp.actual); // 6 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg32_preg32preg32pimm32(EAX, EAX, EBX, (int)&r4300->recomp.dst->ops - (int)r4300->recomp.dst); // 7 cmp_reg32_imm32(EAX, (unsigned int)dynarec_notcompiled); // 6 je_rj(7); // 2 mov_preg32pimm32_imm8(ECX, (unsigned int)r4300->cached_interp.invalid_code, 1); // 7 #endif } void gen_SDC1(struct r4300_core* r4300) { #ifdef INTERPRET_SDC1 gencallinterp(r4300, (unsigned int)cached_interp_SDC1, 0); #else gencheck_cop1_unusable(r4300); mov_reg32_m32(ESI, (unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); mov_reg32_preg32(ECX, ESI); mov_reg32_preg32pimm32(EDX, ESI, 4); mov_eax_memoffs32((unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg32_imm8(EAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg32_preg32x2preg32(EAX, EAX, EAX); mov_reg32_preg32x4pimm32(EAX, EAX, (unsigned int)r4300->mem->handlers[0].write32); cmp_reg32_imm32(EAX, (unsigned int)write_rdram_dram); jump_end_rel8(r4300); } je_rj(42); mov_m32_imm32((unsigned int *)(&(*r4300_pc_struct(r4300))), (unsigned int)(r4300->recomp.dst+1)); // 10 mov_m32_reg32((unsigned int *)(&r4300->recomp.address), EBX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.wdword), ECX); // 6 mov_m32_reg32((unsigned int *)(&r4300->recomp.wdword)+1, EDX); // 6 mov_reg32_imm32(EBX, (unsigned int)dynarec_write_aligned_dword); // 5 call_reg32(EBX); // 2 mov_eax_memoffs32((unsigned int *)(&r4300->recomp.address)); // 5 jmp_imm_short(20); // 2 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg32pimm32_reg32(EBX, ((unsigned int)r4300->rdram->dram)+4, ECX); // 6 mov_preg32pimm32_reg32(EBX, ((unsigned int)r4300->rdram->dram)+0, EDX); // 6 mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg32pimm32_imm8(EBX, (unsigned int)r4300->cached_interp.invalid_code, 0); jne_rj(54); mov_reg32_reg32(ECX, EBX); // 2 shl_reg32_imm8(EBX, 2); // 3 mov_reg32_preg32pimm32(EBX, EBX, (unsigned int)r4300->cached_interp.blocks); // 6 mov_reg32_preg32pimm32(EBX, EBX, (int)&r4300->cached_interp.actual->block - (int)r4300->cached_interp.actual); // 6 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg32_preg32preg32pimm32(EAX, EAX, EBX, (int)&r4300->recomp.dst->ops - (int)r4300->recomp.dst); // 7 cmp_reg32_imm32(EAX, (unsigned int)dynarec_notcompiled); // 6 je_rj(7); // 2 mov_preg32pimm32_imm8(ECX, (unsigned int)r4300->cached_interp.invalid_code, 1); // 7 #endif } void gen_MFC1(struct r4300_core* r4300) { #ifdef INTERPRET_MFC1 gencallinterp(r4300, (unsigned int)cached_interp_MFC1, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_reg32_preg32(EBX, EAX); mov_m32_reg32((unsigned int*)r4300->recomp.dst->f.r.rt, EBX); sar_reg32_imm8(EBX, 31); mov_m32_reg32(((unsigned int*)r4300->recomp.dst->f.r.rt)+1, EBX); #endif } void gen_DMFC1(struct r4300_core* r4300) { #ifdef INTERPRET_DMFC1 gencallinterp(r4300, (unsigned int)cached_interp_DMFC1, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_reg32_preg32(EBX, EAX); mov_reg32_preg32pimm32(ECX, EAX, 4); mov_m32_reg32((unsigned int*)r4300->recomp.dst->f.r.rt, EBX); mov_m32_reg32(((unsigned int*)r4300->recomp.dst->f.r.rt)+1, ECX); #endif } void gen_CFC1(struct r4300_core* r4300) { #ifdef INTERPRET_CFC1 gencallinterp(r4300, (unsigned int)cached_interp_CFC1, 0); #else gencheck_cop1_unusable(r4300); if (r4300->recomp.dst->f.r.nrd == 31) { mov_eax_memoffs32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1))); } else { mov_eax_memoffs32((unsigned int*)&(*r4300_cp1_fcr0(&r4300->cp1))); } mov_memoffs32_eax((unsigned int*)r4300->recomp.dst->f.r.rt); sar_reg32_imm8(EAX, 31); mov_memoffs32_eax(((unsigned int*)r4300->recomp.dst->f.r.rt)+1); #endif } void gen_MTC1(struct r4300_core* r4300) { #ifdef INTERPRET_MTC1 gencallinterp(r4300, (unsigned int)cached_interp_MTC1, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)r4300->recomp.dst->f.r.rt); mov_reg32_m32(EBX, (unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_preg32_reg32(EBX, EAX); #endif } void gen_DMTC1(struct r4300_core* r4300) { #ifdef INTERPRET_DMTC1 gencallinterp(r4300, (unsigned int)cached_interp_DMTC1, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)r4300->recomp.dst->f.r.rt); mov_reg32_m32(EBX, ((unsigned int*)r4300->recomp.dst->f.r.rt)+1); mov_reg32_m32(EDX, (unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_preg32_reg32(EDX, EAX); mov_preg32pimm32_reg32(EDX, 4, EBX); #endif } void gen_CTC1(struct r4300_core* r4300) { #ifdef INTERPRET_CTC1 gencallinterp(r4300, (unsigned int)cached_interp_CTC1, 0); #else gencheck_cop1_unusable(r4300); if (r4300->recomp.dst->f.r.nrd != 31) { return; } mov_eax_memoffs32((unsigned int*)r4300->recomp.dst->f.r.rt); mov_memoffs32_eax((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1))); and_eax_imm32(3); cmp_eax_imm32(0); jne_rj(12); mov_m32_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0x33F); // 10 jmp_imm_short(48); // 2 cmp_eax_imm32(1); // 5 jne_rj(12); // 2 mov_m32_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0xF3F); // 10 jmp_imm_short(29); // 2 cmp_eax_imm32(2); // 5 jne_rj(12); // 2 mov_m32_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0xB3F); // 10 jmp_imm_short(10); // 2 mov_m32_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0x73F); // 10 fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } /* CP1 computational instructions */ void gen_CP1_ABS_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ABS_S gencallinterp(r4300, (unsigned int)cached_interp_ABS_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fabs_(); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_ABS_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ABS_D gencallinterp(r4300, (unsigned int)cached_interp_ABS_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fabs_(); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_ADD_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ADD_S gencallinterp(r4300, (unsigned int)cached_interp_ADD_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fadd_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_ADD_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ADD_D gencallinterp(r4300, (unsigned int)cached_interp_ADD_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fadd_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_DIV_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_DIV_S gencallinterp(r4300, (unsigned int)cached_interp_DIV_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fdiv_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_DIV_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_DIV_D gencallinterp(r4300, (unsigned int)cached_interp_DIV_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fdiv_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_MOV_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_MOV_S gencallinterp(r4300, (unsigned int)cached_interp_MOV_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); mov_reg32_preg32(EBX, EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); mov_preg32_reg32(EAX, EBX); #endif } void gen_CP1_MOV_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_MOV_D gencallinterp(r4300, (unsigned int)cached_interp_MOV_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); mov_reg32_preg32(EBX, EAX); mov_reg32_preg32pimm32(ECX, EAX, 4); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); mov_preg32_reg32(EAX, EBX); mov_preg32pimm32_reg32(EAX, 4, ECX); #endif } void gen_CP1_MUL_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_MUL_S gencallinterp(r4300, (unsigned int)cached_interp_MUL_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fmul_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_MUL_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_MUL_D gencallinterp(r4300, (unsigned int)cached_interp_MUL_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fmul_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_NEG_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_NEG_S gencallinterp(r4300, (unsigned int)cached_interp_NEG_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fchs(); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_NEG_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_NEG_D gencallinterp(r4300, (unsigned int)cached_interp_NEG_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fchs(); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_SQRT_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_SQRT_S gencallinterp(r4300, (unsigned int)cached_interp_SQRT_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fsqrt(); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_SQRT_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_SQRT_D gencallinterp(r4300, (unsigned int)cached_interp_SQRT_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fsqrt(); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_SUB_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_SUB_S gencallinterp(r4300, (unsigned int)cached_interp_SUB_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fsub_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_SUB_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_SUB_D gencallinterp(r4300, (unsigned int)cached_interp_SUB_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fsub_preg32_qword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_TRUNC_W_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_TRUNC_W_S gencallinterp(r4300, (unsigned int)cached_interp_TRUNC_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&trunc_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_TRUNC_W_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_TRUNC_W_D gencallinterp(r4300, (unsigned int)cached_interp_TRUNC_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&trunc_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_TRUNC_L_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_TRUNC_L_S gencallinterp(r4300, (unsigned int)cached_interp_TRUNC_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&trunc_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_TRUNC_L_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_TRUNC_L_D gencallinterp(r4300, (unsigned int)cached_interp_TRUNC_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&trunc_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_W_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ROUND_W_S gencallinterp(r4300, (unsigned int)cached_interp_ROUND_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&round_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_W_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ROUND_W_D gencallinterp(r4300, (unsigned int)cached_interp_ROUND_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&round_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_L_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ROUND_L_S gencallinterp(r4300, (unsigned int)cached_interp_ROUND_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&round_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_L_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_ROUND_L_D gencallinterp(r4300, (unsigned int)cached_interp_ROUND_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&round_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_W_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CEIL_W_S gencallinterp(r4300, (unsigned int)cached_interp_CEIL_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&ceil_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_W_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CEIL_W_D gencallinterp(r4300, (unsigned int)cached_interp_CEIL_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&ceil_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_L_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CEIL_L_S gencallinterp(r4300, (unsigned int)cached_interp_CEIL_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&ceil_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_L_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CEIL_L_D gencallinterp(r4300, (unsigned int)cached_interp_CEIL_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&ceil_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_W_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_FLOOR_W_S gencallinterp(r4300, (unsigned int)cached_interp_FLOOR_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&floor_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_W_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_FLOOR_W_D gencallinterp(r4300, (unsigned int)cached_interp_FLOOR_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&floor_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_L_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_FLOOR_L_S gencallinterp(r4300, (unsigned int)cached_interp_FLOOR_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&floor_mode); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_L_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_FLOOR_L_D gencallinterp(r4300, (unsigned int)cached_interp_FLOOR_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16((unsigned short*)&floor_mode); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); fldcw_m16((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CVT_S_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_S_D gencallinterp(r4300, (unsigned int)cached_interp_CVT_S_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_CVT_S_W(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_S_W gencallinterp(r4300, (unsigned int)cached_interp_CVT_S_W, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg32_dword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_CVT_S_L(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_S_L gencallinterp(r4300, (unsigned int)cached_interp_CVT_S_L, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_dword(EAX); #endif } void gen_CP1_CVT_D_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_D_S gencallinterp(r4300, (unsigned int)cached_interp_CVT_D_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_CVT_D_W(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_D_W gencallinterp(r4300, (unsigned int)cached_interp_CVT_D_W, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg32_dword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_CVT_D_L(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_D_L gencallinterp(r4300, (unsigned int)cached_interp_CVT_D_L, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg32_qword(EAX); #endif } void gen_CP1_CVT_W_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_W_S gencallinterp(r4300, (unsigned int)cached_interp_CVT_W_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); #endif } void gen_CP1_CVT_W_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_W_D gencallinterp(r4300, (unsigned int)cached_interp_CVT_W_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_dword(EAX); #endif } void gen_CP1_CVT_L_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_L_S gencallinterp(r4300, (unsigned int)cached_interp_CVT_L_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); #endif } void gen_CP1_CVT_L_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_CVT_L_D gencallinterp(r4300, (unsigned int)cached_interp_CVT_L_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg32_qword(EAX); #endif } /* CP1 relational instructions */ void gen_CP1_C_F_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_F_S gencallinterp(r4300, (unsigned int)cached_interp_C_F_S, 0); #else gencheck_cop1_unusable(r4300); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_F_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_F_D gencallinterp(r4300, (unsigned int)cached_interp_C_F_D, 0); #else gencheck_cop1_unusable(r4300); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_UN_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_UN_S gencallinterp(r4300, (unsigned int)cached_interp_C_UN_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(12); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 jmp_imm_short(10); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 #endif } void gen_CP1_C_UN_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_UN_D gencallinterp(r4300, (unsigned int)cached_interp_C_UN_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(12); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 jmp_imm_short(10); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 #endif } void gen_CP1_C_EQ_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_EQ_S gencallinterp(r4300, (unsigned int)cached_interp_C_EQ_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jne_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_EQ_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_EQ_D gencallinterp(r4300, (unsigned int)cached_interp_C_EQ_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jne_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_UEQ_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_UEQ_S gencallinterp(r4300, (unsigned int)cached_interp_C_UEQ_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jne_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_UEQ_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_UEQ_D gencallinterp(r4300, (unsigned int)cached_interp_C_UEQ_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jne_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_OLT_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_OLT_S gencallinterp(r4300, (unsigned int)cached_interp_C_OLT_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jae_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_OLT_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_OLT_D gencallinterp(r4300, (unsigned int)cached_interp_C_OLT_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jae_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_ULT_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_ULT_S gencallinterp(r4300, (unsigned int)cached_interp_C_ULT_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jae_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_ULT_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_ULT_D gencallinterp(r4300, (unsigned int)cached_interp_C_ULT_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jae_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_OLE_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_OLE_S gencallinterp(r4300, (unsigned int)cached_interp_C_OLE_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fucomip_fpreg(1); ffree_fpreg(0); ja_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_OLE_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_OLE_D gencallinterp(r4300, (unsigned int)cached_interp_C_OLE_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fucomip_fpreg(1); ffree_fpreg(0); ja_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_ULE_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_ULE_S gencallinterp(r4300, (unsigned int)cached_interp_C_ULE_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(14); ja_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_ULE_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_ULE_D gencallinterp(r4300, (unsigned int)cached_interp_C_ULE_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(14); ja_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_SF_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_SF_S gencallinterp(r4300, (unsigned int)cached_interp_C_SF_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_SF_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_SF_D gencallinterp(r4300, (unsigned int)cached_interp_C_SF_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_NGLE_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGLE_S gencallinterp(r4300, (unsigned int)cached_interp_C_NGLE_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(12); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 jmp_imm_short(10); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 #endif } void gen_CP1_C_NGLE_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGLE_D gencallinterp(r4300, (unsigned int)cached_interp_C_NGLE_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(12); and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 jmp_imm_short(10); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 #endif } void gen_CP1_C_SEQ_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_SEQ_S gencallinterp(r4300, (unsigned int)cached_interp_C_SEQ_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jne_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_SEQ_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_SEQ_D gencallinterp(r4300, (unsigned int)cached_interp_C_SEQ_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jne_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_NGL_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGL_S gencallinterp(r4300, (unsigned int)cached_interp_C_NGL_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jne_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_NGL_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGL_D gencallinterp(r4300, (unsigned int)cached_interp_C_NGL_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jne_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_LT_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_LT_S gencallinterp(r4300, (unsigned int)cached_interp_C_LT_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jae_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_LT_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_LT_D gencallinterp(r4300, (unsigned int)cached_interp_C_LT_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jae_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_NGE_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGE_S gencallinterp(r4300, (unsigned int)cached_interp_C_NGE_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jae_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_NGE_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGE_D gencallinterp(r4300, (unsigned int)cached_interp_C_NGE_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(14); jae_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_LE_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_LE_S gencallinterp(r4300, (unsigned int)cached_interp_C_LE_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); ja_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_LE_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_LE_D gencallinterp(r4300, (unsigned int)cached_interp_C_LE_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); ja_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_NGT_S(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGT_S gencallinterp(r4300, (unsigned int)cached_interp_C_NGT_S, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_dword(EAX); mov_eax_memoffs32((unsigned int *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_dword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(14); ja_rj(12); or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } void gen_CP1_C_NGT_D(struct r4300_core* r4300) { #ifdef INTERPRET_CP1_C_NGT_D gencallinterp(r4300, (unsigned int)cached_interp_C_NGT_D, 0); #else gencheck_cop1_unusable(r4300); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg32_qword(EAX); mov_eax_memoffs32((unsigned int*)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg32_qword(EAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(14); ja_rj(12); // 2 or_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 10 jmp_imm_short(10); // 2 and_m32_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 10 #endif } mupen64plus-core-src-2.6.0/src/device/r4300/x86/interpret.h000066400000000000000000000170211464506436200230570ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - interpret.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_X86_INTERPRET_H #define M64P_DEVICE_R4300_X86_INTERPRET_H //#define INTERPRET_J //#define INTERPRET_J_OUT //#define INTERPRET_J_IDLE //#define INTERPRET_JAL //#define INTERPRET_JAL_OUT //#define INTERPRET_JAL_IDLE //#define INTERPRET_BEQ //#define INTERPRET_BEQ_OUT //#define INTERPRET_BEQ_IDLE //#define INTERPRET_BNE //#define INTERPRET_BNE_OUT //#define INTERPRET_BNE_IDLE //#define INTERPRET_BLEZ //#define INTERPRET_BLEZ_OUT //#define INTERPRET_BLEZ_IDLE //#define INTERPRET_BGTZ //#define INTERPRET_BGTZ_OUT //#define INTERPRET_BGTZ_IDLE //#define INTERPRET_ADDI //#define INTERPRET_ADDIU //#define INTERPRET_SLTI //#define INTERPRET_SLTIU //#define INTERPRET_ANDI //#define INTERPRET_ORI //#define INTERPRET_XORI //#define INTERPRET_LUI //#define INTERPRET_BEQL //#define INTERPRET_BEQL_OUT //#define INTERPRET_BEQL_IDLE //#define INTERPRET_BNEL //#define INTERPRET_BNEL_OUT //#define INTERPRET_BNEL_IDLE //#define INTERPRET_BLEZL //#define INTERPRET_BLEZL_OUT //#define INTERPRET_BLEZL_IDLE //#define INTERPRET_BGTZL //#define INTERPRET_BGTZL_OUT //#define INTERPRET_BGTZL_IDLE //#define INTERPRET_DADDI //#define INTERPRET_DADDIU //#define INTERPRET_LB //#define INTERPRET_LH //#define INTERPRET_LW //#define INTERPRET_LBU //#define INTERPRET_LHU //#define INTERPRET_LWU //#define INTERPRET_SB //#define INTERPRET_SH //#define INTERPRET_SW //#define INTERPRET_LWC1 //#define INTERPRET_LDC1 //#define INTERPRET_LD //#define INTERPRET_SWC1 //#define INTERPRET_SDC1 //#define INTERPRET_SD //#define INTERPRET_SLL //#define INTERPRET_SRL //#define INTERPRET_SRA //#define INTERPRET_SLLV //#define INTERPRET_SRLV //#define INTERPRET_SRAV //#define INTERPRET_JR //#define INTERPRET_JALR //#define INTERPRET_SYSCALL //#define INTERPRET_MFHI //#define INTERPRET_MTHI //#define INTERPRET_MFLO //#define INTERPRET_MTLO //#define INTERPRET_DSLLV //#define INTERPRET_DSRLV //#define INTERPRET_DSRAV //#define INTERPRET_MULT //#define INTERPRET_MULTU //#define INTERPRET_DIV //#define INTERPRET_DIVU //#define INTERPRET_DMULTU //#define INTERPRET_ADD //#define INTERPRET_ADDU //#define INTERPRET_SUB //#define INTERPRET_SUBU //#define INTERPRET_AND //#define INTERPRET_OR //#define INTERPRET_XOR //#define INTERPRET_NOR //#define INTERPRET_SLT //#define INTERPRET_SLTU //#define INTERPRET_DADD //#define INTERPRET_DADDU //#define INTERPRET_DSUB //#define INTERPRET_DSUBU //#define INTERPRET_DSLL //#define INTERPRET_DSRL //#define INTERPRET_DSRA //#define INTERPRET_DSLL32 //#define INTERPRET_DSRL32 //#define INTERPRET_DSRA32 //#define INTERPRET_BLTZ //#define INTERPRET_BLTZ_OUT //#define INTERPRET_BLTZ_IDLE //#define INTERPRET_BGEZ //#define INTERPRET_BGEZ_OUT //#define INTERPRET_BGEZ_IDLE //#define INTERPRET_BLTZL //#define INTERPRET_BLTZL_OUT //#define INTERPRET_BLTZL_IDLE //#define INTERPRET_BGEZL //#define INTERPRET_BGEZL_OUT //#define INTERPRET_BGEZL_IDLE //#define INTERPRET_BLTZAL //#define INTERPRET_BLTZAL_OUT //#define INTERPRET_BLTZAL_IDLE //#define INTERPRET_BGEZAL //#define INTERPRET_BGEZAL_OUT //#define INTERPRET_BGEZAL_IDLE //#define INTERPRET_BLTZALL //#define INTERPRET_BLTZALL_OUT //#define INTERPRET_BLTZALL_IDLE //#define INTERPRET_BGEZALL //#define INTERPRET_BGEZALL_OUT //#define INTERPRET_BGEZALL_IDLE //#define INTERPRET_BC1F //#define INTERPRET_BC1F_OUT //#define INTERPRET_BC1F_IDLE //#define INTERPRET_BC1T //#define INTERPRET_BC1T_OUT //#define INTERPRET_BC1T_IDLE //#define INTERPRET_BC1FL //#define INTERPRET_BC1FL_OUT //#define INTERPRET_BC1FL_IDLE //#define INTERPRET_BC1TL //#define INTERPRET_BC1TL_OUT //#define INTERPRET_BC1TL_IDLE //#define INTERPRET_MFC1 //#define INTERPRET_DMFC1 //#define INTERPRET_CFC1 //#define INTERPRET_MTC1 //#define INTERPRET_DMTC1 //#define INTERPRET_CTC1 //#define INTERPRET_CP1_ADD_D //#define INTERPRET_CP1_SUB_D //#define INTERPRET_CP1_MUL_D //#define INTERPRET_CP1_DIV_D //#define INTERPRET_CP1_SQRT_D //#define INTERPRET_CP1_ABS_D //#define INTERPRET_CP1_MOV_D //#define INTERPRET_CP1_NEG_D //#define INTERPRET_CP1_ROUND_L_D //#define INTERPRET_CP1_TRUNC_L_D //#define INTERPRET_CP1_CEIL_L_D //#define INTERPRET_CP1_FLOOR_L_D //#define INTERPRET_CP1_ROUND_W_D //#define INTERPRET_CP1_TRUNC_W_D //#define INTERPRET_CP1_CEIL_W_D //#define INTERPRET_CP1_FLOOR_W_D //#define INTERPRET_CP1_CVT_S_D //#define INTERPRET_CP1_CVT_W_D //#define INTERPRET_CP1_CVT_L_D //#define INTERPRET_CP1_C_F_D //#define INTERPRET_CP1_C_UN_D //#define INTERPRET_CP1_C_EQ_D //#define INTERPRET_CP1_C_UEQ_D //#define INTERPRET_CP1_C_OLT_D //#define INTERPRET_CP1_C_ULT_D //#define INTERPRET_CP1_C_OLE_D //#define INTERPRET_CP1_C_ULE_D //#define INTERPRET_CP1_C_SF_D //#define INTERPRET_CP1_C_NGLE_D //#define INTERPRET_CP1_C_SEQ_D //#define INTERPRET_CP1_C_NGL_D //#define INTERPRET_CP1_C_LT_D //#define INTERPRET_CP1_C_NGE_D //#define INTERPRET_CP1_C_LE_D //#define INTERPRET_CP1_C_NGT_D //#define INTERPRET_CP1_CVT_S_L //#define INTERPRET_CP1_CVT_D_L //#define INTERPRET_CP1_CVT_S_W //#define INTERPRET_CP1_CVT_D_W //#define INTERPRET_CP1_ADD_S //#define INTERPRET_CP1_SUB_S //#define INTERPRET_CP1_MUL_S //#define INTERPRET_CP1_DIV_S //#define INTERPRET_CP1_SQRT_S //#define INTERPRET_CP1_ABS_S //#define INTERPRET_CP1_MOV_S //#define INTERPRET_CP1_NEG_S //#define INTERPRET_CP1_ROUND_L_S //#define INTERPRET_CP1_TRUNC_L_S //#define INTERPRET_CP1_CEIL_L_S //#define INTERPRET_CP1_FLOOR_L_S //#define INTERPRET_CP1_ROUND_W_S //#define INTERPRET_CP1_TRUNC_W_S //#define INTERPRET_CP1_CEIL_W_S //#define INTERPRET_CP1_FLOOR_W_S //#define INTERPRET_CP1_CVT_D_S //#define INTERPRET_CP1_CVT_W_S //#define INTERPRET_CP1_CVT_L_S //#define INTERPRET_CP1_C_F_S //#define INTERPRET_CP1_C_UN_S //#define INTERPRET_CP1_C_EQ_S //#define INTERPRET_CP1_C_UEQ_S //#define INTERPRET_CP1_C_OLT_S //#define INTERPRET_CP1_C_ULT_S //#define INTERPRET_CP1_C_OLE_S //#define INTERPRET_CP1_C_ULE_S //#define INTERPRET_CP1_C_SF_S //#define INTERPRET_CP1_C_NGLE_S //#define INTERPRET_CP1_C_SEQ_S //#define INTERPRET_CP1_C_NGL_S //#define INTERPRET_CP1_C_LT_S //#define INTERPRET_CP1_C_NGE_S //#define INTERPRET_CP1_C_LE_S //#define INTERPRET_CP1_C_NGT_S #endif /* M64P_DEVICE_R4300_X86_INTERPRET_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86/regcache.c000066400000000000000000000766011464506436200226100ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - regcache.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "assemble.h" #include "assemble_struct.h" #include "regcache.h" #include "device/r4300/r4300_core.h" #include "device/r4300/recomp.h" void init_cache(struct r4300_core* r4300, struct precomp_instr* start) { int i; for (i=0; i<8; i++) { r4300->recomp.regcache_state.last_access[i] = NULL; r4300->recomp.regcache_state.free_since[i] = start; } r4300->recomp.regcache_state.r0 = (unsigned int*)r4300_regs(&g_dev.r4300); } void free_all_registers(struct r4300_core* r4300) { #if defined(PROFILE_R4300) int freestart = r4300->recomp.code_length; int flushed = 0; #endif int i; for (i=0; i<8; i++) { #if defined(PROFILE_R4300) if (r4300->recomp.regcache_state.last_access[i] && r4300->recomp.regcache_state.dirty[i]) flushed = 1; #endif if (r4300->recomp.regcache_state.last_access[i]) free_register(r4300, i); else { while (r4300->recomp.regcache_state.free_since[i] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[i]->reg_cache_infos.needed_registers[i] = NULL; r4300->recomp.regcache_state.free_since[i]++; } } } #if defined(PROFILE_R4300) if (flushed == 1) { long x86addr = (long) ((*r4300->recomp.inst_pointer) + freestart); int mipsop = -5; fwrite(&mipsop, 1, 4, r4300->recomp.pfProfile); /* -5 = regcache flushing */ fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile); // write pointer to start of register cache flushing instructions x86addr = (long) ((*r4300->recomp.inst_pointer) + r4300->recomp.code_length); fwrite(&r4300->recomp.src, 1, 4, r4300->recomp.pfProfile); // write 4-byte MIPS opcode for current instruction fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile); // write pointer to dynamically generated x86 code for this MIPS instruction } #endif } // this function frees a specific X86 GPR void free_register(struct r4300_core* r4300, int reg) { struct precomp_instr *last; if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.r64[reg] != -1 && (int)r4300->recomp.regcache_state.reg_content[reg] != (int)r4300->recomp.regcache_state.reg_content[r4300->recomp.regcache_state.r64[reg]]-4) { free_register(r4300, r4300->recomp.regcache_state.r64[reg]); return; } if (r4300->recomp.regcache_state.last_access[reg] != NULL) last = r4300->recomp.regcache_state.last_access[reg]+1; else last = r4300->recomp.regcache_state.free_since[reg]; while (last <= r4300->recomp.dst) { if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.dirty[reg]) last->reg_cache_infos.needed_registers[reg] = r4300->recomp.regcache_state.reg_content[reg]; else last->reg_cache_infos.needed_registers[reg] = NULL; if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.r64[reg] != -1) { if (r4300->recomp.regcache_state.dirty[r4300->recomp.regcache_state.r64[reg]]) last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[reg]] = r4300->recomp.regcache_state.reg_content[r4300->recomp.regcache_state.r64[reg]]; else last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[reg]] = NULL; } last++; } if (r4300->recomp.regcache_state.last_access[reg] == NULL) { r4300->recomp.regcache_state.free_since[reg] = r4300->recomp.dst+1; return; } if (r4300->recomp.regcache_state.dirty[reg]) { mov_m32_reg32(r4300->recomp.regcache_state.reg_content[reg], reg); if (r4300->recomp.regcache_state.r64[reg] == -1) { sar_reg32_imm8(reg, 31); mov_m32_reg32((unsigned int*)r4300->recomp.regcache_state.reg_content[reg]+1, reg); } else mov_m32_reg32(r4300->recomp.regcache_state.reg_content[r4300->recomp.regcache_state.r64[reg]], r4300->recomp.regcache_state.r64[reg]); } r4300->recomp.regcache_state.last_access[reg] = NULL; r4300->recomp.regcache_state.free_since[reg] = r4300->recomp.dst+1; if (r4300->recomp.regcache_state.r64[reg] != -1) { r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[reg]] = NULL; r4300->recomp.regcache_state.free_since[r4300->recomp.regcache_state.r64[reg]] = r4300->recomp.dst+1; } } int lru_register(struct r4300_core* r4300) { unsigned int oldest_access = 0xFFFFFFFF; int i, reg = 0; for (i=0; i<8; i++) { if (i != ESP && (unsigned int)r4300->recomp.regcache_state.last_access[i] < oldest_access) { oldest_access = (int)r4300->recomp.regcache_state.last_access[i]; reg = i; } } return reg; } int lru_register_exc1(struct r4300_core* r4300, int exc1) { unsigned int oldest_access = 0xFFFFFFFF; int i, reg = 0; for (i=0; i<8; i++) { if (i != ESP && i != exc1 && (unsigned int)r4300->recomp.regcache_state.last_access[i] < oldest_access) { oldest_access = (int)r4300->recomp.regcache_state.last_access[i]; reg = i; } } return reg; } // this function finds a register to put the data contained in addr, // if there was another value before it's cleanly removed of the // register cache. After that, the register number is returned. // If data are already cached, the function only returns the register number int allocate_register(struct r4300_core* r4300, unsigned int *addr) { unsigned int oldest_access = 0xFFFFFFFF; int reg = 0, i; // is it already cached ? if (addr != NULL) { for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = r4300->recomp.regcache_state.reg_content[i]; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; if (r4300->recomp.regcache_state.r64[i] != -1) { last = r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.regcache_state.reg_content[r4300->recomp.regcache_state.r64[i]]; last++; } r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.dst; } return i; } } } // if it's not cached, we take the least recently used register for (i=0; i<8; i++) { if (i != ESP && (unsigned int)r4300->recomp.regcache_state.last_access[i] < oldest_access) { oldest_access = (int)r4300->recomp.regcache_state.last_access[i]; reg = i; } } if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = addr; r4300->recomp.regcache_state.dirty[reg] = 0; r4300->recomp.regcache_state.r64[reg] = -1; if (addr != NULL) { if (addr == r4300->recomp.regcache_state.r0 || addr == r4300->recomp.regcache_state.r0+1) xor_reg32_reg32(reg, reg); else mov_reg32_m32(reg, addr); } return reg; } // this function is similar to allocate_register except it loads // a 64 bits value, and return the register number of the LSB part int allocate_64_register1(struct r4300_core* r4300, unsigned int *addr) { int reg1, reg2, i; // is it already cached as a 32 bits value ? for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { if (r4300->recomp.regcache_state.r64[i] == -1) { allocate_register(r4300, addr); reg2 = allocate_register(r4300, r4300->recomp.regcache_state.dirty[i] ? NULL : addr+1); r4300->recomp.regcache_state.r64[i] = reg2; r4300->recomp.regcache_state.r64[reg2] = i; if (r4300->recomp.regcache_state.dirty[i]) { r4300->recomp.regcache_state.reg_content[reg2] = addr+1; r4300->recomp.regcache_state.dirty[reg2] = 1; mov_reg32_reg32(reg2, i); sar_reg32_imm8(reg2, 31); } return i; } } } reg1 = allocate_register(r4300, addr); reg2 = allocate_register(r4300, addr+1); r4300->recomp.regcache_state.r64[reg1] = reg2; r4300->recomp.regcache_state.r64[reg2] = reg1; return reg1; } // this function is similar to allocate_register except it loads // a 64 bits value, and return the register number of the MSB part int allocate_64_register2(struct r4300_core* r4300, unsigned int *addr) { int reg1, reg2, i; // is it already cached as a 32 bits value ? for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { if (r4300->recomp.regcache_state.r64[i] == -1) { allocate_register(r4300, addr); reg2 = allocate_register(r4300, r4300->recomp.regcache_state.dirty[i] ? NULL : addr+1); r4300->recomp.regcache_state.r64[i] = reg2; r4300->recomp.regcache_state.r64[reg2] = i; if (r4300->recomp.regcache_state.dirty[i]) { r4300->recomp.regcache_state.reg_content[reg2] = addr+1; r4300->recomp.regcache_state.dirty[reg2] = 1; mov_reg32_reg32(reg2, i); sar_reg32_imm8(reg2, 31); } return reg2; } } } reg1 = allocate_register(r4300, addr); reg2 = allocate_register(r4300, addr+1); r4300->recomp.regcache_state.r64[reg1] = reg2; r4300->recomp.regcache_state.r64[reg2] = reg1; return reg2; } // this function checks if the data located at addr are cached in a register // and then, it returns 1 if it's a 64 bit value // 0 if it's a 32 bit value // -1 if it's not cached int is64(struct r4300_core* r4300, unsigned int *addr) { int i; for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { if (r4300->recomp.regcache_state.r64[i] == -1) return 0; return 1; } } return -1; } int allocate_register_w(struct r4300_core* r4300, unsigned int *addr) { unsigned int oldest_access = 0xFFFFFFFF; int reg = 0, i; // is it already cached ? for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; r4300->recomp.regcache_state.dirty[i] = 1; if (r4300->recomp.regcache_state.r64[i] != -1) { last = r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[i]] = NULL; last++; } r4300->recomp.regcache_state.free_since[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.dst+1; r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]] = NULL; r4300->recomp.regcache_state.r64[i] = -1; } return i; } } // if it's not cached, we take the least recently used register for (i=0; i<8; i++) { if (i != ESP && (unsigned int)r4300->recomp.regcache_state.last_access[i] < oldest_access) { oldest_access = (int)r4300->recomp.regcache_state.last_access[i]; reg = i; } } if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = addr; r4300->recomp.regcache_state.dirty[reg] = 1; r4300->recomp.regcache_state.r64[reg] = -1; return reg; } int allocate_64_register1_w(struct r4300_core* r4300, unsigned int *addr) { int reg1, reg2, i; // is it already cached as a 32 bits value ? for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { if (r4300->recomp.regcache_state.r64[i] == -1) { allocate_register_w(r4300, addr); reg2 = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg2]) free_register(r4300, reg2); else { while (r4300->recomp.regcache_state.free_since[reg2] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; r4300->recomp.regcache_state.free_since[reg2]++; } } r4300->recomp.regcache_state.r64[i] = reg2; r4300->recomp.regcache_state.r64[reg2] = i; r4300->recomp.regcache_state.last_access[reg2] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg2] = addr+1; r4300->recomp.regcache_state.dirty[reg2] = 1; mov_reg32_reg32(reg2, i); sar_reg32_imm8(reg2, 31); return i; } else { r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.dst; r4300->recomp.regcache_state.dirty[i] = r4300->recomp.regcache_state.dirty[r4300->recomp.regcache_state.r64[i]] = 1; return i; } } } reg1 = allocate_register_w(r4300, addr); reg2 = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg2]) free_register(r4300, reg2); else { while (r4300->recomp.regcache_state.free_since[reg2] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; r4300->recomp.regcache_state.free_since[reg2]++; } } r4300->recomp.regcache_state.r64[reg1] = reg2; r4300->recomp.regcache_state.r64[reg2] = reg1; r4300->recomp.regcache_state.last_access[reg2] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg2] = addr+1; r4300->recomp.regcache_state.dirty[reg2] = 1; return reg1; } int allocate_64_register2_w(struct r4300_core* r4300, unsigned int *addr) { int reg1, reg2, i; // is it already cached as a 32 bits value ? for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { if (r4300->recomp.regcache_state.r64[i] == -1) { allocate_register_w(r4300, addr); reg2 = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg2]) free_register(r4300, reg2); else { while (r4300->recomp.regcache_state.free_since[reg2] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; r4300->recomp.regcache_state.free_since[reg2]++; } } r4300->recomp.regcache_state.r64[i] = reg2; r4300->recomp.regcache_state.r64[reg2] = i; r4300->recomp.regcache_state.last_access[reg2] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg2] = addr+1; r4300->recomp.regcache_state.dirty[reg2] = 1; mov_reg32_reg32(reg2, i); sar_reg32_imm8(reg2, 31); return reg2; } else { r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.dst; r4300->recomp.regcache_state.dirty[i] = r4300->recomp.regcache_state.dirty[r4300->recomp.regcache_state.r64[i]] = 1; return r4300->recomp.regcache_state.r64[i]; } } } reg1 = allocate_register_w(r4300, addr); reg2 = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg2]) free_register(r4300, reg2); else { while (r4300->recomp.regcache_state.free_since[reg2] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg2]->reg_cache_infos.needed_registers[reg2] = NULL; r4300->recomp.regcache_state.free_since[reg2]++; } } r4300->recomp.regcache_state.r64[reg1] = reg2; r4300->recomp.regcache_state.r64[reg2] = reg1; r4300->recomp.regcache_state.last_access[reg2] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg2] = addr+1; r4300->recomp.regcache_state.dirty[reg2] = 1; return reg2; } void set_register_state(struct r4300_core* r4300, int reg, unsigned int *addr, int d) { r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = addr; r4300->recomp.regcache_state.r64[reg] = -1; r4300->recomp.regcache_state.dirty[reg] = d; } void set_64_register_state(struct r4300_core* r4300, int reg1, int reg2, unsigned int *addr, int d) { r4300->recomp.regcache_state.last_access[reg1] = r4300->recomp.dst; r4300->recomp.regcache_state.last_access[reg2] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg1] = addr; r4300->recomp.regcache_state.reg_content[reg2] = addr+1; r4300->recomp.regcache_state.r64[reg1] = reg2; r4300->recomp.regcache_state.r64[reg2] = reg1; r4300->recomp.regcache_state.dirty[reg1] = d; r4300->recomp.regcache_state.dirty[reg2] = d; } void allocate_register_manually(struct r4300_core* r4300, int reg, unsigned int *addr) { int i; if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.reg_content[reg] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[reg]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[reg] = r4300->recomp.regcache_state.reg_content[reg]; last++; } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; if (r4300->recomp.regcache_state.r64[reg] != -1) { last = r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[reg]]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[reg]] = r4300->recomp.regcache_state.reg_content[r4300->recomp.regcache_state.r64[reg]]; last++; } r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[reg]] = r4300->recomp.dst; } return; } if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } // is it already cached ? for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = r4300->recomp.regcache_state.reg_content[i]; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; if (r4300->recomp.regcache_state.r64[i] != -1) { last = r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.regcache_state.reg_content[r4300->recomp.regcache_state.r64[i]]; last++; } r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.dst; } mov_reg32_reg32(reg, i); r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.r64[reg] = r4300->recomp.regcache_state.r64[i]; if (r4300->recomp.regcache_state.r64[reg] != -1) r4300->recomp.regcache_state.r64[r4300->recomp.regcache_state.r64[reg]] = reg; r4300->recomp.regcache_state.dirty[reg] = r4300->recomp.regcache_state.dirty[i]; r4300->recomp.regcache_state.reg_content[reg] = r4300->recomp.regcache_state.reg_content[i]; r4300->recomp.regcache_state.free_since[i] = r4300->recomp.dst+1; r4300->recomp.regcache_state.last_access[i] = NULL; return; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = addr; r4300->recomp.regcache_state.dirty[reg] = 0; r4300->recomp.regcache_state.r64[reg] = -1; if (addr != NULL) { if (addr == r4300->recomp.regcache_state.r0 || addr == r4300->recomp.regcache_state.r0+1) xor_reg32_reg32(reg, reg); else mov_reg32_m32(reg, addr); } } void allocate_register_manually_w(struct r4300_core* r4300, int reg, unsigned int *addr, int load) { int i; if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.reg_content[reg] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[reg]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[reg] = r4300->recomp.regcache_state.reg_content[reg]; last++; } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; if (r4300->recomp.regcache_state.r64[reg] != -1) { last = r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[reg]]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[reg]] = r4300->recomp.regcache_state.reg_content[r4300->recomp.regcache_state.r64[reg]]; last++; } r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[reg]] = NULL; r4300->recomp.regcache_state.free_since[r4300->recomp.regcache_state.r64[reg]] = r4300->recomp.dst+1; r4300->recomp.regcache_state.r64[reg] = -1; } r4300->recomp.regcache_state.dirty[reg] = 1; return; } if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } // is it already cached ? for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = r4300->recomp.regcache_state.reg_content[i]; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; if (r4300->recomp.regcache_state.r64[i] != -1) { last = r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[r4300->recomp.regcache_state.r64[i]] = NULL; last++; } r4300->recomp.regcache_state.free_since[r4300->recomp.regcache_state.r64[i]] = r4300->recomp.dst+1; r4300->recomp.regcache_state.last_access[r4300->recomp.regcache_state.r64[i]] = NULL; r4300->recomp.regcache_state.r64[i] = -1; } if (load) mov_reg32_reg32(reg, i); r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.dirty[reg] = 1; r4300->recomp.regcache_state.r64[reg] = -1; r4300->recomp.regcache_state.reg_content[reg] = r4300->recomp.regcache_state.reg_content[i]; r4300->recomp.regcache_state.free_since[i] = r4300->recomp.dst+1; r4300->recomp.regcache_state.last_access[i] = NULL; return; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = addr; r4300->recomp.regcache_state.dirty[reg] = 1; r4300->recomp.regcache_state.r64[reg] = -1; if (addr != NULL && load) { if (addr == r4300->recomp.regcache_state.r0 || addr == r4300->recomp.regcache_state.r0+1) xor_reg32_reg32(reg, reg); else mov_reg32_m32(reg, addr); } } // 0x81 0xEC 0x4 0x0 0x0 0x0 sub esp, 4 // 0xA1 0xXXXXXXXX mov eax, XXXXXXXX (&code start) // 0x05 0xXXXXXXXX add eax, XXXXXXXX (local_addr) // 0x89 0x04 0x24 mov [esp], eax // 0x8B (reg<<3)|5 0xXXXXXXXX mov eax, [XXXXXXXX] // 0x8B (reg<<3)|5 0xXXXXXXXX mov ebx, [XXXXXXXX] // 0x8B (reg<<3)|5 0xXXXXXXXX mov ecx, [XXXXXXXX] // 0x8B (reg<<3)|5 0xXXXXXXXX mov edx, [XXXXXXXX] // 0x8B (reg<<3)|5 0xXXXXXXXX mov ebp, [XXXXXXXX] // 0x8B (reg<<3)|5 0xXXXXXXXX mov esi, [XXXXXXXX] // 0x8B (reg<<3)|5 0xXXXXXXXX mov edi, [XXXXXXXX] // 0xC3 ret // total : 62 bytes static void build_wrapper(struct r4300_core* r4300, struct precomp_instr *instr, unsigned char* code, struct precomp_block* block) { int i; int j=0; #if defined(PROFILE_R4300) long x86addr = (long) code; int mipsop = -4; fwrite(&mipsop, 1, 4, r4300->recomp.pfProfile); // write 4-byte MIPS opcode fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile); // write pointer to dynamically generated x86 code for this MIPS instruction #endif code[j++] = 0x81; code[j++] = 0xEC; code[j++] = 0x04; code[j++] = 0x00; code[j++] = 0x00; code[j++] = 0x00; code[j++] = 0xA1; *((unsigned int*)&code[j]) = (unsigned int)(&block->code); j+=4; code[j++] = 0x05; *((unsigned int*)&code[j]) = (unsigned int)instr->local_addr; j+=4; code[j++] = 0x89; code[j++] = 0x04; code[j++] = 0x24; for (i=0; i<8; i++) { if (instr->reg_cache_infos.needed_registers[i] != NULL) { code[j++] = 0x8B; code[j++] = (i << 3) | 5; *((unsigned int*)&code[j]) = (unsigned int)instr->reg_cache_infos.needed_registers[i]; j+=4; } } code[j++] = 0xC3; } void build_wrappers(struct r4300_core* r4300, struct precomp_instr *instr, int start, int end, struct precomp_block* block) { int i, reg;; for (i=start; irecomp.dst->local_addr = r4300->recomp.code_length; for(i=0; i<8; i++) r4300->recomp.dst->reg_cache_infos.needed_registers[i] = NULL; } mupen64plus-core-src-2.6.0/src/device/r4300/x86/regcache.h000066400000000000000000000057451464506436200226160ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - regcache.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_X86_REGCACHE_H #define M64P_DEVICE_R4300_X86_REGCACHE_H struct r4300_core; struct precomp_instr; struct precomp_block; void init_cache(struct r4300_core* r4300, struct precomp_instr* start); void free_all_registers(struct r4300_core* r4300); void free_register(struct r4300_core* r4300, int reg); int allocate_register(struct r4300_core* r4300, unsigned int *addr); int allocate_64_register1(struct r4300_core* r4300, unsigned int *addr); int allocate_64_register2(struct r4300_core* r4300, unsigned int *addr); int is64(struct r4300_core* r4300, unsigned int *addr); void build_wrappers(struct r4300_core* r4300, struct precomp_instr*, int, int, struct precomp_block*); int lru_register(struct r4300_core* r4300); int allocate_register_w(struct r4300_core* r4300, unsigned int *addr); int allocate_64_register1_w(struct r4300_core* r4300, unsigned int *addr); int allocate_64_register2_w(struct r4300_core* r4300, unsigned int *addr); void set_register_state(struct r4300_core* r4300, int reg, unsigned int *addr, int dirty); void set_64_register_state(struct r4300_core* r4300, int reg1, int reg2, unsigned int *addr, int dirty); void allocate_register_manually(struct r4300_core* r4300, int reg, unsigned int *addr); void allocate_register_manually_w(struct r4300_core* r4300, int reg, unsigned int *addr, int load); int lru_register_exc1(struct r4300_core* r4300, int exc1); void simplify_access(struct r4300_core* r4300); #endif /* M64P_DEVICE_R4300_X86_REGCACHE_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/000077500000000000000000000000001464506436200212025ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/assemble.c000066400000000000000000000203231464506436200231410ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assemble.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2007 Richard Goedeken (Richard42) * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "assemble.h" #include "assemble_struct.h" #include "regcache.h" #include "device/r4300/recomp.h" #include "osal/preproc.h" /* Placeholder for RIP-relative offsets is maxmimum 32-bit signed value. * So, if recompiled code is run without running passe2() first, it will * cause an exception. */ #define REL_PLACEHOLDER 0x7fffffff /* Static Functions */ void add_jump(struct r4300_core* r4300, unsigned int pc_addr, unsigned int mi_addr, unsigned int absolute64) { if (r4300->recomp.jumps_number == r4300->recomp.max_jumps_number) { r4300->recomp.max_jumps_number += 512; r4300->recomp.jumps_table = realloc(r4300->recomp.jumps_table, r4300->recomp.max_jumps_number*sizeof(struct jump_table)); } r4300->recomp.jumps_table[r4300->recomp.jumps_number].pc_addr = pc_addr; r4300->recomp.jumps_table[r4300->recomp.jumps_number].mi_addr = mi_addr; r4300->recomp.jumps_table[r4300->recomp.jumps_number].absolute64 = absolute64; r4300->recomp.jumps_number++; } /* Global Functions */ void init_assembler(struct r4300_core* r4300, void *block_jumps_table, int block_jumps_number, void *block_riprel_table, int block_riprel_number) { if (block_jumps_table) { r4300->recomp.jumps_table = block_jumps_table; r4300->recomp.jumps_number = block_jumps_number; if (r4300->recomp.jumps_number <= 512) r4300->recomp.max_jumps_number = 512; else r4300->recomp.max_jumps_number = (r4300->recomp.jumps_number + 511) & ~0x1ff; } else { r4300->recomp.jumps_table = malloc(512*sizeof(struct jump_table)); r4300->recomp.jumps_number = 0; r4300->recomp.max_jumps_number = 512; } if (block_riprel_table) { r4300->recomp.riprel_table = block_riprel_table; r4300->recomp.riprel_number = block_riprel_number; if (r4300->recomp.riprel_number <= 512) r4300->recomp.max_riprel_number = 512; else r4300->recomp.max_riprel_number = (r4300->recomp.riprel_number + 511) & ~0x1ff; } else { r4300->recomp.riprel_table = malloc(512 * sizeof(struct riprelative_table)); r4300->recomp.riprel_number = 0; r4300->recomp.max_riprel_number = 512; } } void free_assembler(struct r4300_core* r4300, void **block_jumps_table, int *block_jumps_number, void **block_riprel_table, int *block_riprel_number) { *block_jumps_table = r4300->recomp.jumps_table; *block_jumps_number = r4300->recomp.jumps_number; *block_riprel_table = r4300->recomp.riprel_table; *block_riprel_number = r4300->recomp.riprel_number; } void passe2(struct r4300_core* r4300, struct precomp_instr *dest, int start, int end, struct precomp_block *block) { unsigned int i; build_wrappers(r4300, dest, start, end, block); /* First, fix up all the jumps. This involves a table lookup to find the offset into the block of x86_64 code for * for start of a recompiled r4300i instruction corresponding to the given jump destination address in the N64 * address space. Next, the relative offset between this destination and the location of the jump instruction is * computed and stored in memory, so that the jump will branch to the right place in the recompiled code. */ for (i = 0; i < r4300->recomp.jumps_number; i++) { struct precomp_instr *jump_instr = dest + ((r4300->recomp.jumps_table[i].mi_addr - dest[0].addr) / 4); unsigned int jmp_offset_loc = r4300->recomp.jumps_table[i].pc_addr; unsigned char *addr_dest = NULL; /* calculate the destination address to jump to */ if (jump_instr->reg_cache_infos.need_map) { addr_dest = jump_instr->reg_cache_infos.jump_wrapper; } else { addr_dest = block->code + jump_instr->local_addr; } /* write either a 32-bit IP-relative offset or a 64-bit absolute address */ if (r4300->recomp.jumps_table[i].absolute64) { *((unsigned long long *) (block->code + jmp_offset_loc)) = (unsigned long long) addr_dest; } else { long jump_rel_offset = (long) (addr_dest - (block->code + jmp_offset_loc + 4)); *((int *) (block->code + jmp_offset_loc)) = (int) jump_rel_offset; if (jump_rel_offset >= 0x7fffffffLL || jump_rel_offset < -0x80000000LL) { DebugMessage(M64MSG_ERROR, "assembler pass2 error: offset too big for relative jump from %p to %p", (block->code + jmp_offset_loc + 4), addr_dest); OSAL_BREAKPOINT_INTERRUPT; } } } /* Next, fix up all of the RIP-relative memory accesses. This is unique to the x86_64 architecture, because * the 32-bit absolute displacement addressing mode is not available (and there's no 64-bit absolute displacement * mode either). */ for (i = 0; i < r4300->recomp.riprel_number; i++) { unsigned char *rel_offset_ptr = block->code + r4300->recomp.riprel_table[i].pc_addr; long rip_rel_offset = (long) (r4300->recomp.riprel_table[i].global_dst - (rel_offset_ptr + 4 + r4300->recomp.riprel_table[i].extra_bytes)); if (rip_rel_offset >= 0x7fffffffLL || rip_rel_offset < -0x80000000LL) { DebugMessage(M64MSG_ERROR, "assembler pass2 error: offset too big between mem target: %p and code position: %p", r4300->recomp.riprel_table[i].global_dst, rel_offset_ptr); OSAL_BREAKPOINT_INTERRUPT; } *((int *) rel_offset_ptr) = (int) rip_rel_offset; } } void jump_start_rel8(struct r4300_core* r4300) { r4300->recomp.jump_start8 = r4300->recomp.code_length; } void jump_start_rel32(struct r4300_core* r4300) { r4300->recomp.jump_start32 = r4300->recomp.code_length; } void jump_end_rel8(struct r4300_core* r4300) { unsigned int jump_end = r4300->recomp.code_length; int jump_vec = jump_end - r4300->recomp.jump_start8; if (jump_vec > 127 || jump_vec < -128) { DebugMessage(M64MSG_ERROR, "Error: 8-bit relative jump too long! From %x to %x", r4300->recomp.jump_start8, jump_end); OSAL_BREAKPOINT_INTERRUPT; } r4300->recomp.code_length = r4300->recomp.jump_start8 - 1; put8(jump_vec); r4300->recomp.code_length = jump_end; } void jump_end_rel32(struct r4300_core* r4300) { unsigned int jump_end = r4300->recomp.code_length; int jump_vec = jump_end - r4300->recomp.jump_start32; r4300->recomp.code_length = r4300->recomp.jump_start32 - 4; put32(jump_vec); r4300->recomp.code_length = jump_end; } mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/assemble.h000066400000000000000000000634571464506436200231650ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assemble.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2007 Richard Goedeken (Richard42) * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_X86_64_ASSEMBLE_H #define M64P_DEVICE_R4300_X86_64_ASSEMBLE_H #include #include #include #include "api/m64p_types.h" #include "api/callbacks.h" #include "main/main.h" #include "osal/preproc.h" #include "device/r4300/recomp.h" #define RAX 0 #define RCX 1 #define RDX 2 #define RBX 3 #define RSP 4 #define RBP 5 #define RSI 6 #define RDI 7 #define EAX 0 #define ECX 1 #define EDX 2 #define EBX 3 #define ESP 4 #define EBP 5 #define ESI 6 #define EDI 7 #define AX 0 #define CX 1 #define DX 2 #define BX 3 #define SP 4 #define BP 5 #define SI 6 #define DI 7 #define AL 0 #define CL 1 #define DL 2 #define BL 3 #define AH 4 #define CH 5 #define DH 6 #define BH 7 struct r4300_core; void jump_start_rel8(struct r4300_core* r4300); void jump_end_rel8(struct r4300_core* r4300); void jump_start_rel32(struct r4300_core* r4300); void jump_end_rel32(struct r4300_core* r4300); void add_jump(struct r4300_core* r4300, unsigned int pc_addr, unsigned int mi_addr, unsigned int absolute64); static osal_inline void put8(unsigned char octet) { struct r4300_core* r4300 = &g_dev.r4300; (*r4300->recomp.inst_pointer)[r4300->recomp.code_length] = octet; r4300->recomp.code_length++; if (r4300->recomp.code_length == r4300->recomp.max_code_length) { *r4300->recomp.inst_pointer = realloc_exec(*r4300->recomp.inst_pointer, r4300->recomp.max_code_length, r4300->recomp.max_code_length+8192); r4300->recomp.max_code_length += 8192; } } static osal_inline void put32(unsigned int dword) { struct r4300_core* r4300 = &g_dev.r4300; if ((r4300->recomp.code_length + 4) >= r4300->recomp.max_code_length) { *r4300->recomp.inst_pointer = realloc_exec(*r4300->recomp.inst_pointer, r4300->recomp.max_code_length, r4300->recomp.max_code_length+8192); r4300->recomp.max_code_length += 8192; } *((unsigned int *) (*r4300->recomp.inst_pointer + r4300->recomp.code_length)) = dword; r4300->recomp.code_length += 4; } static osal_inline void put64(unsigned long long qword) { struct r4300_core* r4300 = &g_dev.r4300; if ((r4300->recomp.code_length + 8) >= r4300->recomp.max_code_length) { *r4300->recomp.inst_pointer = realloc_exec(*r4300->recomp.inst_pointer, r4300->recomp.max_code_length, r4300->recomp.max_code_length+8192); r4300->recomp.max_code_length += 8192; } *((unsigned long long *) (*r4300->recomp.inst_pointer + r4300->recomp.code_length)) = qword; r4300->recomp.code_length += 8; } static osal_inline int rel_r15_offset(void *dest, const char *op_name) { struct r4300_core* r4300 = &g_dev.r4300; /* calculate the destination pointer's offset from the base of the r4300 registers */ long long rel_offset = (long long) ((unsigned char *) dest - (unsigned char *) r4300_regs(r4300)); if (llabs(rel_offset) > 0x7fffffff) { DebugMessage(M64MSG_ERROR, "Error: destination %p more than 2GB away from r15 base %p in %s()", dest, (void*)r4300_regs(r4300), op_name); OSAL_BREAKPOINT_INTERRUPT; } return (int) rel_offset; } static osal_inline void mov_memoffs32_eax(unsigned int *memoffs32) { put8(0xA3); put64((unsigned long long) memoffs32); } static osal_inline void mov_rax_memoffs64(unsigned long long *memoffs64) { put8(0x48); put8(0xA1); put64((unsigned long long) memoffs64); } static osal_inline void mov_memoffs64_rax(unsigned long long *memoffs64) { put8(0x48); put8(0xA3); put64((unsigned long long) memoffs64); } static osal_inline void mov_m8rel_xreg8(unsigned char *m8, int xreg8) { int offset = rel_r15_offset(m8, "mov_m8rel_xreg8"); put8(0x41 | ((xreg8 & 8) >> 1)); put8(0x88); put8(0x87 | ((xreg8 & 7) << 3)); put32(offset); } static osal_inline void mov_xreg16_m16rel(int xreg16, unsigned short *m16) { int offset = rel_r15_offset(m16, "mov_xreg16_m16rel"); put8(0x66); put8(0x41 | ((xreg16 & 8) >> 1)); put8(0x8B); put8(0x87 | ((xreg16 & 7) << 3)); put32(offset); } static osal_inline void mov_m16rel_xreg16(unsigned short *m16, int xreg16) { int offset = rel_r15_offset(m16, "mov_m16rel_xreg16"); put8(0x66); put8(0x41 | ((xreg16 & 8) >> 1)); put8(0x89); put8(0x87 | ((xreg16 & 7) << 3)); put32(offset); } static osal_inline void cmp_xreg32_m32rel(int xreg32, unsigned int *m32) { int offset = rel_r15_offset(m32, "cmp_xreg32_m32rel"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x3B); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void cmp_xreg64_m64rel(int xreg64, unsigned long long *m64) { int offset = rel_r15_offset(m64, "cmp_xreg64_m64rel"); put8(0x49 | ((xreg64 & 8) >> 1)); put8(0x3B); put8(0x87 | ((xreg64 & 7) << 3)); put32(offset); } static osal_inline void cmp_reg32_reg32(int reg1, int reg2) { put8(0x39); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void cmp_reg64_reg64(int reg1, int reg2) { put8(0x48); put8(0x39); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void cmp_reg32_imm8(int reg32, unsigned char imm8) { put8(0x83); put8(0xF8 + reg32); put8(imm8); } static osal_inline void cmp_reg64_imm8(int reg64, unsigned char imm8) { put8(0x48); put8(0x83); put8(0xF8 + reg64); put8(imm8); } static osal_inline void cmp_reg32_imm32(int reg32, unsigned int imm32) { put8(0x81); put8(0xF8 + reg32); put32(imm32); } static osal_inline void cmp_reg64_imm32(int reg64, unsigned int imm32) { put8(0x48); put8(0x81); put8(0xF8 + reg64); put32(imm32); } static osal_inline void cmp_preg64preg64_imm8(int reg1, int reg2, unsigned char imm8) { put8(0x80); put8(0x3C); put8((reg1 << 3) | reg2); put8(imm8); } static osal_inline void sete_m8rel(unsigned char *m8) { int offset = rel_r15_offset(m8, "sete_m8rel"); put8(0x41); put8(0x0F); put8(0x94); put8(0x87); put32(offset); } static osal_inline void setne_m8rel(unsigned char *m8) { int offset = rel_r15_offset(m8, "setne_m8rel"); put8(0x41); put8(0x0F); put8(0x95); put8(0x87); put32(offset); } static osal_inline void setl_m8rel(unsigned char *m8) { int offset = rel_r15_offset(m8, "setl_m8rel"); put8(0x41); put8(0x0F); put8(0x9C); put8(0x87); put32(offset); } static osal_inline void setle_m8rel(unsigned char *m8) { int offset = rel_r15_offset(m8, "setle_m8rel"); put8(0x41); put8(0x0F); put8(0x9E); put8(0x87); put32(offset); } static osal_inline void setg_m8rel(unsigned char *m8) { int offset = rel_r15_offset(m8, "setg_m8rel"); put8(0x41); put8(0x0F); put8(0x9F); put8(0x87); put32(offset); } static osal_inline void setge_m8rel(unsigned char *m8) { int offset = rel_r15_offset(m8, "setge_m8rel"); put8(0x41); put8(0x0F); put8(0x9D); put8(0x87); put32(offset); } static osal_inline void setl_reg8(unsigned int reg8) { put8(0x40); /* we need an REX prefix to use the uniform byte registers */ put8(0x0F); put8(0x9C); put8(0xC0 | reg8); } static osal_inline void setb_reg8(unsigned int reg8) { put8(0x40); /* we need an REX prefix to use the uniform byte registers */ put8(0x0F); put8(0x92); put8(0xC0 | reg8); } static osal_inline void test_m32rel_imm32(unsigned int *m32, unsigned int imm32) { int offset = rel_r15_offset(m32, "test_m32rel_imm32"); put8(0x41); put8(0xF7); put8(0x87); put32(offset); put32(imm32); } static osal_inline void test_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x85); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void add_m32rel_xreg32(unsigned int *m32, int xreg32) { int offset = rel_r15_offset(m32, "add_m32rel_xreg32"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x01); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void sub_m32rel_xreg32(unsigned int *m32, int xreg32) { int offset = rel_r15_offset(m32, "sub_m32rel_xreg32"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x29); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void sub_xreg32_m32rel(int xreg32, unsigned int *m32) { int offset = rel_r15_offset(m32, "sub_xreg32_m32rel"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x2B); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void sub_reg32_reg32(int reg1, int reg2) { put8(0x29); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void sub_reg64_reg64(int reg1, int reg2) { put8(0x48); put8(0x29); put8((reg2 << 3) | reg1 | 0xC0); } static osal_inline void sub_reg64_imm32(int reg64, unsigned int imm32) { put8(0x48); put8(0x81); put8(0xE8 + reg64); put32(imm32); } static osal_inline void sub_eax_imm32(unsigned int imm32) { put8(0x2D); put32(imm32); } static osal_inline void jne_rj(unsigned char saut) { put8(0x75); put8(saut); } static osal_inline void je_rj(unsigned char saut) { put8(0x74); put8(saut); } static osal_inline void jbe_rj(unsigned char saut) { put8(0x76); put8(saut); } static osal_inline void ja_rj(unsigned char saut) { put8(0x77); put8(saut); } static osal_inline void jae_rj(unsigned char saut) { put8(0x73); put8(saut); } static osal_inline void jp_rj(unsigned char saut) { put8(0x7A); put8(saut); } static osal_inline void jns_rj(unsigned char saut) { put8(0x79); put8(saut); } static osal_inline void js_rj(unsigned char saut) { put8(0x78); put8(saut); } static osal_inline void je_near_rj(unsigned int saut) { put8(0x0F); put8(0x84); put32(saut); } static osal_inline void mov_reg32_imm32(int reg32, unsigned int imm32) { put8(0xB8+reg32); put32(imm32); } static osal_inline void mov_reg64_imm64(int reg64, unsigned long long imm64) { put8(0x48); put8(0xB8+reg64); put64(imm64); } static osal_inline void jmp_imm_short(char saut) { put8(0xEB); put8(saut); } static osal_inline void or_m32rel_imm32(unsigned int *m32, unsigned int imm32) { int offset = rel_r15_offset(m32, "or_m32rel_imm32"); put8(0x41); put8(0x81); put8(0x8F); put32(offset); put32(imm32); } static osal_inline void or_reg64_reg64(unsigned int reg1, unsigned int reg2) { put8(0x48); put8(0x09); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void and_reg64_reg64(unsigned int reg1, unsigned int reg2) { put8(0x48); put8(0x21); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void and_m32rel_imm32(unsigned int *m32, unsigned int imm32) { int offset = rel_r15_offset(m32, "and_m32rel_imm32"); put8(0x41); put8(0x81); put8(0xA7); put32(offset); put32(imm32); } static osal_inline void xor_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x31); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void xor_reg64_reg64(unsigned int reg1, unsigned int reg2) { put8(0x48); put8(0x31); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void add_reg64_imm32(unsigned int reg64, unsigned int imm32) { put8(0x48); put8(0x81); put8(0xC0+reg64); put32(imm32); } static osal_inline void add_reg32_imm32(unsigned int reg32, unsigned int imm32) { put8(0x81); put8(0xC0+reg32); put32(imm32); } static osal_inline void inc_m32rel(unsigned int *m32) { int offset = rel_r15_offset(m32, "inc_m32rel"); put8(0x41); put8(0xFF); put8(0x87); put32(offset); } static osal_inline void cmp_m32rel_imm32(unsigned int *m32, unsigned int imm32) { int offset = rel_r15_offset(m32, "cmp_m32rel_imm32"); put8(0x41); put8(0x81); put8(0xBF); put32(offset); put32(imm32); } static osal_inline void cmp_eax_imm32(unsigned int imm32) { put8(0x3D); put32(imm32); } static osal_inline void mov_m32rel_imm32(unsigned int *m32, unsigned int imm32) { int offset = rel_r15_offset(m32, "mov_m32rel_imm32"); put8(0x41); put8(0xC7); put8(0x87); put32(offset); put32(imm32); } static osal_inline void jmp(unsigned int mi_addr) { struct r4300_core* r4300 = &g_dev.r4300; put8(0xFF); put8(0x25); put32(0); put64(0); add_jump(r4300, r4300->recomp.code_length-8, mi_addr, 1); } static osal_inline void cdq(void) { put8(0x99); } static osal_inline void call_reg64(unsigned int reg64) { put8(0xFF); put8(0xD0+reg64); } static osal_inline void shr_reg64_imm8(unsigned int reg64, unsigned char imm8) { put8(0x48); put8(0xC1); put8(0xE8+reg64); put8(imm8); } static osal_inline void shr_reg32_imm8(unsigned int reg32, unsigned char imm8) { put8(0xC1); put8(0xE8+reg32); put8(imm8); } static osal_inline void shr_reg32_cl(unsigned int reg32) { put8(0xD3); put8(0xE8+reg32); } static osal_inline void shr_reg64_cl(unsigned int reg64) { put8(0x48); put8(0xD3); put8(0xE8+reg64); } static osal_inline void sar_reg32_cl(unsigned int reg32) { put8(0xD3); put8(0xF8+reg32); } static osal_inline void sar_reg64_cl(unsigned int reg64) { put8(0x48); put8(0xD3); put8(0xF8+reg64); } static osal_inline void shl_reg32_cl(unsigned int reg32) { put8(0xD3); put8(0xE0+reg32); } static osal_inline void shl_reg64_cl(unsigned int reg64) { put8(0x48); put8(0xD3); put8(0xE0+reg64); } static osal_inline void sar_reg32_imm8(unsigned int reg32, unsigned char imm8) { put8(0xC1); put8(0xF8+reg32); put8(imm8); } static osal_inline void sar_reg64_imm8(unsigned int reg64, unsigned char imm8) { put8(0x48); put8(0xC1); put8(0xF8+reg64); put8(imm8); } static osal_inline void mul_m32rel(unsigned int *m32) { int offset = rel_r15_offset(m32, "mul_m32rel"); put8(0x41); put8(0xF7); put8(0xA7); put32(offset); } static osal_inline void imul_reg32(unsigned int reg32) { put8(0xF7); put8(0xE8+reg32); } static osal_inline void mul_reg64(unsigned int reg64) { put8(0x48); put8(0xF7); put8(0xE0+reg64); } static osal_inline void mul_reg32(unsigned int reg32) { put8(0xF7); put8(0xE0+reg32); } static osal_inline void idiv_reg32(unsigned int reg32) { put8(0xF7); put8(0xF8+reg32); } static osal_inline void div_reg32(unsigned int reg32) { put8(0xF7); put8(0xF0+reg32); } static osal_inline void add_reg32_reg32(unsigned int reg1, unsigned int reg2) { put8(0x01); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void add_reg64_reg64(unsigned int reg1, unsigned int reg2) { put8(0x48); put8(0x01); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void jmp_reg64(unsigned int reg64) { put8(0xFF); put8(0xE0 + reg64); } static osal_inline void mov_reg32_preg64(unsigned int reg1, unsigned int reg2) { put8(0x8B); put8((reg1 << 3) | reg2); } static osal_inline void mov_preg64_reg32(int reg1, int reg2) { put8(0x89); put8((reg2 << 3) | reg1); } static osal_inline void mov_reg64_preg64(int reg1, int reg2) { put8(0x48); put8(0x8B); put8((reg1 << 3) | reg2); } static osal_inline void mov_reg32_preg64preg64pimm32(int reg1, int reg2, int reg3, unsigned int imm32) { put8(0x8B); put8((reg1 << 3) | 0x84); put8(reg2 | (reg3 << 3)); put32(imm32); } static osal_inline void mov_preg64preg64pimm32_reg32(int reg1, int reg2, unsigned int imm32, int reg3) { put8(0x89); put8((reg3 << 3) | 0x84); put8(reg1 | (reg2 << 3)); put32(imm32); } static osal_inline void mov_reg64_preg64preg64pimm32(int reg1, int reg2, int reg3, unsigned int imm32) { put8(0x48); put8(0x8B); put8((reg1 << 3) | 0x84); put8(reg2 | (reg3 << 3)); put32(imm32); } static osal_inline void mov_reg32_preg64preg64(int reg1, int reg2, int reg3) { put8(0x8B); put8((reg1 << 3) | 0x04); put8((reg2 << 3) | reg3); } static osal_inline void mov_reg64_preg64preg64(int reg1, int reg2, int reg3) { put8(0x48); put8(0x8B); put8((reg1 << 3) | 0x04); put8(reg2 | (reg3 << 3)); } static osal_inline void mov_reg32_preg64pimm32(int reg1, int reg2, unsigned int imm32) { put8(0x8B); put8(0x80 | (reg1 << 3) | reg2); put32(imm32); } static osal_inline void mov_reg64_preg64pimm32(int reg1, int reg2, unsigned int imm32) { put8(0x48); put8(0x8B); put8(0x80 | (reg1 << 3) | reg2); put32(imm32); } static osal_inline void mov_reg64_preg64pimm8(int reg1, int reg2, unsigned int imm8) { put8(0x48); put8(0x8B); put8(0x40 | (reg1 << 3) | reg2); put8(imm8); } static osal_inline void lea_reg64_preg64x2preg64(int reg1, int reg2, int reg3) { put8(0x48); put8(0x8D); put8(0x04 | (reg1 << 3)); put8(0x40 | (reg2 << 3) | reg3); } static osal_inline void mov_reg64_preg64x8preg64(int reg1, int reg2, int reg3) { put8(0x48); put8(0x8B); put8((reg1 << 3) | 4); put8(0xC0 | (reg2 << 3) | reg3); } static osal_inline void mov_preg64preg64_reg8(int reg1, int reg2, int reg8) { put8(0x88); put8(0x04 | (reg8 << 3)); put8((reg1 << 3) | reg2); } static osal_inline void mov_preg64preg64_imm8(int reg1, int reg2, unsigned char imm8) { put8(0xC6); put8(0x04); put8((reg1 << 3) | reg2); put8(imm8); } static osal_inline void mov_preg64preg64_reg16(int reg1, int reg2, int reg16) { put8(0x66); put8(0x89); put8(0x04 | (reg16 << 3)); put8((reg1 << 3) | reg2); } static osal_inline void mov_preg64preg64_reg32(int reg1, int reg2, int reg32) { put8(0x89); put8(0x04 | (reg32 << 3)); put8((reg1 << 3) | reg2); } static osal_inline void mov_preg64pimm32_reg32(int reg1, unsigned int imm32, int reg2) { put8(0x89); put8(0x80 | reg1 | (reg2 << 3)); put32(imm32); } static osal_inline void mov_preg64pimm8_reg64(int reg1, unsigned int imm8, int reg2) { put8(0x48); put8(0x89); put8(0x40 | (reg2 << 3) | reg1); put8(imm8); } static osal_inline void add_eax_imm32(unsigned int imm32) { put8(0x05); put32(imm32); } static osal_inline void shl_reg32_imm8(unsigned int reg32, unsigned char imm8) { put8(0xC1); put8(0xE0 + reg32); put8(imm8); } static osal_inline void shl_reg64_imm8(unsigned int reg64, unsigned char imm8) { put8(0x48); put8(0xC1); put8(0xE0 + reg64); put8(imm8); } static osal_inline void mov_reg32_reg32(unsigned int reg1, unsigned int reg2) { if (reg1 == reg2) return; put8(0x89); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void mov_reg64_reg64(unsigned int reg1, unsigned int reg2) { if (reg1 == reg2) return; put8(0x48); put8(0x89); put8(0xC0 | (reg2 << 3) | reg1); } static osal_inline void mov_xreg32_m32rel(unsigned int xreg32, unsigned int *m32) { int offset = rel_r15_offset(m32, "mov_xreg32_m32rel"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x8B); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void mov_m32rel_xreg32(unsigned int *m32, unsigned int xreg32) { int offset = rel_r15_offset(m32, "mov_m32rel_xreg32"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x89); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void mov_xreg64_m64rel(unsigned int xreg64, unsigned long long* m64) { int offset = rel_r15_offset(m64, "mov_xreg64_m64rel"); put8(0x49 | ((xreg64 & 8) >> 1)); put8(0x8B); put8(0x87 | ((xreg64 & 7) << 3)); put32(offset); } static osal_inline void mov_m64rel_xreg64(unsigned long long *m64, unsigned int xreg64) { int offset = rel_r15_offset(m64, "mov_m64rel_xreg64"); put8(0x49 | ((xreg64 & 8) >> 1)); put8(0x89); put8(0x87 | ((xreg64 & 7) << 3)); put32(offset); } static osal_inline void mov_xreg8_m8rel(int xreg8, unsigned char *m8) { int offset = rel_r15_offset(m8, "mov_xreg8_m8rel"); put8(0x41 | ((xreg8 & 8) >> 1)); put8(0x8A); put8(0x87 | ((xreg8 & 7) << 3)); put32(offset); } static osal_inline void and_eax_imm32(unsigned int imm32) { put8(0x25); put32(imm32); } static osal_inline void or_reg64_imm32(int reg64, unsigned int imm32) { put8(0x48); put8(0x81); put8(0xC8 + reg64); put32(imm32); } static osal_inline void and_reg32_imm32(int reg32, unsigned int imm32) { put8(0x81); put8(0xE0 + reg32); put32(imm32); } static osal_inline void and_reg64_imm32(int reg64, unsigned int imm32) { put8(0x48); put8(0x81); put8(0xE0 + reg64); put32(imm32); } static osal_inline void and_reg64_imm8(int reg64, unsigned char imm8) { put8(0x48); put8(0x83); put8(0xE0 + reg64); put8(imm8); } static osal_inline void xor_reg64_imm32(int reg64, unsigned int imm32) { put8(0x48); put8(0x81); put8(0xF0 + reg64); put32(imm32); } static osal_inline void xor_reg8_imm8(int reg8, unsigned char imm8) { put8(0x40); /* we need an REX prefix to use the uniform byte registers */ put8(0x80); put8(0xF0 + reg8); put8(imm8); } static osal_inline void not_reg64(unsigned int reg64) { put8(0x48); put8(0xF7); put8(0xD0 + reg64); } static osal_inline void neg_reg32(unsigned int reg32) { put8(0xF7); put8(0xD8 + reg32); } static osal_inline void neg_reg64(unsigned int reg64) { put8(0x48); put8(0xF7); put8(0xD8 + reg64); } static osal_inline void movsx_xreg32_m8rel(int xreg32, unsigned char *m8) { int offset = rel_r15_offset(m8, "movsx_xreg32_m8rel"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x0F); put8(0xBE); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void movsx_reg32_8preg64preg64(int reg1, int reg2, int reg3) { put8(0x0F); put8(0xBE); put8((reg1 << 3) | 0x04); put8((reg2 << 3) | reg3); } static osal_inline void movsx_reg32_16preg64preg64(int reg1, int reg2, int reg3) { put8(0x0F); put8(0xBF); put8((reg1 << 3) | 0x04); put8((reg2 << 3) | reg3); } static osal_inline void movsx_xreg32_m16rel(int xreg32, unsigned short *m16) { int offset = rel_r15_offset(m16, "movsx_xreg32_m16rel"); put8(0x41 | ((xreg32 & 8) >> 1)); put8(0x0F); put8(0xBF); put8(0x87 | ((xreg32 & 7) << 3)); put32(offset); } static osal_inline void movsxd_reg64_reg32(int reg64, int reg32) { put8(0x48); put8(0x63); put8((reg64 << 3) | reg32 | 0xC0); } static osal_inline void fldcw_m16rel(unsigned short *m16) { int offset = rel_r15_offset(m16, "fldcw_m16rel"); put8(0x41); put8(0xD9); put8(0xAF); put32(offset); } static osal_inline void fld_preg64_dword(int reg64) { put8(0xD9); put8(reg64); } static osal_inline void fdiv_preg64_dword(int reg64) { put8(0xD8); put8(0x30 + reg64); } static osal_inline void fstp_preg64_dword(int reg64) { put8(0xD9); put8(0x18 + reg64); } static osal_inline void fchs(void) { put8(0xD9); put8(0xE0); } static osal_inline void fstp_preg64_qword(int reg64) { put8(0xDD); put8(0x18 + reg64); } static osal_inline void fadd_preg64_dword(int reg64) { put8(0xD8); put8(reg64); } static osal_inline void fsub_preg64_dword(int reg64) { put8(0xD8); put8(0x20 + reg64); } static osal_inline void fmul_preg64_dword(int reg64) { put8(0xD8); put8(0x08 + reg64); } static osal_inline void fistp_preg64_dword(int reg64) { put8(0xDB); put8(0x18 + reg64); } static osal_inline void fistp_preg64_qword(int reg64) { put8(0xDF); put8(0x38 + reg64); } static osal_inline void fld_preg64_qword(int reg64) { put8(0xDD); put8(reg64); } static osal_inline void fild_preg64_qword(int reg64) { put8(0xDF); put8(0x28+reg64); } static osal_inline void fild_preg64_dword(int reg64) { put8(0xDB); put8(reg64); } static osal_inline void fadd_preg64_qword(int reg64) { put8(0xDC); put8(reg64); } static osal_inline void fdiv_preg64_qword(int reg64) { put8(0xDC); put8(0x30 + reg64); } static osal_inline void fsub_preg64_qword(int reg64) { put8(0xDC); put8(0x20 + reg64); } static osal_inline void fmul_preg64_qword(int reg64) { put8(0xDC); put8(0x08 + reg64); } static osal_inline void fsqrt(void) { put8(0xD9); put8(0xFA); } static osal_inline void fabs_(void) { put8(0xD9); put8(0xE1); } static osal_inline void fcomip_fpreg(int fpreg) { put8(0xDF); put8(0xF0 + fpreg); } static osal_inline void fucomip_fpreg(int fpreg) { put8(0xDF); put8(0xE8 + fpreg); } static osal_inline void ffree_fpreg(int fpreg) { put8(0xDD); put8(0xC0 + fpreg); } #endif /* M64P_DEVICE_R4300_X86_64_ASSEMBLE_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/assemble_struct.h000066400000000000000000000050511464506436200245530ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - assemble_struct.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2007 Richard Goedeken (Richard42) * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_X86_64_ASSEMBLE_STRUCT_H #define M64P_DEVICE_R4300_X86_64_ASSEMBLE_STRUCT_H struct precomp_instr; struct regcache_state { unsigned long long * reg_content[8]; struct precomp_instr* last_access[8]; struct precomp_instr* free_since[8]; int dirty[8]; int is64bits[8]; unsigned long long *r0; }; struct reg_cache { int need_map; void *needed_registers[8]; unsigned char jump_wrapper[84]; int need_cop1_check; }; struct jump_table { unsigned int mi_addr; unsigned int pc_addr; unsigned int absolute64; }; struct riprelative_table { unsigned int pc_addr; /* index in bytes from start of x86_64 code block to the displacement value to write */ unsigned int extra_bytes; /* number of remaining instruction bytes (immediate data) after 4-byte displacement */ unsigned char *global_dst; /* 64-bit pointer to the data object */ }; #endif /* M64P_DEVICE_R4300_X86_64_ASSEMBLE_STRUCT_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/dyna_start.asm000066400000000000000000000060341464506436200240570ustar00rootroot00000000000000;Mupen64plus - dyna_start.asm ;Mupen64Plus homepage: https://mupen64plus.org/ ;Copyright (C) 2007 Richard Goedeken (Richard42) ;Copyright (C) 2002 Hacktarux ; ;This program is free software; you can redistribute it and/or modify ;it under the terms of the GNU General Public License as published by ;the Free Software Foundation; either version 2 of the License, or ;(at your option) any later version. ; ;This program is distributed in the hope that it will be useful, ;but WITHOUT ANY WARRANTY; without even the implied warranty of ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;GNU General Public License for more details. ; ;You should have received a copy of the GNU General Public License ;along with this program; if not, write to the ;Free Software Foundation, Inc., ;51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. %include "asm_defines_nasm.h" %ifidn __OUTPUT_FORMAT__,elf section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf32 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf64 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifdef LEADING_UNDERSCORE %macro cglobal 1 global _%1 %define %1 _%1 %endmacro %macro cextern 1 extern _%1 %define %1 _%1 %endmacro %else %macro cglobal 1 global %1 %endmacro %macro cextern 1 extern %1 %endmacro %endif %define g_dev_r4300_recomp_save_rsp (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_rsp) %define g_dev_r4300_recomp_save_rip (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_save_rip) %define g_dev_r4300_recomp_return_address (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_recomp + offsetof_struct_recomp_return_address) %define g_dev_r4300_regs (g_dev + offsetof_struct_device_r4300 + offsetof_struct_r4300_core_regs) cglobal dyna_start cextern g_dev section .bss align 4 section .rodata section .text dyna_start: ;we must push an even # of registers to keep stack 16-byte aligned %ifdef WIN64 push rdi push rsi %endif push rbx push r12 push r13 push r14 push r15 push rbp mov [rel g_dev_r4300_recomp_save_rsp], rsp lea r15, [rel g_dev_r4300_regs] ;store the base location of the r4300 registers in r15 for addressing call _A1 jmp _A2 _A1: pop rax mov [rel g_dev_r4300_recomp_save_rip], rax sub rsp, 0x20 and rsp, 0xFFFFFFFFFFFFFFF0 ;ensure that stack is 16-byte aligned mov rax, rsp sub rax, 8 mov [rel g_dev_r4300_recomp_return_address], rax %ifdef WIN64 call rcx %else call rdi %endif _A2: mov rsp, [rel g_dev_r4300_recomp_save_rsp] pop rbp pop r15 pop r14 pop r13 pop r12 pop rbx %ifdef WIN64 pop rsi pop rdi %endif mov QWORD [rel g_dev_r4300_recomp_save_rsp], 0 mov QWORD [rel g_dev_r4300_recomp_save_rip], 0 ret mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/dynarec.c000066400000000000000000006143421464506436200230050ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dynarec.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2007 Richard Goedeken (Richard42) * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "assemble.h" #include "assemble_struct.h" #include "interpret.h" #include "regcache.h" #include "api/callbacks.h" #include "api/debugger.h" #include "api/m64p_types.h" #include "device/memory/memory.h" #include "device/r4300/cached_interp.h" #include "device/r4300/cp0.h" #include "device/r4300/cp1.h" #include "device/r4300/interrupt.h" #include "device/r4300/recomp.h" #include "device/rdram/rdram.h" #include "main/main.h" #if defined(COUNT_INSTR) #include "device/r4300/instr_counters.h" #endif #include #include #include #include #include #if !defined(offsetof) # define offsetof(TYPE,MEMBER) ((unsigned int) &((TYPE*)0)->MEMBER) #endif /* These are constants with addresses so that FLDCW can read them */ static const uint16_t trunc_mode = 0xf3f; static const uint16_t round_mode = 0x33f; static const uint16_t ceil_mode = 0xb3f; static const uint16_t floor_mode = 0x73f; static const unsigned int precomp_instr_size = sizeof(struct precomp_instr); /* Dynarec control functions */ void dyna_jump(void) { struct r4300_core* r4300 = &g_dev.r4300; if (*r4300_stop(r4300) == 1) { dyna_stop(r4300); return; } if ((*r4300_pc_struct(r4300))->reg_cache_infos.need_map) { *r4300->recomp.return_address = (unsigned long long) ((*r4300_pc_struct(r4300))->reg_cache_infos.jump_wrapper); } else { *r4300->recomp.return_address = (unsigned long long) (r4300->cached_interp.actual->code + (*r4300_pc_struct(r4300))->local_addr); } } void dyna_stop(struct r4300_core* r4300) { if (r4300->recomp.save_rip == 0) { DebugMessage(M64MSG_WARNING, "Instruction pointer is 0 at dyna_stop()"); } else { *r4300->recomp.return_address = (unsigned long long) r4300->recomp.save_rip; } } /* M64P Pseudo instructions */ static void gencallinterp(struct r4300_core* r4300, uintptr_t addr, int jump) { free_registers_move_start(r4300); if (jump) { mov_m32rel_imm32((unsigned int*)(&r4300->recomp.dyna_interp), 1); } mov_reg64_imm64(RAX, (unsigned long long) r4300->recomp.dst); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, addr); call_reg64(RAX); if (jump) { mov_m32rel_imm32((unsigned int*)(&r4300->recomp.dyna_interp), 0); mov_reg64_imm64(RAX, (unsigned long long)dyna_jump); call_reg64(RAX); } } static void gencheck_cop1_unusable(struct r4300_core* r4300) { free_registers_move_start(r4300); test_m32rel_imm32((unsigned int*)&r4300_cp0_regs(&r4300->cp0)[CP0_STATUS_REG], CP0_STATUS_CU1); jne_rj(0); jump_start_rel8(r4300); gencallinterp(r4300, (unsigned long long)dynarec_check_cop1_unusable, 0); jump_end_rel8(r4300); } static void gencp0_update_count(struct r4300_core* r4300, unsigned int addr) { #if !defined(COMPARE_CORE) && !defined(DBG) mov_reg32_imm32(EAX, addr); sub_xreg32_m32rel(EAX, (unsigned int*)(&r4300->cp0.last_addr)); shr_reg32_imm8(EAX, 2); mov_xreg32_m32rel(EDX, (void*)&r4300->cp0.count_per_op); mul_reg32(EDX); if (r4300->cp0.count_per_op_denom_pot) { add_reg32_imm32(EAX, (1 << g_dev.r4300.cp0.count_per_op_denom_pot) - 1); shr_reg32_imm8(EAX, g_dev.r4300.cp0.count_per_op_denom_pot); } add_m32rel_xreg32((unsigned int*)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), EAX); add_m32rel_xreg32((unsigned int*)(r4300_cp0_cycle_count(&r4300->cp0)), EAX); #else mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long)dynarec_cp0_update_count); call_reg64(RAX); #endif } static void gencheck_interrupt(struct r4300_core* r4300, unsigned long long instr_structure) { mov_xreg32_m32rel(EAX, (void*)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(EAX, EAX); js_rj(0); jump_start_rel8(r4300); mov_reg64_imm64(RAX, (unsigned long long) instr_structure); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_gen_interrupt); call_reg64(RAX); jump_end_rel8(r4300); } static void gencheck_interrupt_out(struct r4300_core* r4300, unsigned int addr) { mov_xreg32_m32rel(EAX, (void*)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(EAX, EAX); js_rj(0); jump_start_rel8(r4300); mov_m32rel_imm32((unsigned int*)(&r4300->recomp.fake_instr.addr), addr); mov_reg64_imm64(RAX, (unsigned long long) (&r4300->recomp.fake_instr)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_gen_interrupt); call_reg64(RAX); jump_end_rel8(r4300); } static void gencheck_interrupt_reg(struct r4300_core* r4300) // addr is in EAX { mov_xreg32_m32rel(EBX, (void*)r4300_cp0_cycle_count(&r4300->cp0)); test_reg32_reg32(EBX, EBX); js_rj(0); jump_start_rel8(r4300); mov_m32rel_xreg32((unsigned int*)(&r4300->recomp.fake_instr.addr), EAX); mov_reg64_imm64(RAX, (unsigned long long) (&r4300->recomp.fake_instr)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_gen_interrupt); call_reg64(RAX); jump_end_rel8(r4300); } static void gendelayslot(struct r4300_core* r4300) { mov_m32rel_imm32((void*)(&r4300->delay_slot), 1); recompile_opcode(r4300); free_all_registers(r4300); gencp0_update_count(r4300, r4300->recomp.dst->addr+4); mov_m32rel_imm32((void*)(&r4300->delay_slot), 0); } static void ld_register_alloc(struct r4300_core* r4300, int *pGpr1, int *pGpr2, int *pBase1, int *pBase2) { int gpr1, gpr2, base1, base2 = 0; #ifdef COMPARE_CORE free_registers_move_start(r4300); // to maintain parity with 32-bit core #endif if (r4300->recomp.dst->f.i.rs == r4300->recomp.dst->f.i.rt) { allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); // tell regcache we need to read RS register here gpr1 = allocate_register_32_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); // tell regcache we will modify RT register during this instruction gpr2 = lock_register(r4300, lru_register(r4300)); // free and lock least recently used register for usage here add_reg32_imm32(gpr1, (int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(gpr2, gpr1); } else { gpr2 = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); // tell regcache we need to read RS register here gpr1 = allocate_register_32_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); // tell regcache we will modify RT register during this instruction free_register(r4300, gpr2); // write out gpr2 if dirty because I'm going to trash it right now add_reg32_imm32(gpr2, (int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(gpr1, gpr2); lock_register(r4300, gpr2); // lock the freed gpr2 it so it doesn't get returned in the lru query } base1 = lock_register(r4300, lru_base_register(r4300)); // get another lru register if (!r4300->recomp.fast_memory) { base2 = lock_register(r4300, lru_base_register(r4300)); // and another one if necessary unlock_register(r4300, base2); } unlock_register(r4300, base1); // unlock the locked registers (they are unlock_register(r4300, gpr2); set_register_state(r4300, gpr1, NULL, 0, 0); // clear gpr1 state because it hasn't been written yet - // we don't want it to be pushed/popped around read_rdramX call *pGpr1 = gpr1; *pGpr2 = gpr2; *pBase1 = base1; *pBase2 = base2; } static void ld_register_alloc2(struct r4300_core* r4300, int *pGpr1, int *pGpr2, int *pBase1, int *pBase2) { int gpr1, gpr2, base1, base2; #ifdef COMPARE_CORE free_registers_move_start(r4300); // to maintain parity with 32-bit core #endif base2 = lock_register(r4300, ECX); // make sure we get ECX for base2 if (r4300->recomp.dst->f.i.rs == r4300->recomp.dst->f.i.rt) { allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); // tell regcache we need to read RS register here gpr1 = allocate_register_32_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); // tell regcache we will modify RT register during this instruction gpr2 = lock_register(r4300, lru_register(r4300)); // free and lock least recently used register for usage here add_reg32_imm32(gpr1, (int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(gpr2, gpr1); } else { gpr2 = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); // tell regcache we need to read RS register here gpr1 = allocate_register_32_w(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); // tell regcache we will modify RT register during this instruction free_register(r4300, gpr2); // write out gpr2 if dirty because I'm going to trash it right now add_reg32_imm32(gpr2, (int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(gpr1, gpr2); lock_register(r4300, gpr2); // lock the freed gpr2 it so it doesn't get returned in the lru query } base1 = lock_register(r4300, lru_base_register(r4300)); // get another lru register unlock_register(r4300, base2); unlock_register(r4300, base1); // unlock the locked registers (they are unlock_register(r4300, gpr2); set_register_state(r4300, gpr1, NULL, 0, 0); // clear gpr1 state because it hasn't been written yet - // we don't want it to be pushed/popped around read_rdramX call *pGpr1 = gpr1; *pGpr2 = gpr2; *pBase1 = base1; *pBase2 = base2; /* base2 is RCX */ assert(gpr1 != RCX); assert(gpr2 != RCX); assert(base1 != RCX); assert(base2 == RCX); } #ifdef COMPARE_CORE extern unsigned int op; /* api/debugger.c */ void gendebug(struct r4300_core* r4300) { free_all_registers(r4300); mov_memoffs64_rax((unsigned long long *) &r4300->recomp.debug_reg_storage); mov_reg64_imm64(RAX, (unsigned long long) &r4300->recomp.debug_reg_storage); mov_preg64pimm8_reg64(RAX, 8, RBX); mov_preg64pimm8_reg64(RAX, 16, RCX); mov_preg64pimm8_reg64(RAX, 24, RDX); mov_preg64pimm8_reg64(RAX, 32, RSP); mov_preg64pimm8_reg64(RAX, 40, RBP); mov_preg64pimm8_reg64(RAX, 48, RSI); mov_preg64pimm8_reg64(RAX, 56, RDI); mov_reg64_imm64(RAX, (unsigned long long) r4300->recomp.dst); mov_memoffs64_rax((unsigned long long *) &(*r4300_pc_struct(r4300))); mov_reg32_imm32(EAX, (unsigned int) r4300->recomp.src); mov_memoffs32_eax((unsigned int *) &op); mov_reg64_imm64(RAX, (unsigned long long) CoreCompareCallback); call_reg64(RAX); mov_reg64_imm64(RAX, (unsigned long long) &r4300->recomp.debug_reg_storage); mov_reg64_preg64pimm8(RDI, RAX, 56); mov_reg64_preg64pimm8(RSI, RAX, 48); mov_reg64_preg64pimm8(RBP, RAX, 40); mov_reg64_preg64pimm8(RSP, RAX, 32); mov_reg64_preg64pimm8(RDX, RAX, 24); mov_reg64_preg64pimm8(RCX, RAX, 16); mov_reg64_preg64pimm8(RBX, RAX, 8); mov_reg64_preg64(RAX, RAX); } #endif void genni(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[1]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_NI, 0); } void gennotcompiled(struct r4300_core* r4300) { free_registers_move_start(r4300); mov_reg64_imm64(RAX, (unsigned long long) r4300->recomp.dst); mov_memoffs64_rax((unsigned long long *) &(*r4300_pc_struct(r4300))); /* RIP-relative will not work here */ mov_reg64_imm64(RAX, (unsigned long long) dynarec_notcompiled); call_reg64(RAX); } void genlink_subblock(struct r4300_core* r4300) { free_all_registers(r4300); jmp(r4300->recomp.dst->addr+4); } void genfin_block(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)dynarec_fin_block, 0); } /* Reserved */ void gen_RESERVED(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[0]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_RESERVED, 0); } /* Load instructions */ void gen_LB(struct r4300_core* r4300) { int gpr1, gpr2, base1, base2; #if defined(COUNT_INSTR) inc_m32rel(&instr_count[24]); #endif #ifdef INTERPRET_LB gencallinterp(r4300, (unsigned long long)cached_interp_LB, 0); #else free_registers_move_start(r4300); ld_register_alloc2(r4300, &gpr1, &gpr2, &base1, &base2); /* is address in RDRAM ? */ and_reg32_imm32(gpr1, 0xDF800000); cmp_reg32_imm32(gpr1, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(gpr1, 16); and_reg32_imm32(gpr1, 0x1fff); lea_reg64_preg64x2preg64(gpr1, gpr1, gpr1); mov_reg64_imm64(base1, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(gpr1, gpr1, base1); mov_reg64_imm64(base1, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(gpr1, base1); jump_end_rel8(r4300); } je_rj(0); jump_start_rel8(r4300); mov_reg64_imm64(gpr1, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), gpr1); /* if non RDRAM read, * compute shift (base2) and address (gpr2) to perform a regular read. * Save base2 content to memory as RCX can be overwritten when calling read32 function */ mov_reg64_reg64(base2, gpr2); and_reg64_imm8(base2, 3); xor_reg8_imm8(base2, 3); shl_reg64_imm8(base2, 3); mov_m64rel_xreg64(&r4300->recomp.shift, base2); mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), gpr2); mov_reg64_imm64(gpr1, (unsigned long long) r4300->recomp.dst->f.i.rt); mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), gpr1); mov_reg64_imm64(gpr2, (unsigned long long)dynarec_read_aligned_word); call_reg64(gpr2); and_reg64_reg64(RAX, RAX); je_rj(57); mov_xreg64_m64rel(gpr1, (unsigned long long*)r4300->recomp.dst->f.i.rt); // 7 mov_xreg64_m64rel(RCX, &r4300->recomp.shift); // 7 shr_reg64_cl(gpr1); // 3 mov_m64rel_xreg64((unsigned long long*)r4300->recomp.dst->f.i.rt, gpr1); // 7 movsx_xreg32_m8rel(gpr1, (unsigned char *)r4300->recomp.dst->f.i.rt); // 7 jmp_imm_short(24); // 2 /* else (RDRAM read), read byte */ jump_end_rel8(r4300); mov_reg64_imm64(base1, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(gpr2, 0x7FFFFF); // 6 xor_reg8_imm8(gpr2, 3); // 4 movsx_reg32_8preg64preg64(gpr1, gpr2, base1); // 4 set_register_state(r4300, gpr1, (unsigned int*)r4300->recomp.dst->f.i.rt, 1, 0); #endif } void gen_LBU(struct r4300_core* r4300) { int gpr1, gpr2, base1, base2; #if defined(COUNT_INSTR) inc_m32rel(&instr_count[28]); #endif #ifdef INTERPRET_LBU gencallinterp(r4300, (unsigned long long)cached_interp_LBU, 0); #else free_registers_move_start(r4300); ld_register_alloc2(r4300, &gpr1, &gpr2, &base1, &base2); /* is address in RDRAM ? */ and_reg32_imm32(gpr1, 0xDF800000); cmp_reg32_imm32(gpr1, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(gpr1, 16); and_reg32_imm32(gpr1, 0x1fff); lea_reg64_preg64x2preg64(gpr1, gpr1, gpr1); mov_reg64_imm64(base1, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(gpr1, gpr1, base1); mov_reg64_imm64(base1, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(gpr1, base1); jump_end_rel8(r4300); } je_rj(0); jump_start_rel8(r4300); mov_reg64_imm64(gpr1, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), gpr1); /* if non RDRAM read, * compute shift (base2) and address (gpr2) to perform a regular read. * Save base2 content to memory as RCX can be overwritten when calling read32 function */ mov_reg64_reg64(base2, gpr2); and_reg64_imm8(base2, 3); xor_reg8_imm8(base2, 3); shl_reg64_imm8(base2, 3); mov_m64rel_xreg64(&r4300->recomp.shift, base2); mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), gpr2); mov_reg64_imm64(gpr1, (unsigned long long) r4300->recomp.dst->f.i.rt); mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), gpr1); mov_reg64_imm64(gpr2, (unsigned long long)dynarec_read_aligned_word); call_reg64(gpr2); and_reg64_reg64(RAX, RAX); je_rj(48); mov_xreg32_m32rel(gpr1, (unsigned int *)r4300->recomp.dst->f.i.rt); // 7 mov_xreg64_m64rel(RCX, &r4300->recomp.shift); // 7 shr_reg64_cl(gpr1); // 3 jmp_imm_short(23); // 2 /* else (RDRAM read), read byte */ jump_end_rel8(r4300); mov_reg64_imm64(base1, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(gpr2, 0x7FFFFF); // 6 xor_reg8_imm8(gpr2, 3); // 4 mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3 and_reg32_imm32(gpr1, 0xFF); // 6 set_register_state(r4300, gpr1, (unsigned int*)r4300->recomp.dst->f.i.rt, 1, 0); #endif } void gen_LH(struct r4300_core* r4300) { int gpr1, gpr2, base1, base2; #if defined(COUNT_INSTR) inc_m32rel(&instr_count[25]); #endif #ifdef INTERPRET_LH gencallinterp(r4300, (unsigned long long)cached_interp_LH, 0); #else free_registers_move_start(r4300); ld_register_alloc2(r4300, &gpr1, &gpr2, &base1, &base2); /* is address in RDRAM ? */ and_reg32_imm32(gpr1, 0xDF800000); cmp_reg32_imm32(gpr1, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(gpr1, 16); and_reg32_imm32(gpr1, 0x1fff); lea_reg64_preg64x2preg64(gpr1, gpr1, gpr1); mov_reg64_imm64(base1, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(gpr1, gpr1, base1); mov_reg64_imm64(base1, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(gpr1, base1); jump_end_rel8(r4300); } je_rj(0); jump_start_rel8(r4300); mov_reg64_imm64(gpr1, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), gpr1); /* if non RDRAM read, * compute shift (base2) and address (gpr2) to perform a regular read. * Save base2 content to memory as RCX can be overwritten when calling read32 function */ mov_reg64_reg64(base2, gpr2); and_reg64_imm8(base2, 2); xor_reg8_imm8(base2, 2); shl_reg64_imm8(base2, 3); mov_m64rel_xreg64(&r4300->recomp.shift, base2); mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), gpr2); mov_reg64_imm64(gpr1, (unsigned long long) r4300->recomp.dst->f.i.rt); mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), gpr1); mov_reg64_imm64(gpr2, (unsigned long long)dynarec_read_aligned_word); call_reg64(gpr2); and_reg64_reg64(RAX, RAX); je_rj(58); mov_xreg64_m64rel(gpr1, (unsigned long long*)r4300->recomp.dst->f.i.rt); // 7 mov_xreg64_m64rel(RCX, &r4300->recomp.shift); // 7 shr_reg64_cl(gpr1); // 3 mov_m64rel_xreg64((unsigned long long*)r4300->recomp.dst->f.i.rt, gpr1); // 7 movsx_xreg32_m16rel(gpr1, (unsigned short *)r4300->recomp.dst->f.i.rt); // 8 jmp_imm_short(24); // 2 jump_end_rel8(r4300); mov_reg64_imm64(base1, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(gpr2, 0x7FFFFF); // 6 xor_reg8_imm8(gpr2, 2); // 4 movsx_reg32_16preg64preg64(gpr1, gpr2, base1); // 4 set_register_state(r4300, gpr1, (unsigned int*)r4300->recomp.dst->f.i.rt, 1, 0); #endif } void gen_LHU(struct r4300_core* r4300) { int gpr1, gpr2, base1, base2; #if defined(COUNT_INSTR) inc_m32rel(&instr_count[29]); #endif #ifdef INTERPRET_LHU gencallinterp(r4300, (unsigned long long)cached_interp_LHU, 0); #else free_registers_move_start(r4300); ld_register_alloc2(r4300, &gpr1, &gpr2, &base1, &base2); /* is address in RDRAM ? */ and_reg32_imm32(gpr1, 0xDF800000); cmp_reg32_imm32(gpr1, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(gpr1, 16); and_reg32_imm32(gpr1, 0x1fff); lea_reg64_preg64x2preg64(gpr1, gpr1, gpr1); mov_reg64_imm64(base1, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(gpr1, gpr1, base1); mov_reg64_imm64(base1, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(gpr1, base1); jump_end_rel8(r4300); } je_rj(0); jump_start_rel8(r4300); mov_reg64_imm64(gpr1, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), gpr1); /* if non RDRAM read, * compute shift (base2) and address (gpr2) to perform a regular read. * Save base2 content to memory as RCX can be overwritten when calling read32 function */ mov_reg64_reg64(base2, gpr2); and_reg64_imm8(base2, 2); xor_reg8_imm8(base2, 2); shl_reg64_imm8(base2, 3); mov_m64rel_xreg64(&r4300->recomp.shift, base2); mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), gpr2); mov_reg64_imm64(gpr1, (unsigned long long) r4300->recomp.dst->f.i.rt); mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), gpr1); mov_reg64_imm64(gpr2, (unsigned long long)dynarec_read_aligned_word); call_reg64(gpr2); and_reg64_reg64(RAX, RAX); je_rj(48); mov_xreg32_m32rel(gpr1, (unsigned int *)r4300->recomp.dst->f.i.rt); // 7 mov_xreg64_m64rel(RCX, &r4300->recomp.shift); // 7 shr_reg64_cl(gpr1); // 3 jmp_imm_short(23); // 2 jump_end_rel8(r4300); mov_reg64_imm64(base1, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(gpr2, 0x7FFFFF); // 6 xor_reg8_imm8(gpr2, 2); // 4 mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3 and_reg32_imm32(gpr1, 0xFFFF); // 6 set_register_state(r4300, gpr1, (unsigned int*)r4300->recomp.dst->f.i.rt, 1, 0); #endif } void gen_LL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[42]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_LL, 0); } void gen_LW(struct r4300_core* r4300) { int gpr1, gpr2, base1, base2 = 0; #if defined(COUNT_INSTR) inc_m32rel(&instr_count[26]); #endif #ifdef INTERPRET_LW gencallinterp(r4300, (unsigned long long)cached_interp_LW, 0); #else free_registers_move_start(r4300); ld_register_alloc(r4300, &gpr1, &gpr2, &base1, &base2); /* is address in RDRAM ? */ and_reg32_imm32(gpr1, 0xDF800000); cmp_reg32_imm32(gpr1, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(gpr1, 16); and_reg32_imm32(gpr1, 0x1fff); lea_reg64_preg64x2preg64(gpr1, gpr1, gpr1); mov_reg64_imm64(base1, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(gpr1, gpr1, base1); mov_reg64_imm64(base1, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(gpr1, base1); jump_end_rel8(r4300); } jne_rj(21); mov_reg64_imm64(base1, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(gpr2, 0x7FFFFF); // 6 mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3 jmp_imm_short(0); // 2 jump_start_rel8(r4300); mov_reg64_imm64(gpr1, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), gpr1); mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), gpr2); mov_reg64_imm64(gpr1, (unsigned long long) r4300->recomp.dst->f.i.rt); mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), gpr1); mov_reg64_imm64(gpr1, (unsigned long long)dynarec_read_aligned_word); call_reg64(gpr1); mov_xreg32_m32rel(gpr1, (unsigned int *)(r4300->recomp.dst->f.i.rt)); jump_end_rel8(r4300); set_register_state(r4300, gpr1, (unsigned int*)r4300->recomp.dst->f.i.rt, 1, 0); // set gpr1 state as dirty, and bound to r4300 reg RT #endif } void gen_LWU(struct r4300_core* r4300) { int gpr1, gpr2, base1, base2 = 0; #if defined(COUNT_INSTR) inc_m32rel(&instr_count[30]); #endif #ifdef INTERPRET_LWU gencallinterp(r4300, (unsigned long long)cached_interp_LWU, 0); #else free_registers_move_start(r4300); ld_register_alloc(r4300, &gpr1, &gpr2, &base1, &base2); /* is address in RDRAM ? */ and_reg32_imm32(gpr1, 0xDF800000); cmp_reg32_imm32(gpr1, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(gpr1, 16); and_reg32_imm32(gpr1, 0x1fff); lea_reg64_preg64x2preg64(gpr1, gpr1, gpr1); mov_reg64_imm64(base1, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(gpr1, gpr1, base1); mov_reg64_imm64(base1, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(gpr1, base1); jump_end_rel8(r4300); } je_rj(0); jump_start_rel8(r4300); mov_reg64_imm64(gpr1, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), gpr1); mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), gpr2); mov_reg64_imm64(gpr1, (unsigned long long) r4300->recomp.dst->f.i.rt); mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), gpr1); mov_reg64_imm64(gpr2, (unsigned long long)dynarec_read_aligned_word); call_reg64(gpr2); mov_xreg32_m32rel(gpr1, (unsigned int *)r4300->recomp.dst->f.i.rt); jmp_imm_short(19); jump_end_rel8(r4300); mov_reg64_imm64(base1, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(gpr2, 0x7FFFFF); // 6 mov_reg32_preg64preg64(gpr1, gpr2, base1); // 3 set_register_state(r4300, gpr1, (unsigned int*)r4300->recomp.dst->f.i.rt, 1, 1); #endif } void gen_LWL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[27]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_LWL, 0); } void gen_LWR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[31]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_LWR, 0); } void gen_LD(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[41]); #endif #ifdef INTERPRET_LD gencallinterp(r4300, (unsigned long long)cached_interp_LD, 0); #else free_registers_move_start(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(62); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 mov_reg64_imm64(RAX, (unsigned long long) r4300->recomp.dst->f.i.rt); // 10 mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), RAX); // 7 mov_reg64_imm64(RBX, (unsigned long long)dynarec_read_aligned_dword); // 10 call_reg64(RBX); // 2 mov_xreg64_m64rel(RAX, (unsigned long long *)(r4300->recomp.dst->f.i.rt)); // 7 jmp_imm_short(33); // 2 mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg32_preg64preg64(EAX, RBX, RSI); // 3 mov_reg32_preg64preg64pimm32(EBX, RBX, RSI, 4); // 7 shl_reg64_imm8(RAX, 32); // 4 or_reg64_reg64(RAX, RBX); // 3 set_register_state(r4300, RAX, (unsigned int*)r4300->recomp.dst->f.i.rt, 1, 1); #endif } void gen_LDL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[22]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_LDL, 0); } void gen_LDR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[23]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_LDR, 0); } /* Store instructions */ void gen_SB(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[32]); #endif #ifdef INTERPRET_SB gencallinterp(r4300, (unsigned long long)cached_interp_SB, 0); #else free_registers_move_start(r4300); /* get value in EDX */ xor_reg64_reg64(RDX, RDX); mov_xreg8_m8rel(DL, (unsigned char *)r4300->recomp.dst->f.i.rt); /* get address in both EAX and EBX */ mov_xreg32_m32rel(EAX, (unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].write32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) write_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(88); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 /* if non RDRAM write, * compute shift (ECX), word (EDX), wmask (EDX) and address (EBX) to perform a regular write */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 3); // 6 xor_reg8_imm8(CL, 3); // 4 shl_reg32_imm8(ECX, 3); // 3 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 shl_reg32_cl(EDX); // 2 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wword), EDX); // 7 mov_reg64_imm64(RDX, 0xff); // 10 shl_reg32_cl(EDX); // 2 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wmask), EDX); // 7 mov_reg64_imm64(RBX, (unsigned long long)dynarec_write_aligned_word); // 10 call_reg64(RBX); // 2 mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300->recomp.address)); // 7 jmp_imm_short(25); // 2 /* else (RDRAM write), write byte */ mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 3); // 4 mov_preg64preg64_reg8(RBX, RSI, DL); // 3 mov_reg64_imm64(RSI, (unsigned long long) r4300->cached_interp.invalid_code); mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg64preg64_imm8(RBX, RSI, 0); jne_rj(65); mov_reg64_imm64(RDI, (unsigned long long) r4300->cached_interp.blocks); // 10 mov_reg32_reg32(ECX, EBX); // 2 mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4 mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(struct precomp_block, block)); // 7 mov_reg64_imm64(RDI, (unsigned long long) dynarec_notcompiled); // 10 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(struct precomp_instr, ops)); // 8 cmp_reg64_reg64(RAX, RDI); // 3 je_rj(4); // 2 mov_preg64preg64_imm8(RCX, RSI, 1); // 4 #endif } void gen_SH(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[33]); #endif #ifdef INTERPRET_SH gencallinterp(r4300, (unsigned long long)cached_interp_SH, 0); #else free_registers_move_start(r4300); /* get value in EDX */ xor_reg64_reg64(RDX, RDX); mov_xreg16_m16rel(DX, (unsigned short *)r4300->recomp.dst->f.i.rt); /* get address in both EAX and EBX */ mov_xreg32_m32rel(EAX, (unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].write32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) write_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(88); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 /* if non RDRAM write, * compute shift (ECX), word (EDX), wmask (EDX) and address (EBX) to perform a regular write */ mov_reg32_reg32(ECX, EBX); // 2 and_reg32_imm32(ECX, 2); // 6 xor_reg8_imm8(CL, 2); // 4 shl_reg32_imm8(ECX, 3); // 3 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 shl_reg32_cl(EDX); // 2 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wword), EDX); // 7 mov_reg64_imm64(RDX, 0xffff); // 10 shl_reg32_cl(EDX); // 2 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wmask), EDX); // 7 mov_reg64_imm64(RBX, (unsigned long long)dynarec_write_aligned_word); // 10 call_reg64(RBX); // 2 mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300->recomp.address)); // 7 jmp_imm_short(26); // 2 /* else (RDRAM write), write hword */ mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 xor_reg8_imm8(BL, 2); // 4 mov_preg64preg64_reg16(RBX, RSI, DX); // 4 mov_reg64_imm64(RSI, (unsigned long long) r4300->cached_interp.invalid_code); mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg64preg64_imm8(RBX, RSI, 0); jne_rj(65); mov_reg64_imm64(RDI, (unsigned long long) r4300->cached_interp.blocks); // 10 mov_reg32_reg32(ECX, EBX); // 2 mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4 mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(struct precomp_block, block)); // 7 mov_reg64_imm64(RDI, (unsigned long long) dynarec_notcompiled); // 10 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(struct precomp_instr, ops)); // 8 cmp_reg64_reg64(RAX, RDI); // 3 je_rj(4); // 2 mov_preg64preg64_imm8(RCX, RSI, 1); // 4 #endif } void gen_SC(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[46]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_SC, 0); } void gen_SW(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[34]); #endif #ifdef INTERPRET_SW gencallinterp(r4300, (unsigned long long)cached_interp_SW, 0); #else free_registers_move_start(r4300); mov_xreg32_m32rel(ECX, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_xreg32_m32rel(EAX, (unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].write32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) write_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(63); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wword), ECX); // 7 mov_m32rel_imm32((unsigned int *)(&r4300->recomp.wmask), ~UINT32_C(0)); // 11 mov_reg64_imm64(RBX, (unsigned long long)dynarec_write_aligned_word); // 10 call_reg64(RBX); // 2 mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300->recomp.address)); // 7 jmp_imm_short(21); // 2 mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg64preg64_reg32(RBX, RSI, ECX); // 3 mov_reg64_imm64(RSI, (unsigned long long) r4300->cached_interp.invalid_code); mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg64preg64_imm8(RBX, RSI, 0); jne_rj(65); mov_reg64_imm64(RDI, (unsigned long long) r4300->cached_interp.blocks); // 10 mov_reg32_reg32(ECX, EBX); // 2 mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4 mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(struct precomp_block, block)); // 7 mov_reg64_imm64(RDI, (unsigned long long) dynarec_notcompiled); // 10 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(struct precomp_instr, ops)); // 8 cmp_reg64_reg64(RAX, RDI); // 3 je_rj(4); // 2 mov_preg64preg64_imm8(RCX, RSI, 1); // 4 #endif } void gen_SWL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[35]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_SWL, 0); } void gen_SWR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[36]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_SWR, 0); } void gen_SD(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[45]); #endif #ifdef INTERPRET_SD gencallinterp(r4300, (unsigned long long)cached_interp_SD, 0); #else free_registers_move_start(r4300); mov_xreg32_m32rel(ECX, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_xreg32_m32rel(EDX, ((unsigned int *)r4300->recomp.dst->f.i.rt)+1); mov_xreg32_m32rel(EAX, (unsigned int *)r4300->recomp.dst->f.i.rs); add_eax_imm32((int)r4300->recomp.dst->f.i.immediate); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].write32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) write_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(59); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wdword), ECX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wdword)+1, EDX); // 7 mov_reg64_imm64(RBX, (unsigned long long)dynarec_write_aligned_dword); // 10 call_reg64(RBX); // 2 mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300->recomp.address)); // 7 jmp_imm_short(28); // 2 mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg64preg64pimm32_reg32(RBX, RSI, 4, ECX); // 7 mov_preg64preg64_reg32(RBX, RSI, EDX); // 3 mov_reg64_imm64(RSI, (unsigned long long) r4300->cached_interp.invalid_code); mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg64preg64_imm8(RBX, RSI, 0); jne_rj(65); mov_reg64_imm64(RDI, (unsigned long long) r4300->cached_interp.blocks); // 10 mov_reg32_reg32(ECX, EBX); // 2 mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4 mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(struct precomp_block, block)); // 7 mov_reg64_imm64(RDI, (unsigned long long) dynarec_notcompiled); // 10 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(struct precomp_instr, ops)); // 8 cmp_reg64_reg64(RAX, RDI); // 3 je_rj(4); // 2 mov_preg64preg64_imm8(RCX, RSI, 1); // 4 #endif } void gen_SDL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[37]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_SDL, 0); } void gen_SDR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[38]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_SDR, 0); } /* Computational instructions */ void gen_ADD(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[79]); #endif #ifdef INTERPRET_ADD gencallinterp(r4300, (unsigned long long)cached_interp_ADD, 0); #else int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rs == rd) { add_reg32_reg32(rd, rt); } else if (rt == rd) { add_reg32_reg32(rd, rs); } else { mov_reg32_reg32(rd, rs); add_reg32_reg32(rd, rt); } #endif } void gen_ADDU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[80]); #endif #ifdef INTERPRET_ADDU gencallinterp(r4300, (unsigned long long)cached_interp_ADDU, 0); #else int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rs == rd) { add_reg32_reg32(rd, rt); } else if (rt == rd) { add_reg32_reg32(rd, rs); } else { mov_reg32_reg32(rd, rs); add_reg32_reg32(rd, rt); } #endif } void gen_ADDI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[8]); #endif #ifdef INTERPRET_ADDI gencallinterp(r4300, (unsigned long long)cached_interp_ADDI, 0); #else int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt, rs); add_reg32_imm32(rt,(int)r4300->recomp.dst->f.i.immediate); #endif } void gen_ADDIU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[9]); #endif #ifdef INTERPRET_ADDIU gencallinterp(r4300, (unsigned long long)cached_interp_ADDIU, 0); #else int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_reg32(rt, rs); add_reg32_imm32(rt,(int)r4300->recomp.dst->f.i.immediate); #endif } void gen_DADD(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[89]); #endif #ifdef INTERPRET_DADD gencallinterp(r4300, (unsigned long long)cached_interp_DADD, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { add_reg64_reg64(rd, rt); } else if (rt == rd) { add_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); add_reg64_reg64(rd, rt); } #endif } void gen_DADDU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[90]); #endif #ifdef INTERPRET_DADDU gencallinterp(r4300, (unsigned long long)cached_interp_DADDU, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { add_reg64_reg64(rd, rt); } else if (rt == rd) { add_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); add_reg64_reg64(rd, rt); } #endif } void gen_DADDI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[20]); #endif #ifdef INTERPRET_DADDI gencallinterp(r4300, (unsigned long long)cached_interp_DADDI, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); mov_reg64_reg64(rt, rs); add_reg64_imm32(rt, (int) r4300->recomp.dst->f.i.immediate); #endif } void gen_DADDIU(struct r4300_core* r4300) { #ifdef INTERPRET_DADDIU gencallinterp(r4300, (unsigned long long)cached_interp_DADDIU, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); mov_reg64_reg64(rt, rs); add_reg64_imm32(rt, (int) r4300->recomp.dst->f.i.immediate); #endif } void gen_SUB(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[81]); #endif #ifdef INTERPRET_SUB gencallinterp(r4300, (unsigned long long)cached_interp_SUB, 0); #else int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rs == rd) { sub_reg32_reg32(rd, rt); } else if (rt == rd) { neg_reg32(rd); add_reg32_reg32(rd, rs); } else { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } #endif } void gen_SUBU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[82]); #endif #ifdef INTERPRET_SUBU gencallinterp(r4300, (unsigned long long)cached_interp_SUBU, 0); #else int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rs == rd) { sub_reg32_reg32(rd, rt); } else if (rt == rd) { neg_reg32(rd); add_reg32_reg32(rd, rs); } else { mov_reg32_reg32(rd, rs); sub_reg32_reg32(rd, rt); } #endif } void gen_DSUB(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[91]); #endif #ifdef INTERPRET_DSUB gencallinterp(r4300, (unsigned long long)cached_interp_DSUB, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { sub_reg64_reg64(rd, rt); } else if (rt == rd) { neg_reg64(rd); add_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); sub_reg64_reg64(rd, rt); } #endif } void gen_DSUBU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[92]); #endif #ifdef INTERPRET_DSUBU gencallinterp(r4300, (unsigned long long)cached_interp_DSUBU, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { sub_reg64_reg64(rd, rt); } else if (rt == rd) { neg_reg64(rd); add_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); sub_reg64_reg64(rd, rt); } #endif } void gen_SLT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[87]); #endif #ifdef INTERPRET_SLT gencallinterp(r4300, (unsigned long long)cached_interp_SLT, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); cmp_reg64_reg64(rs, rt); setl_reg8(rd); and_reg64_imm8(rd, 1); #endif } void gen_SLTU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[88]); #endif #ifdef INTERPRET_SLTU gencallinterp(r4300, (unsigned long long)cached_interp_SLTU, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); cmp_reg64_reg64(rs, rt); setb_reg8(rd); and_reg64_imm8(rd, 1); #endif } void gen_SLTI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[10]); #endif #ifdef INTERPRET_SLTI gencallinterp(r4300, (unsigned long long)cached_interp_SLTI, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *) r4300->recomp.dst->f.i.rs); int rt = allocate_register_64_w(r4300, (unsigned long long *) r4300->recomp.dst->f.i.rt); int imm = (int) r4300->recomp.dst->f.i.immediate; cmp_reg64_imm32(rs, imm); setl_reg8(rt); and_reg64_imm8(rt, 1); #endif } void gen_SLTIU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[11]); #endif #ifdef INTERPRET_SLTIU gencallinterp(r4300, (unsigned long long)cached_interp_SLTIU, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); int imm = (int) r4300->recomp.dst->f.i.immediate; cmp_reg64_imm32(rs, imm); setb_reg8(rt); and_reg64_imm8(rt, 1); #endif } void gen_AND(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[83]); #endif #ifdef INTERPRET_AND gencallinterp(r4300, (unsigned long long)cached_interp_AND, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { and_reg64_reg64(rd, rt); } else if (rt == rd) { and_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); and_reg64_reg64(rd, rt); } #endif } void gen_ANDI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[12]); #endif #ifdef INTERPRET_ANDI gencallinterp(r4300, (unsigned long long)cached_interp_ANDI, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); mov_reg64_reg64(rt, rs); and_reg64_imm32(rt, (unsigned short)r4300->recomp.dst->f.i.immediate); #endif } void gen_OR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[84]); #endif #ifdef INTERPRET_OR gencallinterp(r4300, (unsigned long long)cached_interp_OR, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { or_reg64_reg64(rd, rt); } else if (rt == rd) { or_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); or_reg64_reg64(rd, rt); } #endif } void gen_ORI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[13]); #endif #ifdef INTERPRET_ORI gencallinterp(r4300, (unsigned long long)cached_interp_ORI, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *) r4300->recomp.dst->f.i.rs); int rt = allocate_register_64_w(r4300, (unsigned long long *) r4300->recomp.dst->f.i.rt); mov_reg64_reg64(rt, rs); or_reg64_imm32(rt, (unsigned short)r4300->recomp.dst->f.i.immediate); #endif } void gen_XOR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[85]); #endif #ifdef INTERPRET_XOR gencallinterp(r4300, (unsigned long long)cached_interp_XOR, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { xor_reg64_reg64(rd, rt); } else if (rt == rd) { xor_reg64_reg64(rd, rs); } else { mov_reg64_reg64(rd, rs); xor_reg64_reg64(rd, rt); } #endif } void gen_XORI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[14]); #endif #ifdef INTERPRET_XORI gencallinterp(r4300, (unsigned long long)cached_interp_XORI, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); mov_reg64_reg64(rt, rs); xor_reg64_imm32(rt, (unsigned short)r4300->recomp.dst->f.i.immediate); #endif } void gen_NOR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[86]); #endif #ifdef INTERPRET_NOR gencallinterp(r4300, (unsigned long long)cached_interp_NOR, 0); #else int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rs == rd) { or_reg64_reg64(rd, rt); not_reg64(rd); } else if (rt == rd) { or_reg64_reg64(rd, rs); not_reg64(rd); } else { mov_reg64_reg64(rd, rs); or_reg64_reg64(rd, rt); not_reg64(rd); } #endif } void gen_LUI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[15]); #endif #ifdef INTERPRET_LUI gencallinterp(r4300, (unsigned long long)cached_interp_LUI, 0); #else int rt = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); mov_reg32_imm32(rt, (unsigned int)r4300->recomp.dst->f.i.immediate << 16); #endif } /* Shift instructions */ void gen_NOP(struct r4300_core* r4300) { } void gen_SLL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[55]); #endif #ifdef INTERPRET_SLL gencallinterp(r4300, (unsigned long long)cached_interp_SLL, 0); #else int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd, rt); shl_reg32_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_SLLV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[58]); #endif #ifdef INTERPRET_SLLV gencallinterp(r4300, (unsigned long long)cached_interp_SLLV, 0); #else int rt, rd; allocate_register_32_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg32_reg32(rd, rt); shl_reg32_cl(rd); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rt); shl_reg32_cl(temp); mov_reg32_reg32(rd, temp); } #endif } void gen_DSLL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[93]); #endif #ifdef INTERPRET_DSLL gencallinterp(r4300, (unsigned long long)cached_interp_DSLL, 0); #else int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); mov_reg64_reg64(rd, rt); shl_reg64_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_DSLLV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[68]); #endif #ifdef INTERPRET_DSLLV gencallinterp(r4300, (unsigned long long)cached_interp_DSLLV, 0); #else int rt, rd; allocate_register_32_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg64_reg64(rd, rt); shl_reg64_cl(rd); } else { int temp; temp = lru_register(r4300); free_register(r4300, temp); mov_reg64_reg64(temp, rt); shl_reg64_cl(temp); mov_reg64_reg64(rd, temp); } #endif } void gen_DSLL32(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[97]); #endif #ifdef INTERPRET_DSLL32 gencallinterp(r4300, (unsigned long long)cached_interp_DSLL32, 0); #else int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); mov_reg64_reg64(rd, rt); shl_reg64_imm8(rd, r4300->recomp.dst->f.r.sa + 32); #endif } void gen_SRL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[56]); #endif #ifdef INTERPRET_SRL gencallinterp(r4300, (unsigned long long)cached_interp_SRL, 0); #else int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd, rt); shr_reg32_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_SRLV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[59]); #endif #ifdef INTERPRET_SRLV gencallinterp(r4300, (unsigned long long)cached_interp_SRLV, 0); #else int rt, rd; allocate_register_32_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg32_reg32(rd, rt); shr_reg32_cl(rd); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rt); shr_reg32_cl(temp); mov_reg32_reg32(rd, temp); } #endif } void gen_DSRL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[94]); #endif #ifdef INTERPRET_DSRL gencallinterp(r4300, (unsigned long long)cached_interp_DSRL, 0); #else int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); mov_reg64_reg64(rd, rt); shr_reg64_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_DSRLV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[69]); #endif #ifdef INTERPRET_DSRLV gencallinterp(r4300, (unsigned long long)cached_interp_DSRLV, 0); #else int rt, rd; allocate_register_32_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg64_reg64(rd, rt); shr_reg64_cl(rd); } else { int temp; temp = lru_register(r4300); free_register(r4300, temp); mov_reg64_reg64(temp, rt); shr_reg64_cl(temp); mov_reg64_reg64(rd, temp); } #endif } void gen_DSRL32(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[98]); #endif #ifdef INTERPRET_DSRL32 gencallinterp(r4300, (unsigned long long)cached_interp_DSRL32, 0); #else int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); mov_reg64_reg64(rd, rt); shr_reg64_imm8(rd, r4300->recomp.dst->f.r.sa + 32); #endif } void gen_SRA(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[57]); #endif #ifdef INTERPRET_SRA gencallinterp(r4300, (unsigned long long)cached_interp_SRA, 0); #else int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); mov_reg32_reg32(rd, rt); sar_reg32_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_SRAV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[60]); #endif #ifdef INTERPRET_SRAV gencallinterp(r4300, (unsigned long long)cached_interp_SRAV, 0); #else int rt, rd; allocate_register_32_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.r.rt); rd = allocate_register_32_w(r4300, (unsigned int *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg32_reg32(rd, rt); sar_reg32_cl(rd); } else { int temp = lru_register(r4300); free_register(r4300, temp); mov_reg32_reg32(temp, rt); sar_reg32_cl(temp); mov_reg32_reg32(rd, temp); } #endif } void gen_DSRA(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[95]); #endif #ifdef INTERPRET_DSRA gencallinterp(r4300, (unsigned long long)cached_interp_DSRA, 0); #else int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); mov_reg64_reg64(rd, rt); sar_reg64_imm8(rd, r4300->recomp.dst->f.r.sa); #endif } void gen_DSRAV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[70]); #endif #ifdef INTERPRET_DSRAV gencallinterp(r4300, (unsigned long long)cached_interp_DSRAV, 0); #else int rt, rd; allocate_register_32_manually(r4300, ECX, (unsigned int *)r4300->recomp.dst->f.r.rs); rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); if (rd != ECX) { mov_reg64_reg64(rd, rt); sar_reg64_cl(rd); } else { int temp; temp = lru_register(r4300); free_register(r4300, temp); mov_reg64_reg64(temp, rt); sar_reg64_cl(temp); mov_reg64_reg64(rd, temp); } #endif } void gen_DSRA32(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[99]); #endif #ifdef INTERPRET_DSRA32 gencallinterp(r4300, (unsigned long long)cached_interp_DSRA32, 0); #else int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rt); int rd = allocate_register_64_w(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rd); mov_reg64_reg64(rd, rt); sar_reg64_imm8(rd, r4300->recomp.dst->f.r.sa + 32); #endif } /* Multiply / Divide instructions */ void gen_MULT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[71]); #endif #ifdef INTERPRET_MULT gencallinterp(r4300, (unsigned long long)cached_interp_MULT, 0); #else int rs, rt; allocate_register_32_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300)); /* these must be done first so they are not assigned by allocate_register() */ allocate_register_32_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300)); rs = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); mov_reg32_reg32(EAX, rs); imul_reg32(rt); #endif } void gen_MULTU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[72]); #endif #ifdef INTERPRET_MULTU gencallinterp(r4300, (unsigned long long)cached_interp_MULTU, 0); #else int rs, rt; allocate_register_32_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300)); allocate_register_32_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300)); rs = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); mov_reg32_reg32(EAX, rs); mul_reg32(rt); #endif } void gen_DMULT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[75]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_DMULT, 0); } void gen_DMULTU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[76]); #endif #ifdef INTERPRET_DMULTU gencallinterp(r4300, (unsigned long long)cached_interp_DMULTU, 0); #else free_registers_move_start(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *) r4300->recomp.dst->f.r.rs); mov_xreg64_m64rel(RDX, (unsigned long long *) r4300->recomp.dst->f.r.rt); mul_reg64(RDX); mov_m64rel_xreg64((unsigned long long *) r4300_mult_lo(r4300), RAX); mov_m64rel_xreg64((unsigned long long *) r4300_mult_hi(r4300), RDX); #endif } void gen_DIV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[73]); #endif #ifdef INTERPRET_DIV gencallinterp(r4300, (unsigned long long)cached_interp_DIV, 0); #else int rs, rt; allocate_register_32_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300)); allocate_register_32_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300)); rs = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); cmp_reg32_imm32(rt, 0); je_rj((rs == EAX ? 0 : 2) + 1 + 2); mov_reg32_reg32(EAX, rs); // 0 or 2 cdq(); // 1 idiv_reg32(rt); // 2 #endif } void gen_DIVU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[74]); #endif #ifdef INTERPRET_DIVU gencallinterp(r4300, (unsigned long long)cached_interp_DIVU, 0); #else int rs, rt; allocate_register_32_manually_w(r4300, EAX, (unsigned int *)r4300_mult_lo(r4300)); allocate_register_32_manually_w(r4300, EDX, (unsigned int *)r4300_mult_hi(r4300)); rs = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rs); rt = allocate_register_32(r4300, (unsigned int*)r4300->recomp.dst->f.r.rt); cmp_reg32_imm32(rt, 0); je_rj((rs == EAX ? 0 : 2) + 2 + 2); mov_reg32_reg32(EAX, rs); // 0 or 2 xor_reg32_reg32(EDX, EDX); // 2 div_reg32(rt); // 2 #endif } void gen_DDIV(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[77]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_DDIV, 0); } void gen_DDIVU(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[78]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_DDIVU, 0); } void gen_MFHI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[64]); #endif #ifdef INTERPRET_MFHI gencallinterp(r4300, (unsigned long long)cached_interp_MFHI, 0); #else int rd = allocate_register_64_w(r4300, (unsigned long long *) r4300->recomp.dst->f.r.rd); int _hi = allocate_register_64(r4300, (unsigned long long *) r4300_mult_hi(r4300)); mov_reg64_reg64(rd, _hi); #endif } void gen_MTHI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[65]); #endif #ifdef INTERPRET_MTHI gencallinterp(r4300, (unsigned long long)cached_interp_MTHI, 0); #else int _hi = allocate_register_64_w(r4300, (unsigned long long *) r4300_mult_hi(r4300)); int rs = allocate_register_64(r4300, (unsigned long long *) r4300->recomp.dst->f.r.rs); mov_reg64_reg64(_hi, rs); #endif } void gen_MFLO(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[66]); #endif #ifdef INTERPRET_MFLO gencallinterp(r4300, (unsigned long long)cached_interp_MFLO, 0); #else int rd = allocate_register_64_w(r4300, (unsigned long long *) r4300->recomp.dst->f.r.rd); int _lo = allocate_register_64(r4300, (unsigned long long *) r4300_mult_lo(r4300)); mov_reg64_reg64(rd, _lo); #endif } void gen_MTLO(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[67]); #endif #ifdef INTERPRET_MTLO gencallinterp(r4300, (unsigned long long)cached_interp_MTLO, 0); #else int _lo = allocate_register_64_w(r4300, (unsigned long long *)r4300_mult_lo(r4300)); int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.r.rs); mov_reg64_reg64(_lo, rs); #endif } /* Jump & Branch instructions */ static void gentest(struct r4300_core* r4300) { cmp_m32rel_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt(r4300, (unsigned long long) (r4300->recomp.dst + (r4300->recomp.dst-1)->f.i.immediate)); jmp(r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); jump_end_rel32(r4300); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned long long)(r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void gentest_out(struct r4300_core* r4300) { cmp_m32rel_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt_out(r4300, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_m32rel_imm32(&r4300->recomp.jump_to_address, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_jump_to_recomp_address); call_reg64(RAX); jump_end_rel32(r4300); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned long long) (r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void gentest_idle(struct r4300_core* r4300) { int reg; reg = lru_register(r4300); free_register(r4300, reg); cmp_m32rel_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); mov_xreg32_m32rel(reg, (unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(reg, reg); jns_rj(0); jump_start_rel8(r4300); sub_m32rel_xreg32((unsigned int *)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), reg); mov_m32rel_imm32((unsigned int *)r4300_cp0_cycle_count(&r4300->cp0), 0); jump_end_rel8(r4300); jump_end_rel32(r4300); } static void gentestl(struct r4300_core* r4300) { cmp_m32rel_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); gendelayslot(r4300); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt(r4300, (unsigned long long) (r4300->recomp.dst + (r4300->recomp.dst-1)->f.i.immediate)); jmp(r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); jump_end_rel32(r4300); gencp0_update_count(r4300, r4300->recomp.dst->addr-4); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned long long) (r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void gentestl_out(struct r4300_core* r4300) { cmp_m32rel_imm32((unsigned int *)(&r4300->recomp.branch_taken), 0); je_near_rj(0); jump_start_rel32(r4300); gendelayslot(r4300); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); gencheck_interrupt_out(r4300, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_m32rel_imm32(&r4300->recomp.jump_to_address, r4300->recomp.dst->addr + (r4300->recomp.dst-1)->f.i.immediate*4); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_jump_to_recomp_address); call_reg64(RAX); jump_end_rel32(r4300); gencp0_update_count(r4300, r4300->recomp.dst->addr-4); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), r4300->recomp.dst->addr + 4); gencheck_interrupt(r4300, (unsigned long long) (r4300->recomp.dst + 1)); jmp(r4300->recomp.dst->addr + 4); } static void genbranchlink(struct r4300_core* r4300) { int r31_64bit = is64(r4300, (unsigned int*)&r4300_regs(r4300)[31]); if (r31_64bit == 0) { int r31 = allocate_register_32_w(r4300, (unsigned int *)&r4300_regs(r4300)[31]); mov_reg32_imm32(r31, r4300->recomp.dst->addr+8); } else if (r31_64bit == -1) { mov_m32rel_imm32((unsigned int *)&r4300_regs(r4300)[31], r4300->recomp.dst->addr + 8); if (r4300->recomp.dst->addr & 0x80000000) { mov_m32rel_imm32(((unsigned int *)&r4300_regs(r4300)[31])+1, 0xFFFFFFFF); } else { mov_m32rel_imm32(((unsigned int *)&r4300_regs(r4300)[31])+1, 0); } } else { int r31 = allocate_register_64_w(r4300, (unsigned long long *)&r4300_regs(r4300)[31]); mov_reg32_imm32(r31, r4300->recomp.dst->addr+8); movsxd_reg64_reg32(r31, r31); } } void gen_J(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[2]); #endif #ifdef INTERPRET_J gencallinterp(r4300, (unsigned long long)cached_interp_J, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_J, 1); return; } gendelayslot(r4300); naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), naddr); gencheck_interrupt(r4300, (unsigned long long) &r4300->cached_interp.actual->block[(naddr-r4300->cached_interp.actual->start)/4]); jmp(naddr); #endif } void gen_J_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[2]); #endif #ifdef INTERPRET_J_OUT gencallinterp(r4300, (unsigned long long)cached_interp_J_OUT, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_J_OUT, 1); return; } gendelayslot(r4300); naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), naddr); gencheck_interrupt_out(r4300, naddr); mov_m32rel_imm32(&r4300->recomp.jump_to_address, naddr); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_jump_to_recomp_address); call_reg64(RAX); #endif } void gen_J_IDLE(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[2]); #endif #ifdef INTERPRET_J_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_J_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_J_IDLE, 1); return; } mov_xreg32_m32rel(EAX, (unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(EAX, EAX); jns_rj(18); sub_m32rel_xreg32((unsigned int *)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), EAX); // 7 mov_m32rel_imm32((unsigned int *)r4300_cp0_cycle_count(&r4300->cp0), 0); // 11 gen_J(r4300); #endif } void gen_JAL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[3]); #endif #ifdef INTERPRET_JAL gencallinterp(r4300, (unsigned long long)cached_interp_JAL, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_JAL, 1); return; } gendelayslot(r4300); mov_m32rel_imm32((unsigned int *)(r4300_regs(r4300) + 31), r4300->recomp.dst->addr + 4); if (((r4300->recomp.dst->addr + 4) & 0x80000000)) { mov_m32rel_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0xFFFFFFFF); } else { mov_m32rel_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0); } naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), naddr); gencheck_interrupt(r4300, (unsigned long long) &r4300->cached_interp.actual->block[(naddr-r4300->cached_interp.actual->start)/4]); jmp(naddr); #endif } void gen_JAL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[3]); #endif #ifdef INTERPRET_JAL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_JAL_OUT, 1); #else unsigned int naddr; if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_JAL_OUT, 1); return; } gendelayslot(r4300); mov_m32rel_imm32((unsigned int *)(r4300_regs(r4300) + 31), r4300->recomp.dst->addr + 4); if (((r4300->recomp.dst->addr + 4) & 0x80000000)) { mov_m32rel_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0xFFFFFFFF); } else { mov_m32rel_imm32((unsigned int *)(&r4300_regs(r4300)[31])+1, 0); } naddr = ((r4300->recomp.dst-1)->f.j.inst_index<<2) | (r4300->recomp.dst->addr & 0xF0000000); mov_m32rel_imm32((void*)(&r4300->cp0.last_addr), naddr); gencheck_interrupt_out(r4300, naddr); mov_m32rel_imm32(&r4300->recomp.jump_to_address, naddr); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_jump_to_recomp_address); call_reg64(RAX); #endif } void gen_JAL_IDLE(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[3]); #endif #ifdef INTERPRET_JAL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_JAL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_JAL_IDLE, 1); return; } mov_xreg32_m32rel(EAX, (unsigned int *)(r4300_cp0_cycle_count(&r4300->cp0))); test_reg32_reg32(EAX, EAX); jns_rj(18); sub_m32rel_xreg32((unsigned int *)(&r4300_cp0_regs(&r4300->cp0)[CP0_COUNT_REG]), EAX); // 7 mov_m32rel_imm32((unsigned int *)r4300_cp0_cycle_count(&r4300->cp0), 0); // 11 gen_JAL(r4300); #endif } void gen_JR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[61]); #endif #ifdef INTERPRET_JR gencallinterp(r4300, (unsigned long long)cached_interp_JR_OUT, 1); #else unsigned int diff = (unsigned int) offsetof(struct precomp_instr, local_addr); unsigned int diff_need = (unsigned int) offsetof(struct precomp_instr, reg_cache_infos.need_map); unsigned int diff_wrap = (unsigned int) offsetof(struct precomp_instr, reg_cache_infos.jump_wrapper); if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_JR_OUT, 1); return; } free_registers_move_start(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)r4300->recomp.dst->f.i.rs); mov_m32rel_xreg32((unsigned int *)&r4300->recomp.local_rs, EAX); gendelayslot(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)&r4300->recomp.local_rs); mov_m32rel_xreg32((unsigned int *)&r4300->cp0.last_addr, EAX); gencheck_interrupt_reg(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)&r4300->recomp.local_rs); mov_reg32_reg32(EBX, EAX); and_eax_imm32(0xFFFFF000); cmp_eax_imm32(r4300->recomp.dst_block->start & 0xFFFFF000); je_near_rj(0); jump_start_rel32(r4300); mov_m32rel_xreg32(&r4300->recomp.jump_to_address, EBX); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_jump_to_recomp_address); call_reg64(RAX); /* will never return from call */ jump_end_rel32(r4300); mov_reg64_imm64(RSI, (unsigned long long) r4300->recomp.dst_block->block); mov_reg32_reg32(EAX, EBX); sub_eax_imm32(r4300->recomp.dst_block->start); shr_reg32_imm8(EAX, 2); mul_m32rel((unsigned int *)(&precomp_instr_size)); mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); cmp_reg32_imm32(EBX, 1); jne_rj(11); add_reg32_imm32(EAX, diff_wrap); // 6 add_reg64_reg64(RAX, RSI); // 3 jmp_reg64(RAX); // 2 mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); mov_rax_memoffs64((unsigned long long *) &r4300->recomp.dst_block->code); add_reg64_reg64(RAX, RBX); jmp_reg64(RAX); #endif } void gen_JALR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[62]); #endif #ifdef INTERPRET_JALR gencallinterp(r4300, (unsigned long long)cached_interp_JALR_OUT, 0); #else unsigned int diff = (unsigned int) offsetof(struct precomp_instr, local_addr); unsigned int diff_need = (unsigned int) offsetof(struct precomp_instr, reg_cache_infos.need_map); unsigned int diff_wrap = (unsigned int) offsetof(struct precomp_instr, reg_cache_infos.jump_wrapper); if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_JALR_OUT, 1); return; } free_registers_move_start(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)r4300->recomp.dst->f.r.rs); mov_m32rel_xreg32((unsigned int *)&r4300->recomp.local_rs, EAX); gendelayslot(r4300); mov_m32rel_imm32((unsigned int *)(r4300->recomp.dst-1)->f.r.rd, r4300->recomp.dst->addr+4); if ((r4300->recomp.dst->addr+4) & 0x80000000) { mov_m32rel_imm32(((unsigned int *)(r4300->recomp.dst-1)->f.r.rd)+1, 0xFFFFFFFF); } else { mov_m32rel_imm32(((unsigned int *)(r4300->recomp.dst-1)->f.r.rd)+1, 0); } mov_xreg32_m32rel(EAX, (unsigned int *)&r4300->recomp.local_rs); mov_m32rel_xreg32((unsigned int *)&r4300->cp0.last_addr, EAX); gencheck_interrupt_reg(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)&r4300->recomp.local_rs); mov_reg32_reg32(EBX, EAX); and_eax_imm32(0xFFFFF000); cmp_eax_imm32(r4300->recomp.dst_block->start & 0xFFFFF000); je_near_rj(0); jump_start_rel32(r4300); mov_m32rel_xreg32(&r4300->recomp.jump_to_address, EBX); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); mov_reg64_imm64(RAX, (unsigned long long) dynarec_jump_to_recomp_address); call_reg64(RAX); /* will never return from call */ jump_end_rel32(r4300); mov_reg64_imm64(RSI, (unsigned long long) r4300->recomp.dst_block->block); mov_reg32_reg32(EAX, EBX); sub_eax_imm32(r4300->recomp.dst_block->start); shr_reg32_imm8(EAX, 2); mul_m32rel((unsigned int *)(&precomp_instr_size)); mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); cmp_reg32_imm32(EBX, 1); jne_rj(11); add_reg32_imm32(EAX, diff_wrap); // 6 add_reg64_reg64(RAX, RSI); // 3 jmp_reg64(RAX); // 2 mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); mov_rax_memoffs64((unsigned long long *) &r4300->recomp.dst_block->code); add_reg64_reg64(RAX, RBX); jmp_reg64(RAX); #endif } static void genbeq_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); if (rs_64bit == 0 && rt_64bit == 0) { int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); cmp_reg32_reg32(rs, rt); sete_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else if (rs_64bit == -1) { int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); cmp_xreg64_m64rel(rt, (unsigned long long *) r4300->recomp.dst->f.i.rs); sete_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else if (rt_64bit == -1) { int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); cmp_xreg64_m64rel(rs, (unsigned long long *)r4300->recomp.dst->f.i.rt); sete_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else { int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); cmp_reg64_reg64(rs, rt); sete_m8rel((unsigned char *) &r4300->recomp.branch_taken); } } void gen_BEQ(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[4]); #endif #ifdef INTERPRET_BEQ gencallinterp(r4300, (unsigned long long)cached_interp_BEQ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BEQ, 1); return; } genbeq_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BEQ_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[4]); #endif #ifdef INTERPRET_BEQ_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BEQ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BEQ_OUT, 1); return; } genbeq_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BEQ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BEQ_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BEQ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BEQ_IDLE, 1); return; } genbeq_test(r4300); gentest_idle(r4300); gen_BEQ(r4300); #endif } void gen_BEQL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[16]); #endif #ifdef INTERPRET_BEQL gencallinterp(r4300, (unsigned long long)cached_interp_BEQL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BEQL, 1); return; } genbeq_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BEQL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[16]); #endif #ifdef INTERPRET_BEQL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BEQL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BEQL_OUT, 1); return; } genbeq_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BEQL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BEQL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BEQL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BEQL_IDLE, 1); return; } genbeq_test(r4300); gentest_idle(r4300); gen_BEQL(r4300); #endif } static void genbne_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); if (rs_64bit == 0 && rt_64bit == 0) { int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rt); cmp_reg32_reg32(rs, rt); setne_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else if (rs_64bit == -1) { int rt = allocate_register_64(r4300, (unsigned long long *) r4300->recomp.dst->f.i.rt); cmp_xreg64_m64rel(rt, (unsigned long long *)r4300->recomp.dst->f.i.rs); setne_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else if (rt_64bit == -1) { int rs = allocate_register_64(r4300, (unsigned long long *) r4300->recomp.dst->f.i.rs); cmp_xreg64_m64rel(rs, (unsigned long long *)r4300->recomp.dst->f.i.rt); setne_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else { int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); int rt = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rt); cmp_reg64_reg64(rs, rt); setne_m8rel((unsigned char *) &r4300->recomp.branch_taken); } } void gen_BNE(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[5]); #endif #ifdef INTERPRET_BNE gencallinterp(r4300, (unsigned long long)cached_interp_BNE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BNE, 1); return; } genbne_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BNE_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[5]); #endif #ifdef INTERPRET_BNE_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BNE_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BNE_OUT, 1); return; } genbne_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BNE_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BNE_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BNE_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BNE_IDLE, 1); return; } genbne_test(r4300); gentest_idle(r4300); gen_BNE(r4300); #endif } void gen_BNEL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[17]); #endif #ifdef INTERPRET_BNEL gencallinterp(r4300, (unsigned long long)cached_interp_BNEL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BNEL, 1); return; } genbne_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BNEL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[17]); #endif #ifdef INTERPRET_BNEL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BNEL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BNEL_OUT, 1); return; } genbne_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BNEL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BNEL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BNEL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BNEL_IDLE, 1); return; } genbne_test(r4300); gentest_idle(r4300); gen_BNEL(r4300); #endif } static void genblez_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (rs_64bit == 0) { int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); setle_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else { int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); cmp_reg64_imm8(rs, 0); setle_m8rel((unsigned char *) &r4300->recomp.branch_taken); } } void gen_BLEZ(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[6]); #endif #ifdef INTERPRET_BLEZ gencallinterp(r4300, (unsigned long long)cached_interp_BLEZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLEZ, 1); return; } genblez_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BLEZ_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[6]); #endif #ifdef INTERPRET_BLEZ_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BLEZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLEZ_OUT, 1); return; } genblez_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BLEZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZ_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BLEZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLEZ_IDLE, 1); return; } genblez_test(r4300); gentest_idle(r4300); gen_BLEZ(r4300); #endif } void gen_BLEZL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[18]); #endif #ifdef INTERPRET_BLEZL gencallinterp(r4300, (unsigned long long)cached_interp_BLEZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLEZL, 1); return; } genblez_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BLEZL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[18]); #endif #ifdef INTERPRET_BLEZL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BLEZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLEZL_OUT, 1); return; } genblez_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BLEZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLEZL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BLEZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLEZL_IDLE, 1); return; } genblez_test(r4300); gentest_idle(r4300); gen_BLEZL(r4300); #endif } static void genbgtz_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (rs_64bit == 0) { int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); setg_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else { int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); cmp_reg64_imm8(rs, 0); setg_m8rel((unsigned char *) &r4300->recomp.branch_taken); } } void gen_BGTZ(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[7]); #endif #ifdef INTERPRET_BGTZ gencallinterp(r4300, (unsigned long long)cached_interp_BGTZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGTZ, 1); return; } genbgtz_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BGTZ_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[7]); #endif #ifdef INTERPRET_BGTZ_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BGTZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGTZ_OUT, 1); return; } genbgtz_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BGTZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZ_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BGTZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGTZ_IDLE, 1); return; } genbgtz_test(r4300); gentest_idle(r4300); gen_BGTZ(r4300); #endif } void gen_BGTZL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[19]); #endif #ifdef INTERPRET_BGTZL gencallinterp(r4300, (unsigned long long)cached_interp_BGTZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGTZL, 1); return; } genbgtz_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BGTZL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[19]); #endif #ifdef INTERPRET_BGTZL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BGTZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGTZL_OUT, 1); return; } genbgtz_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BGTZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGTZL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BGTZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGTZL_IDLE, 1); return; } genbgtz_test(r4300); gentest_idle(r4300); gen_BGTZL(r4300); #endif } static void genbltz_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (rs_64bit == 0) { int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); setl_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else if (rs_64bit == -1) { cmp_m32rel_imm32(((unsigned int *)r4300->recomp.dst->f.i.rs)+1, 0); setl_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else { int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); cmp_reg64_imm8(rs, 0); setl_m8rel((unsigned char *) &r4300->recomp.branch_taken); } } void gen_BLTZ(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[47]); #endif #ifdef INTERPRET_BLTZ gencallinterp(r4300, (unsigned long long)cached_interp_BLTZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZ, 1); return; } genbltz_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BLTZ_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[47]); #endif #ifdef INTERPRET_BLTZ_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BLTZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZ_OUT, 1); return; } genbltz_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BLTZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZ_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BLTZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZ_IDLE, 1); return; } genbltz_test(r4300); gentest_idle(r4300); gen_BLTZ(r4300); #endif } void gen_BLTZAL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[51]); #endif #ifdef INTERPRET_BLTZAL gencallinterp(r4300, (unsigned long long)cached_interp_BLTZAL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZAL, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BLTZAL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[51]); #endif #ifdef INTERPRET_BLTZAL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BLTZAL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZAL_OUT, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BLTZAL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZAL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BLTZAL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZAL_IDLE, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BLTZAL(r4300); #endif } void gen_BLTZL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[49]); #endif #ifdef INTERPRET_BLTZL gencallinterp(r4300, (unsigned long long)cached_interp_BLTZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZL, 1); return; } genbltz_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BLTZL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[49]); #endif #ifdef INTERPRET_BLTZL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BLTZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZL_OUT, 1); return; } genbltz_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BLTZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BLTZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZL_IDLE, 1); return; } genbltz_test(r4300); gentest_idle(r4300); gen_BLTZL(r4300); #endif } void gen_BLTZALL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[53]); #endif #ifdef INTERPRET_BLTZALL gencallinterp(r4300, (unsigned long long)cached_interp_BLTZALL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZALL, 1); return; } genbltz_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BLTZALL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[53]); #endif #ifdef INTERPRET_BLTZALL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BLTZALL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZALL_OUT, 1); return; } genbltz_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BLTZALL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BLTZALL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BLTZALL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BLTZALL_IDLE, 1); return; } genbltz_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BLTZALL(r4300); #endif } static void genbgez_test(struct r4300_core* r4300) { int rs_64bit = is64(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); if (rs_64bit == 0) { int rs = allocate_register_32(r4300, (unsigned int *)r4300->recomp.dst->f.i.rs); cmp_reg32_imm32(rs, 0); setge_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else if (rs_64bit == -1) { cmp_m32rel_imm32(((unsigned int *)r4300->recomp.dst->f.i.rs)+1, 0); setge_m8rel((unsigned char *) &r4300->recomp.branch_taken); } else { int rs = allocate_register_64(r4300, (unsigned long long *)r4300->recomp.dst->f.i.rs); cmp_reg64_imm8(rs, 0); setge_m8rel((unsigned char *) &r4300->recomp.branch_taken); } } void gen_BGEZ(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[48]); #endif #ifdef INTERPRET_BGEZ gencallinterp(r4300, (unsigned long long)cached_interp_BGEZ, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZ, 1); return; } genbgez_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BGEZ_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[48]); #endif #ifdef INTERPRET_BGEZ_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BGEZ_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZ_OUT, 1); return; } genbgez_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BGEZ_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZ_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BGEZ_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZ_IDLE, 1); return; } genbgez_test(r4300); gentest_idle(r4300); gen_BGEZ(r4300); #endif } void gen_BGEZAL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[52]); #endif #ifdef INTERPRET_BGEZAL gencallinterp(r4300, (unsigned long long)cached_interp_BGEZAL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZAL, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BGEZAL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[52]); #endif #ifdef INTERPRET_BGEZAL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BGEZAL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZAL_OUT, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BGEZAL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZAL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BGEZAL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZAL_IDLE, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BGEZAL(r4300); #endif } void gen_BGEZL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[50]); #endif #ifdef INTERPRET_BGEZL gencallinterp(r4300, (unsigned long long)cached_interp_BGEZL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZL, 1); return; } genbgez_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BGEZL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[50]); #endif #ifdef INTERPRET_BGEZL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BGEZL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZL_OUT, 1); return; } genbgez_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BGEZL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BGEZL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZL_IDLE, 1); return; } genbgez_test(r4300); gentest_idle(r4300); gen_BGEZL(r4300); #endif } void gen_BGEZALL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[54]); #endif #ifdef INTERPRET_BGEZALL gencallinterp(r4300, (unsigned long long)cached_interp_BGEZALL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZALL, 1); return; } genbgez_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BGEZALL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[54]); #endif #ifdef INTERPRET_BGEZALL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BGEZALL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZALL_OUT, 1); return; } genbgez_test(r4300); genbranchlink(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BGEZALL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BGEZALL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BGEZALL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BGEZALL_IDLE, 1); return; } genbgez_test(r4300); genbranchlink(r4300); gentest_idle(r4300); gen_BGEZALL(r4300); #endif } static void genbc1f_test(struct r4300_core* r4300) { test_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); sete_m8rel((unsigned char *) &r4300->recomp.branch_taken); } void gen_BC1F(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[100]); #endif #ifdef INTERPRET_BC1F gencallinterp(r4300, (unsigned long long)cached_interp_BC1F, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1F, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BC1F_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[100]); #endif #ifdef INTERPRET_BC1F_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BC1F_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1F_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BC1F_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1F_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BC1F_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1F_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gentest_idle(r4300); gen_BC1F(r4300); #endif } void gen_BC1FL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[102]); #endif #ifdef INTERPRET_BC1FL gencallinterp(r4300, (unsigned long long)cached_interp_BC1FL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1FL, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BC1FL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[102]); #endif #ifdef INTERPRET_BC1FL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BC1FL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1FL_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BC1FL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1FL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BC1FL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1FL_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1f_test(r4300); gentest_idle(r4300); gen_BC1FL(r4300); #endif } static void genbc1t_test(struct r4300_core* r4300) { test_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); setne_m8rel((unsigned char *) &r4300->recomp.branch_taken); } void gen_BC1T(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[101]); #endif #ifdef INTERPRET_BC1T gencallinterp(r4300, (unsigned long long)cached_interp_BC1T, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1T, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gendelayslot(r4300); gentest(r4300); #endif } void gen_BC1T_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[101]); #endif #ifdef INTERPRET_BC1T_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BC1T_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1T_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gendelayslot(r4300); gentest_out(r4300); #endif } void gen_BC1T_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1T_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BC1T_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1T_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gentest_idle(r4300); gen_BC1T(r4300); #endif } void gen_BC1TL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[103]); #endif #ifdef INTERPRET_BC1TL gencallinterp(r4300, (unsigned long long)cached_interp_BC1TL, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1TL, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); free_all_registers(r4300); gentestl(r4300); #endif } void gen_BC1TL_OUT(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[103]); #endif #ifdef INTERPRET_BC1TL_OUT gencallinterp(r4300, (unsigned long long)cached_interp_BC1TL_OUT, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1TL_OUT, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); free_all_registers(r4300); gentestl_out(r4300); #endif } void gen_BC1TL_IDLE(struct r4300_core* r4300) { #ifdef INTERPRET_BC1TL_IDLE gencallinterp(r4300, (unsigned long long)cached_interp_BC1TL_IDLE, 1); #else if (((r4300->recomp.dst->addr & 0xFFF) == 0xFFC && (r4300->recomp.dst->addr < 0x80000000 || r4300->recomp.dst->addr >= 0xC0000000)) || r4300->recomp.no_compiled_jump) { gencallinterp(r4300, (unsigned long long)cached_interp_BC1TL_IDLE, 1); return; } gencheck_cop1_unusable(r4300); genbc1t_test(r4300); gentest_idle(r4300); gen_BC1TL(r4300); #endif } /* Special instructions */ void gen_CACHE(struct r4300_core* r4300) { } void gen_ERET(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[108]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_ERET, 1); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); genupdate_system(r4300, 0); mov_reg32_imm32(EAX, (unsigned int)(ERET)); call_reg32(EAX); mov_reg32_imm32(EAX, (unsigned int)(jump_code)); jmp_reg32(EAX); #endif } void gen_SYNC(struct r4300_core* r4300) { } void gen_SYSCALL(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[63]); #endif #ifdef INTERPRET_SYSCALL gencallinterp(r4300, (unsigned long long)cached_interp_SYSCALL, 0); #else free_registers_move_start(r4300); mov_m32rel_imm32(&r4300_cp0_regs(&r4300->cp0)[CP0_CAUSE_REG], 8 << 2); gencallinterp(r4300, (unsigned long long)dynarec_exception_general, 0); #endif } /* Trap instructions */ void gen_TGE(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TGE, 0); } void gen_TGEU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TGEU, 0); } void gen_TGEI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TGEI, 0); } void gen_TGEIU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TGEIU, 0); } void gen_TLT(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TLT, 0); } void gen_TLTU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TLTU, 0); } void gen_TLTI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TLTI, 0); } void gen_TLTIU(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TLTIU, 0); } void gen_TEQ(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[96]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_TEQ, 0); } void gen_TEQI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TEQI, 0); } void gen_TNE(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TNE, 0); } void gen_TNEI(struct r4300_core* r4300) { gencallinterp(r4300, (unsigned long long)cached_interp_TNEI, 0); } /* TLB instructions */ void gen_TLBP(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[105]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_TLBP, 0); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); mov_reg32_imm32(EAX, (unsigned int)(TLBP)); call_reg32(EAX); genupdate_system(r4300, 0); #endif } void gen_TLBR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[106]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_TLBR, 0); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); mov_reg32_imm32(EAX, (unsigned int)(TLBR)); call_reg32(EAX); genupdate_system(r4300, 0); #endif } void gen_TLBWR(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[107]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_TLBWR, 0); } void gen_TLBWI(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[104]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_TLBWI, 0); #if 0 dst->local_addr = code_length; mov_m32_imm32((void *)(&(*r4300_pc_struct(r4300))), (unsigned int)(dst)); mov_reg32_imm32(EAX, (unsigned int)(TLBWI)); call_reg32(EAX); genupdate_system(r4300, 0); #endif } /* CP0 load/store instructions */ void gen_MFC0(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[109]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_MFC0, 0); } void gen_MTC0(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[110]); #endif gencallinterp(r4300, (unsigned long long)cached_interp_MTC0, 0); } /* CP1 load/store instructions */ void gen_LWC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[39]); #endif #ifdef INTERPRET_LWC1 gencallinterp(r4300, (unsigned long long)cached_interp_LWC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(52); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 mov_xreg64_m64rel(RDX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 7 mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), RDX); // 7 mov_reg64_imm64(RBX, (unsigned long long)dynarec_read_aligned_word); // 10 call_reg64(RBX); // 2 jmp_imm_short(28); // 2 mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg32_preg64preg64(EAX, RBX, RSI); // 3 mov_xreg64_m64rel(RBX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 7 mov_preg64_reg32(RBX, EAX); // 2 #endif } void gen_LDC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[40]); #endif #ifdef INTERPRET_LDC1 gencallinterp(r4300, (unsigned long long)cached_interp_LDC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].read32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) read_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(52); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 mov_xreg64_m64rel(RDX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 7 mov_m64rel_xreg64((unsigned long long *)(&r4300->recomp.rdword), RDX); // 7 mov_reg64_imm64(RBX, (unsigned long long)dynarec_read_aligned_dword); // 10 call_reg64(RBX); // 2 jmp_imm_short(39); // 2 mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_reg64_preg64preg64(RAX, RBX, RSI); // 4 mov_xreg64_m64rel(RBX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); // 7 mov_preg64pimm32_reg32(RBX, 4, EAX); // 6 shr_reg64_imm8(RAX, 32); // 4 mov_preg64_reg32(RBX, EAX); // 2 #endif } void gen_SWC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[43]); #endif #ifdef INTERPRET_SWC1 gencallinterp(r4300, (unsigned long long)cached_interp_SWC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RDX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); mov_reg32_preg64(ECX, RDX); mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].write32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) write_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(63); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wword), ECX); // 7 mov_m32rel_imm32((unsigned int *)(&r4300->recomp.wmask), ~UINT32_C(0)); // 11 mov_reg64_imm64(RBX, (unsigned long long)dynarec_write_aligned_word); // 10 call_reg64(RBX); // 2 mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300->recomp.address)); // 7 jmp_imm_short(21); // 2 mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg64preg64_reg32(RBX, RSI, ECX); // 3 mov_reg64_imm64(RSI, (unsigned long long) r4300->cached_interp.invalid_code); mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg64preg64_imm8(RBX, RSI, 0); jne_rj(65); mov_reg64_imm64(RDI, (unsigned long long) r4300->cached_interp.blocks); // 10 mov_reg32_reg32(ECX, EBX); // 2 mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4 mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(struct precomp_block, block)); // 7 mov_reg64_imm64(RDI, (unsigned long long) dynarec_notcompiled); // 10 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(struct precomp_instr, ops)); // 8 cmp_reg64_reg64(RAX, RDI); // 3 je_rj(4); // 2 mov_preg64preg64_imm8(RCX, RSI, 1); // 4 #endif } void gen_SDC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[44]); #endif #ifdef INTERPRET_SDC1 gencallinterp(r4300, (unsigned long long)cached_interp_SDC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RSI, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.lf.ft])); mov_reg32_preg64(ECX, RSI); mov_reg32_preg64pimm32(EDX, RSI, 4); mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300_regs(r4300)[r4300->recomp.dst->f.lf.base])); add_eax_imm32((int)r4300->recomp.dst->f.lf.offset); mov_reg32_reg32(EBX, EAX); /* is address in RDRAM ? */ and_reg32_imm32(EAX, 0xDF800000); cmp_reg32_imm32(EAX, 0x80000000); /* when fast_memory is true, we know that there is * no custom read handler so skip this test entirely */ if (!r4300->recomp.fast_memory) { /* not in RDRAM anyway so skip the read32 check */ jne_rj(0); jump_start_rel8(r4300); shr_reg64_imm8(RAX, 16); and_reg32_imm32(EAX, 0x1fff); lea_reg64_preg64x2preg64(RAX, RAX, RAX); mov_reg64_imm64(RSI, (unsigned long long) r4300->mem->handlers[0].write32); mov_reg64_preg64x8preg64(RAX, RAX, RSI); mov_reg64_imm64(RSI, (unsigned long long) write_rdram_dram); cmp_reg64_reg64(RAX, RSI); jump_end_rel8(r4300); } je_rj(59); mov_reg64_imm64(RAX, (unsigned long long) (r4300->recomp.dst+1)); // 10 mov_m64rel_xreg64((unsigned long long *)(&(*r4300_pc_struct(r4300))), RAX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.address), EBX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wdword), ECX); // 7 mov_m32rel_xreg32((unsigned int *)(&r4300->recomp.wdword)+1, EDX); // 7 mov_reg64_imm64(RBX, (unsigned long long)dynarec_write_aligned_dword); // 10 call_reg64(RBX); // 2 mov_xreg32_m32rel(EAX, (unsigned int *)(&r4300->recomp.address)); // 7 jmp_imm_short(28); // 2 mov_reg64_imm64(RSI, (unsigned long long) r4300->rdram->dram); // 10 mov_reg32_reg32(EAX, EBX); // 2 and_reg32_imm32(EBX, 0x7FFFFF); // 6 mov_preg64preg64pimm32_reg32(RBX, RSI, 4, ECX); // 7 mov_preg64preg64_reg32(RBX, RSI, EDX); // 3 mov_reg64_imm64(RSI, (unsigned long long) r4300->cached_interp.invalid_code); mov_reg32_reg32(EBX, EAX); shr_reg32_imm8(EBX, 12); cmp_preg64preg64_imm8(RBX, RSI, 0); jne_rj(65); mov_reg64_imm64(RDI, (unsigned long long) r4300->cached_interp.blocks); // 10 mov_reg32_reg32(ECX, EBX); // 2 mov_reg64_preg64x8preg64(RBX, RBX, RDI); // 4 mov_reg64_preg64pimm32(RBX, RBX, (int) offsetof(struct precomp_block, block)); // 7 mov_reg64_imm64(RDI, (unsigned long long) dynarec_notcompiled); // 10 and_eax_imm32(0xFFF); // 5 shr_reg32_imm8(EAX, 2); // 3 mov_reg32_imm32(EDX, sizeof(struct precomp_instr)); // 5 mul_reg32(EDX); // 2 mov_reg64_preg64preg64pimm32(RAX, RAX, RBX, (int) offsetof(struct precomp_instr, ops)); // 8 cmp_reg64_reg64(RAX, RDI); // 3 je_rj(4); // 2 mov_preg64preg64_imm8(RCX, RSI, 1); // 4 #endif } void gen_MFC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[111]); #endif #ifdef INTERPRET_MFC1 gencallinterp(r4300, (unsigned long long)cached_interp_MFC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_reg32_preg64(EBX, RAX); mov_m32rel_xreg32((unsigned int*)r4300->recomp.dst->f.r.rt, EBX); sar_reg32_imm8(EBX, 31); mov_m32rel_xreg32(((unsigned int*)r4300->recomp.dst->f.r.rt)+1, EBX); #endif } void gen_DMFC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[112]); #endif #ifdef INTERPRET_DMFC1 gencallinterp(r4300, (unsigned long long)cached_interp_DMFC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *) (&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_reg32_preg64(EBX, RAX); mov_reg32_preg64pimm32(ECX, RAX, 4); mov_m32rel_xreg32((unsigned int*)r4300->recomp.dst->f.r.rt, EBX); mov_m32rel_xreg32(((unsigned int*)r4300->recomp.dst->f.r.rt)+1, ECX); #endif } void gen_CFC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[113]); #endif #ifdef INTERPRET_CFC1 gencallinterp(r4300, (unsigned long long)cached_interp_CFC1, 0); #else gencheck_cop1_unusable(r4300); if (r4300->recomp.dst->f.r.nrd == 31) { mov_xreg32_m32rel(EAX, (unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1))); } else { mov_xreg32_m32rel(EAX, (unsigned int*)&(*r4300_cp1_fcr0(&r4300->cp1))); } mov_m32rel_xreg32((unsigned int*)r4300->recomp.dst->f.r.rt, EAX); sar_reg32_imm8(EAX, 31); mov_m32rel_xreg32(((unsigned int*)r4300->recomp.dst->f.r.rt)+1, EAX); #endif } void gen_MTC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[114]); #endif #ifdef INTERPRET_MTC1 gencallinterp(r4300, (unsigned long long)cached_interp_MTC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg32_m32rel(EAX, (unsigned int*)r4300->recomp.dst->f.r.rt); mov_xreg64_m64rel(RBX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_preg64_reg32(RBX, EAX); #endif } void gen_DMTC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[115]); #endif #ifdef INTERPRET_DMTC1 gencallinterp(r4300, (unsigned long long)cached_interp_DMTC1, 0); #else gencheck_cop1_unusable(r4300); mov_xreg32_m32rel(EAX, (unsigned int*)r4300->recomp.dst->f.r.rt); mov_xreg32_m32rel(EBX, ((unsigned int*)r4300->recomp.dst->f.r.rt)+1); mov_xreg64_m64rel(RDX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.r.nrd])); mov_preg64_reg32(RDX, EAX); mov_preg64pimm32_reg32(RDX, 4, EBX); #endif } void gen_CTC1(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[116]); #endif #ifdef INTERPRET_CTC1 gencallinterp(r4300, (unsigned long long)cached_interp_CTC1, 0); #else gencheck_cop1_unusable(r4300); if (r4300->recomp.dst->f.r.nrd != 31) { return; } mov_xreg32_m32rel(EAX, (unsigned int*)r4300->recomp.dst->f.r.rt); mov_m32rel_xreg32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), EAX); and_eax_imm32(3); cmp_eax_imm32(0); jne_rj(13); mov_m32rel_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0x33F); // 11 jmp_imm_short(51); // 2 cmp_eax_imm32(1); // 5 jne_rj(13); // 2 mov_m32rel_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0xF3F); // 11 jmp_imm_short(31); // 2 cmp_eax_imm32(2); // 5 jne_rj(13); // 2 mov_m32rel_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0xB3F); // 11 jmp_imm_short(11); // 2 mov_m32rel_imm32((unsigned int*)&r4300->cp1.rounding_mode, 0x73F); // 11 fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } /* CP1 computational instructions */ void gen_CP1_ABS_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[124]); #endif #ifdef INTERPRET_CP1_ABS_S gencallinterp(r4300, (unsigned long long)cached_interp_ABS_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fabs_(); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_ABS_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[124]); #endif #ifdef INTERPRET_CP1_ABS_D gencallinterp(r4300, (unsigned long long)cached_interp_ABS_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fabs_(); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_ADD_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[119]); #endif #ifdef INTERPRET_CP1_ADD_S gencallinterp(r4300, (unsigned long long)cached_interp_ADD_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fadd_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_ADD_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[119]); #endif #ifdef INTERPRET_CP1_ADD_D gencallinterp(r4300, (unsigned long long)cached_interp_ADD_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fadd_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_DIV_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[122]); #endif #ifdef INTERPRET_CP1_DIV_S gencallinterp(r4300, (unsigned long long)cached_interp_DIV_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fdiv_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_DIV_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[122]); #endif #ifdef INTERPRET_CP1_DIV_D gencallinterp(r4300, (unsigned long long)cached_interp_DIV_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fdiv_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_MOV_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[125]); #endif #ifdef INTERPRET_CP1_MOV_S gencallinterp(r4300, (unsigned long long)cached_interp_MOV_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); mov_reg32_preg64(EBX, RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); mov_preg64_reg32(RAX, EBX); #endif } void gen_CP1_MOV_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[125]); #endif #ifdef INTERPRET_CP1_MOV_D gencallinterp(r4300, (unsigned long long)cached_interp_MOV_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); mov_reg32_preg64(EBX, RAX); mov_reg32_preg64pimm32(ECX, RAX, 4); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); mov_preg64_reg32(RAX, EBX); mov_preg64pimm32_reg32(RAX, 4, ECX); #endif } void gen_CP1_MUL_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[121]); #endif #ifdef INTERPRET_CP1_MUL_S gencallinterp(r4300, (unsigned long long)cached_interp_MUL_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fmul_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_MUL_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[121]); #endif #ifdef INTERPRET_CP1_MUL_D gencallinterp(r4300, (unsigned long long)cached_interp_MUL_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fmul_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_NEG_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[126]); #endif #ifdef INTERPRET_CP1_NEG_S gencallinterp(r4300, (unsigned long long)cached_interp_NEG_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fchs(); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_NEG_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[126]); #endif #ifdef INTERPRET_CP1_NEG_D gencallinterp(r4300, (unsigned long long)cached_interp_NEG_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fchs(); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_SQRT_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[123]); #endif #ifdef INTERPRET_CP1_SQRT_S gencallinterp(r4300, (unsigned long long)cached_interp_SQRT_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fsqrt(); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_SQRT_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[123]); #endif #ifdef INTERPRET_CP1_SQRT_D gencallinterp(r4300, (unsigned long long)cached_interp_SQRT_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fsqrt(); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_SUB_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[120]); #endif #ifdef INTERPRET_CP1_SUB_S gencallinterp(r4300, (unsigned long long)cached_interp_SUB_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fsub_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_SUB_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[120]); #endif #ifdef INTERPRET_CP1_SUB_D gencallinterp(r4300, (unsigned long long)cached_interp_SUB_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fsub_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_TRUNC_W_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[128]); #endif #ifdef INTERPRET_CP1_TRUNC_W_S gencallinterp(r4300, (unsigned long long)cached_interp_TRUNC_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&trunc_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_TRUNC_W_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[128]); #endif #ifdef INTERPRET_CP1_TRUNC_W_D gencallinterp(r4300, (unsigned long long)cached_interp_TRUNC_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&trunc_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_TRUNC_L_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[128]); #endif #ifdef INTERPRET_CP1_TRUNC_L_S gencallinterp(r4300, (unsigned long long)cached_interp_TRUNC_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&trunc_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_TRUNC_L_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[128]); #endif #ifdef INTERPRET_CP1_TRUNC_L_D gencallinterp(r4300, (unsigned long long)cached_interp_TRUNC_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&trunc_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_W_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[127]); #endif #ifdef INTERPRET_CP1_ROUND_W_S gencallinterp(r4300, (unsigned long long)cached_interp_ROUND_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&round_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_W_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[127]); #endif #ifdef INTERPRET_CP1_ROUND_W_D gencallinterp(r4300, (unsigned long long)cached_interp_ROUND_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&round_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_L_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[127]); #endif #ifdef INTERPRET_CP1_ROUND_L_S gencallinterp(r4300, (unsigned long long)cached_interp_ROUND_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&round_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_ROUND_L_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[127]); #endif #ifdef INTERPRET_CP1_ROUND_L_D gencallinterp(r4300, (unsigned long long)cached_interp_ROUND_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&round_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_W_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[129]); #endif #ifdef INTERPRET_CP1_CEIL_W_S gencallinterp(r4300, (unsigned long long)cached_interp_CEIL_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&ceil_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_W_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[129]); #endif #ifdef INTERPRET_CP1_CEIL_W_D gencallinterp(r4300, (unsigned long long)cached_interp_CEIL_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&ceil_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_L_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[129]); #endif #ifdef INTERPRET_CP1_CEIL_L_S gencallinterp(r4300, (unsigned long long)cached_interp_CEIL_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&ceil_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CEIL_L_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[129]); #endif #ifdef INTERPRET_CP1_CEIL_L_D gencallinterp(r4300, (unsigned long long)cached_interp_CEIL_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&ceil_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_W_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[130]); #endif #ifdef INTERPRET_CP1_FLOOR_W_S gencallinterp(r4300, (unsigned long long)cached_interp_FLOOR_W_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&floor_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_W_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[130]); #endif #ifdef INTERPRET_CP1_FLOOR_W_D gencallinterp(r4300, (unsigned long long)cached_interp_FLOOR_W_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&floor_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_L_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[130]); #endif #ifdef INTERPRET_CP1_FLOOR_L_S gencallinterp(r4300, (unsigned long long)cached_interp_FLOOR_L_S, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&floor_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_FLOOR_L_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[130]); #endif #ifdef INTERPRET_CP1_FLOOR_L_D gencallinterp(r4300, (unsigned long long)cached_interp_FLOOR_L_D, 0); #else gencheck_cop1_unusable(r4300); fldcw_m16rel((unsigned short*)&floor_mode); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); fldcw_m16rel((unsigned short*)&r4300->cp1.rounding_mode); #endif } void gen_CP1_CVT_S_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_S_D gencallinterp(r4300, (unsigned long long)cached_interp_CVT_S_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_CVT_S_W(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_S_W gencallinterp(r4300, (unsigned long long)cached_interp_CVT_S_W, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_CVT_S_L(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_S_L gencallinterp(r4300, (unsigned long long)cached_interp_CVT_S_L, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_dword(RAX); #endif } void gen_CP1_CVT_D_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_D_S gencallinterp(r4300, (unsigned long long)cached_interp_CVT_D_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_CVT_D_W(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_D_W gencallinterp(r4300, (unsigned long long)cached_interp_CVT_D_W, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_CVT_D_L(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_D_L gencallinterp(r4300, (unsigned long long)cached_interp_CVT_D_L, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fild_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fstp_preg64_qword(RAX); #endif } void gen_CP1_CVT_W_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_W_S gencallinterp(r4300, (unsigned long long)cached_interp_CVT_W_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); #endif } void gen_CP1_CVT_W_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_W_D gencallinterp(r4300, (unsigned long long)cached_interp_CVT_W_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_dword(RAX); #endif } void gen_CP1_CVT_L_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_L_S gencallinterp(r4300, (unsigned long long)cached_interp_CVT_L_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); #endif } void gen_CP1_CVT_L_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[117]); #endif #ifdef INTERPRET_CP1_CVT_L_D gencallinterp(r4300, (unsigned long long)cached_interp_CVT_L_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fd])); fistp_preg64_qword(RAX); #endif } /* CP1 relational instructions */ void gen_CP1_C_F_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_F_S gencallinterp(r4300, (unsigned long long)cached_interp_C_F_S, 0); #else gencheck_cop1_unusable(r4300); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_F_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_F_D gencallinterp(r4300, (unsigned long long)cached_interp_C_F_D, 0); #else gencheck_cop1_unusable(r4300); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_UN_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_UN_S gencallinterp(r4300, (unsigned long long)cached_interp_C_UN_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(13); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 jmp_imm_short(11); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 #endif } void gen_CP1_C_UN_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_UN_D gencallinterp(r4300, (unsigned long long)cached_interp_C_UN_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(13); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 jmp_imm_short(11); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 #endif } void gen_CP1_C_EQ_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_EQ_S gencallinterp(r4300, (unsigned long long)cached_interp_C_EQ_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jne_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_EQ_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_EQ_D gencallinterp(r4300, (unsigned long long)cached_interp_C_EQ_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jne_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_UEQ_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_UEQ_S gencallinterp(r4300, (unsigned long long)cached_interp_C_UEQ_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jne_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_UEQ_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_UEQ_D gencallinterp(r4300, (unsigned long long)cached_interp_C_UEQ_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jne_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_OLT_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_OLT_S gencallinterp(r4300, (unsigned long long)cached_interp_C_OLT_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jae_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_OLT_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_OLT_D gencallinterp(r4300, (unsigned long long)cached_interp_C_OLT_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jae_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_ULT_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_ULT_S gencallinterp(r4300, (unsigned long long)cached_interp_C_ULT_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jae_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_ULT_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_ULT_D gencallinterp(r4300, (unsigned long long)cached_interp_C_ULT_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jae_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_OLE_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_OLE_S gencallinterp(r4300, (unsigned long long)cached_interp_C_OLE_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fucomip_fpreg(1); ffree_fpreg(0); ja_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_OLE_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_OLE_D gencallinterp(r4300, (unsigned long long)cached_interp_C_OLE_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fucomip_fpreg(1); ffree_fpreg(0); ja_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_ULE_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_ULE_S gencallinterp(r4300, (unsigned long long)cached_interp_C_ULE_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(15); ja_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_ULE_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_ULE_D gencallinterp(r4300, (unsigned long long)cached_interp_C_ULE_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fucomip_fpreg(1); ffree_fpreg(0); jp_rj(15); ja_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_SF_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_SF_S gencallinterp(r4300, (unsigned long long)cached_interp_C_SF_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_SF_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_SF_D gencallinterp(r4300, (unsigned long long)cached_interp_C_SF_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); #endif } void gen_CP1_C_NGLE_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGLE_S gencallinterp(r4300, (unsigned long long)cached_interp_C_NGLE_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(13); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 jmp_imm_short(11); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 #endif } void gen_CP1_C_NGLE_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGLE_D gencallinterp(r4300, (unsigned long long)cached_interp_C_NGLE_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(13); and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 jmp_imm_short(11); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 #endif } void gen_CP1_C_SEQ_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_SEQ_S gencallinterp(r4300, (unsigned long long)cached_interp_C_SEQ_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jne_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_SEQ_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_SEQ_D gencallinterp(r4300, (unsigned long long)cached_interp_C_SEQ_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jne_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_NGL_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGL_S gencallinterp(r4300, (unsigned long long)cached_interp_C_NGL_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jne_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_NGL_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGL_D gencallinterp(r4300, (unsigned long long)cached_interp_C_NGL_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jne_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_LT_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_LT_S gencallinterp(r4300, (unsigned long long)cached_interp_C_LT_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jae_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_LT_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_LT_D gencallinterp(r4300, (unsigned long long)cached_interp_C_LT_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jae_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_NGE_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGE_S gencallinterp(r4300, (unsigned long long)cached_interp_C_NGE_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jae_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_NGE_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGE_D gencallinterp(r4300, (unsigned long long)cached_interp_C_NGE_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(15); jae_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_LE_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_LE_S gencallinterp(r4300, (unsigned long long)cached_interp_C_LE_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); ja_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_LE_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_LE_D gencallinterp(r4300, (unsigned long long)cached_interp_C_LE_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); ja_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_NGT_S(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGT_S gencallinterp(r4300, (unsigned long long)cached_interp_C_NGT_S, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_dword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_simple(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_dword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(15); ja_rj(13); or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } void gen_CP1_C_NGT_D(struct r4300_core* r4300) { #if defined(COUNT_INSTR) inc_m32rel(&instr_count[118]); #endif #ifdef INTERPRET_CP1_C_NGT_D gencallinterp(r4300, (unsigned long long)cached_interp_C_NGT_D, 0); #else gencheck_cop1_unusable(r4300); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.ft])); fld_preg64_qword(RAX); mov_xreg64_m64rel(RAX, (unsigned long long *)(&(r4300_cp1_regs_double(&r4300->cp1))[r4300->recomp.dst->f.cf.fs])); fld_preg64_qword(RAX); fcomip_fpreg(1); ffree_fpreg(0); jp_rj(15); ja_rj(13); // 2 or_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), 0x800000); // 11 jmp_imm_short(11); // 2 and_m32rel_imm32((unsigned int*)&(*r4300_cp1_fcr31(&r4300->cp1)), ~0x800000); // 11 #endif } mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/interpret.h000066400000000000000000000171471464506436200234010ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - interpret.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2007 Richard Goedeken (Richard42) * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_R4300_X86_64_INTERPRET_H #define M64P_DEVICE_R4300_X86_64_INTERPRET_H //#define INTERPRET_J //#define INTERPRET_J_OUT //#define INTERPRET_J_IDLE //#define INTERPRET_JAL //#define INTERPRET_JAL_OUT //#define INTERPRET_JAL_IDLE //#define INTERPRET_BEQ //#define INTERPRET_BEQ_OUT //#define INTERPRET_BEQ_IDLE //#define INTERPRET_BNE //#define INTERPRET_BNE_OUT //#define INTERPRET_BNE_IDLE //#define INTERPRET_BLEZ //#define INTERPRET_BLEZ_OUT //#define INTERPRET_BLEZ_IDLE //#define INTERPRET_BGTZ //#define INTERPRET_BGTZ_OUT //#define INTERPRET_BGTZ_IDLE //#define INTERPRET_ADDI //#define INTERPRET_ADDIU //#define INTERPRET_SLTI //#define INTERPRET_SLTIU //#define INTERPRET_ANDI //#define INTERPRET_ORI //#define INTERPRET_XORI //#define INTERPRET_LUI //#define INTERPRET_BEQL //#define INTERPRET_BEQL_OUT //#define INTERPRET_BEQL_IDLE //#define INTERPRET_BNEL //#define INTERPRET_BNEL_OUT //#define INTERPRET_BNEL_IDLE //#define INTERPRET_BLEZL //#define INTERPRET_BLEZL_OUT //#define INTERPRET_BLEZL_IDLE //#define INTERPRET_BGTZL //#define INTERPRET_BGTZL_OUT //#define INTERPRET_BGTZL_IDLE //#define INTERPRET_DADDI //#define INTERPRET_DADDIU //#define INTERPRET_LB //#define INTERPRET_LH //#define INTERPRET_LW //#define INTERPRET_LBU //#define INTERPRET_LHU //#define INTERPRET_LWU //#define INTERPRET_SB //#define INTERPRET_SH //#define INTERPRET_SW //#define INTERPRET_LWC1 //#define INTERPRET_LDC1 //#define INTERPRET_LD //#define INTERPRET_SWC1 //#define INTERPRET_SDC1 //#define INTERPRET_SD //#define INTERPRET_SLL //#define INTERPRET_SRL //#define INTERPRET_SRA //#define INTERPRET_SLLV //#define INTERPRET_SRLV //#define INTERPRET_SRAV //#define INTERPRET_JR //#define INTERPRET_JALR //#define INTERPRET_SYSCALL //#define INTERPRET_MFHI //#define INTERPRET_MTHI //#define INTERPRET_MFLO //#define INTERPRET_MTLO //#define INTERPRET_DSLLV //#define INTERPRET_DSRLV //#define INTERPRET_DSRAV //#define INTERPRET_MULT //#define INTERPRET_MULTU //#define INTERPRET_DIV //#define INTERPRET_DIVU //#define INTERPRET_DMULTU //#define INTERPRET_ADD //#define INTERPRET_ADDU //#define INTERPRET_SUB //#define INTERPRET_SUBU //#define INTERPRET_AND //#define INTERPRET_OR //#define INTERPRET_XOR //#define INTERPRET_NOR //#define INTERPRET_SLT //#define INTERPRET_SLTU //#define INTERPRET_DADD //#define INTERPRET_DADDU //#define INTERPRET_DSUB //#define INTERPRET_DSUBU //#define INTERPRET_DSLL //#define INTERPRET_DSRL //#define INTERPRET_DSRA //#define INTERPRET_DSLL32 //#define INTERPRET_DSRL32 //#define INTERPRET_DSRA32 //#define INTERPRET_BLTZ //#define INTERPRET_BLTZ_OUT //#define INTERPRET_BLTZ_IDLE //#define INTERPRET_BGEZ //#define INTERPRET_BGEZ_OUT //#define INTERPRET_BGEZ_IDLE //#define INTERPRET_BLTZL //#define INTERPRET_BLTZL_OUT //#define INTERPRET_BLTZL_IDLE //#define INTERPRET_BGEZL //#define INTERPRET_BGEZL_OUT //#define INTERPRET_BGEZL_IDLE //#define INTERPRET_BLTZAL //#define INTERPRET_BLTZAL_OUT //#define INTERPRET_BLTZAL_IDLE //#define INTERPRET_BGEZAL //#define INTERPRET_BGEZAL_OUT //#define INTERPRET_BGEZAL_IDLE //#define INTERPRET_BLTZALL //#define INTERPRET_BLTZALL_OUT //#define INTERPRET_BLTZALL_IDLE //#define INTERPRET_BGEZALL //#define INTERPRET_BGEZALL_OUT //#define INTERPRET_BGEZALL_IDLE //#define INTERPRET_BC1F //#define INTERPRET_BC1F_OUT //#define INTERPRET_BC1F_IDLE //#define INTERPRET_BC1T //#define INTERPRET_BC1T_OUT //#define INTERPRET_BC1T_IDLE //#define INTERPRET_BC1FL //#define INTERPRET_BC1FL_OUT //#define INTERPRET_BC1FL_IDLE //#define INTERPRET_BC1TL //#define INTERPRET_BC1TL_OUT //#define INTERPRET_BC1TL_IDLE //#define INTERPRET_MFC1 //#define INTERPRET_DMFC1 //#define INTERPRET_CFC1 //#define INTERPRET_MTC1 //#define INTERPRET_DMTC1 //#define INTERPRET_CTC1 //#define INTERPRET_CP1_ADD_D //#define INTERPRET_CP1_SUB_D //#define INTERPRET_CP1_MUL_D //#define INTERPRET_CP1_DIV_D //#define INTERPRET_CP1_SQRT_D //#define INTERPRET_CP1_ABS_D //#define INTERPRET_CP1_MOV_D //#define INTERPRET_CP1_NEG_D //#define INTERPRET_CP1_ROUND_L_D //#define INTERPRET_CP1_TRUNC_L_D //#define INTERPRET_CP1_CEIL_L_D //#define INTERPRET_CP1_FLOOR_L_D //#define INTERPRET_CP1_ROUND_W_D //#define INTERPRET_CP1_TRUNC_W_D //#define INTERPRET_CP1_CEIL_W_D //#define INTERPRET_CP1_FLOOR_W_D //#define INTERPRET_CP1_CVT_S_D //#define INTERPRET_CP1_CVT_W_D //#define INTERPRET_CP1_CVT_L_D //#define INTERPRET_CP1_C_F_D //#define INTERPRET_CP1_C_UN_D //#define INTERPRET_CP1_C_EQ_D //#define INTERPRET_CP1_C_UEQ_D //#define INTERPRET_CP1_C_OLT_D //#define INTERPRET_CP1_C_ULT_D //#define INTERPRET_CP1_C_OLE_D //#define INTERPRET_CP1_C_ULE_D //#define INTERPRET_CP1_C_SF_D //#define INTERPRET_CP1_C_NGLE_D //#define INTERPRET_CP1_C_SEQ_D //#define INTERPRET_CP1_C_NGL_D //#define INTERPRET_CP1_C_LT_D //#define INTERPRET_CP1_C_NGE_D //#define INTERPRET_CP1_C_LE_D //#define INTERPRET_CP1_C_NGT_D //#define INTERPRET_CP1_CVT_S_L //#define INTERPRET_CP1_CVT_D_L //#define INTERPRET_CP1_CVT_S_W //#define INTERPRET_CP1_CVT_D_W //#define INTERPRET_CP1_ADD_S //#define INTERPRET_CP1_SUB_S //#define INTERPRET_CP1_MUL_S //#define INTERPRET_CP1_DIV_S //#define INTERPRET_CP1_SQRT_S //#define INTERPRET_CP1_ABS_S //#define INTERPRET_CP1_MOV_S //#define INTERPRET_CP1_NEG_S //#define INTERPRET_CP1_ROUND_L_S //#define INTERPRET_CP1_TRUNC_L_S //#define INTERPRET_CP1_CEIL_L_S //#define INTERPRET_CP1_FLOOR_L_S //#define INTERPRET_CP1_ROUND_W_S //#define INTERPRET_CP1_TRUNC_W_S //#define INTERPRET_CP1_CEIL_W_S //#define INTERPRET_CP1_FLOOR_W_S //#define INTERPRET_CP1_CVT_D_S //#define INTERPRET_CP1_CVT_W_S //#define INTERPRET_CP1_CVT_L_S //#define INTERPRET_CP1_C_F_S //#define INTERPRET_CP1_C_UN_S //#define INTERPRET_CP1_C_EQ_S //#define INTERPRET_CP1_C_UEQ_S //#define INTERPRET_CP1_C_OLT_S //#define INTERPRET_CP1_C_ULT_S //#define INTERPRET_CP1_C_OLE_S //#define INTERPRET_CP1_C_ULE_S //#define INTERPRET_CP1_C_SF_S //#define INTERPRET_CP1_C_NGLE_S //#define INTERPRET_CP1_C_SEQ_S //#define INTERPRET_CP1_C_NGL_S //#define INTERPRET_CP1_C_LT_S //#define INTERPRET_CP1_C_NGE_S //#define INTERPRET_CP1_C_LE_S //#define INTERPRET_CP1_C_NGT_S #endif /* M64P_DEVICE_R4300_X86_64_INTERPRET_H */ mupen64plus-core-src-2.6.0/src/device/r4300/x86_64/regcache.c000066400000000000000000000604451464506436200231200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - regcache.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2007 Richard Goedeken (Richard42) * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "assemble.h" #include "assemble_struct.h" #include "regcache.h" #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/r4300/r4300_core.h" #include "device/r4300/recomp.h" void init_cache(struct r4300_core* r4300, struct precomp_instr* start) { int i; for (i=0; i<8; i++) { r4300->recomp.regcache_state.reg_content[i] = NULL; r4300->recomp.regcache_state.last_access[i] = NULL; r4300->recomp.regcache_state.free_since[i] = start; r4300->recomp.regcache_state.dirty[i] = 0; r4300->recomp.regcache_state.is64bits[i] = 0; } r4300->recomp.regcache_state.r0 = (unsigned long long *) r4300_regs(r4300); } void free_all_registers(struct r4300_core* r4300) { #if defined(PROFILE_R4300) int freestart = r4300->recomp.code_length; int flushed = 0; #endif int i; for (i=0; i<8; i++) { #if defined(PROFILE_R4300) if (r4300->recomp.regcache_state.last_access[i] && r4300->recomp.regcache_state.dirty[i]) flushed = 1; #endif if (r4300->recomp.regcache_state.last_access[i]) { free_register(r4300, i); } else { while (r4300->recomp.regcache_state.free_since[i] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[i]->reg_cache_infos.needed_registers[i] = NULL; r4300->recomp.regcache_state.free_since[i]++; } } } #if defined(PROFILE_R4300) if (flushed == 1) { long long x86addr = (long long) ((*r4300->recomp.inst_pointer) + freestart); int mipsop = -5; if (fwrite(&mipsop, 1, 4, r4300->recomp.pfProfile) != 4 || /* -5 = regcache flushing */ fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) // write pointer to start of register cache flushing instructions DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); x86addr = (long long) ((*r4300->recomp.inst_pointer) + r4300->recomp.code_length); if (fwrite(&r4300->recomp.src, 1, 4, r4300->recomp.pfProfile) != 4 || // write 4-byte MIPS opcode for current instruction fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) // write pointer to dynamically generated x86 code for this MIPS instruction DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); } #endif } static void simplify_access(struct r4300_core* r4300) { int i; r4300->recomp.dst->local_addr = r4300->recomp.code_length; for(i=0; i<8; i++) r4300->recomp.dst->reg_cache_infos.needed_registers[i] = NULL; } void free_registers_move_start(struct r4300_core* r4300) { /* flush all dirty registers and clear needed_registers table */ free_all_registers(r4300); /* now move the start of the new instruction down past the flushing instructions */ simplify_access(r4300); } // this function frees a specific X86 GPR void free_register(struct r4300_core* r4300, int reg) { struct precomp_instr *last; if (r4300->recomp.regcache_state.last_access[reg] != NULL) last = r4300->recomp.regcache_state.last_access[reg]+1; else last = r4300->recomp.regcache_state.free_since[reg]; while (last <= r4300->recomp.dst) { if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.dirty[reg]) last->reg_cache_infos.needed_registers[reg] = r4300->recomp.regcache_state.reg_content[reg]; else last->reg_cache_infos.needed_registers[reg] = NULL; last++; } if (r4300->recomp.regcache_state.last_access[reg] == NULL) { r4300->recomp.regcache_state.free_since[reg] = r4300->recomp.dst+1; return; } if (r4300->recomp.regcache_state.dirty[reg]) { if (r4300->recomp.regcache_state.is64bits[reg]) { mov_m64rel_xreg64((unsigned long long *) r4300->recomp.regcache_state.reg_content[reg], reg); } else { movsxd_reg64_reg32(reg, reg); mov_m64rel_xreg64((unsigned long long *) r4300->recomp.regcache_state.reg_content[reg], reg); } } r4300->recomp.regcache_state.last_access[reg] = NULL; r4300->recomp.regcache_state.free_since[reg] = r4300->recomp.dst+1; } int lru_register(struct r4300_core* r4300) { unsigned long long oldest_access = 0xFFFFFFFFFFFFFFFFULL; int i, reg = 0; for (i=0; i<8; i++) { if (i != ESP && (unsigned long long) r4300->recomp.regcache_state.last_access[i] < oldest_access) { oldest_access = (unsigned long long) r4300->recomp.regcache_state.last_access[i]; reg = i; } } return reg; } int lru_base_register(struct r4300_core* r4300) /* EBP cannot be used as a base register for SIB addressing byte */ { unsigned long long oldest_access = 0xFFFFFFFFFFFFFFFFULL; int i, reg = 0; for (i=0; i<8; i++) { if (i != ESP && i != EBP && (unsigned long long) r4300->recomp.regcache_state.last_access[i] < oldest_access) { oldest_access = (unsigned long long) r4300->recomp.regcache_state.last_access[i]; reg = i; } } return reg; } void set_register_state(struct r4300_core* r4300, int reg, unsigned int *addr, int _dirty, int _is64bits) { if (addr == NULL) r4300->recomp.regcache_state.last_access[reg] = NULL; else r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = (unsigned long long *) addr; r4300->recomp.regcache_state.is64bits[reg] = _is64bits; r4300->recomp.regcache_state.dirty[reg] = _dirty; } int lock_register(struct r4300_core* r4300, int reg) { free_register(r4300, reg); r4300->recomp.regcache_state.last_access[reg] = (struct precomp_instr *) 0xFFFFFFFFFFFFFFFFULL; r4300->recomp.regcache_state.reg_content[reg] = NULL; return reg; } void unlock_register(struct r4300_core* r4300, int reg) { r4300->recomp.regcache_state.last_access[reg] = NULL; } // this function finds a register to put the data contained in addr, // if there was another value before it's cleanly removed of the // register cache. After that, the register number is returned. // If data are already cached, the function only returns the register number int allocate_register_32(struct r4300_core* r4300, unsigned int *addr) { int reg = 0, i; // is it already cached ? if (addr != NULL) { for (i = 0; i < 8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && (unsigned int *) r4300->recomp.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = r4300->recomp.regcache_state.reg_content[i]; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; r4300->recomp.regcache_state.is64bits[i] = 0; return i; } } } // it's not cached, so take the least recently used register reg = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = (unsigned long long *) addr; r4300->recomp.regcache_state.dirty[reg] = 0; r4300->recomp.regcache_state.is64bits[reg] = 0; if (addr != NULL) { if (addr == (unsigned int *) r4300->recomp.regcache_state.r0) xor_reg32_reg32(reg, reg); else mov_xreg32_m32rel(reg, addr); } return reg; } // this function is similar to allocate_register except it loads // a 64 bits value, and return the register number of the LSB part int allocate_register_64(struct r4300_core* r4300, unsigned long long *addr) { int reg, i; // is it already cached? if (addr != NULL) { for (i = 0; i < 8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = r4300->recomp.regcache_state.reg_content[i]; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; if (r4300->recomp.regcache_state.is64bits[i] == 0) { movsxd_reg64_reg32(i, i); r4300->recomp.regcache_state.is64bits[i] = 1; } return i; } } } // it's not cached, so take the least recently used register reg = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = addr; r4300->recomp.regcache_state.dirty[reg] = 0; r4300->recomp.regcache_state.is64bits[reg] = 1; if (addr != NULL) { if (addr == r4300->recomp.regcache_state.r0) xor_reg64_reg64(reg, reg); else mov_xreg64_m64rel(reg, addr); } return reg; } // this function checks if the data located at addr are cached in a register // and then, it returns 1 if it's a 64 bit value // 0 if it's a 32 bit value // -1 if it's not cached int is64(struct r4300_core* r4300, unsigned int *addr) { int i; for (i = 0; i < 8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == (unsigned long long *) addr) { return r4300->recomp.regcache_state.is64bits[i]; } } return -1; } int allocate_register_32_w(struct r4300_core* r4300, unsigned int *addr) { int reg = 0, i; // is it already cached ? for (i = 0; i < 8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == (unsigned long long *) addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i] + 1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; r4300->recomp.regcache_state.dirty[i] = 1; r4300->recomp.regcache_state.is64bits[i] = 0; return i; } } // it's not cached, so take the least recently used register reg = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = (unsigned long long *) addr; r4300->recomp.regcache_state.dirty[reg] = 1; r4300->recomp.regcache_state.is64bits[reg] = 0; return reg; } int allocate_register_64_w(struct r4300_core* r4300, unsigned long long *addr) { int reg, i; // is it already cached? for (i = 0; i < 8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i] + 1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; r4300->recomp.regcache_state.is64bits[i] = 1; r4300->recomp.regcache_state.dirty[i] = 1; return i; } } // it's not cached, so take the least recently used register reg = lru_register(r4300); if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = addr; r4300->recomp.regcache_state.dirty[reg] = 1; r4300->recomp.regcache_state.is64bits[reg] = 1; return reg; } void allocate_register_32_manually(struct r4300_core* r4300, int reg, unsigned int *addr) { int i; /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */ if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.reg_content[reg] == (unsigned long long *) addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[reg] + 1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[reg] = r4300->recomp.regcache_state.reg_content[reg]; last++; } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; /* we won't touch is64bits or dirty; the register returned is "read-only" */ return; } /* otherwise free up the requested x86 register */ if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } /* if the r4300 register is already cached in a different x86 register, then copy it to the requested x86 register */ for (i=0; i<8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == (unsigned long long *) addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = r4300->recomp.regcache_state.reg_content[i]; last++; } r4300->recomp.regcache_state.last_access[i] = r4300->recomp.dst; if (r4300->recomp.regcache_state.is64bits[i]) mov_reg64_reg64(reg, i); else mov_reg32_reg32(reg, i); r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.is64bits[reg] = r4300->recomp.regcache_state.is64bits[i]; r4300->recomp.regcache_state.dirty[reg] = r4300->recomp.regcache_state.dirty[i]; r4300->recomp.regcache_state.reg_content[reg] = r4300->recomp.regcache_state.reg_content[i]; /* free the previous x86 register used to cache this r4300 register */ r4300->recomp.regcache_state.free_since[i] = r4300->recomp.dst + 1; r4300->recomp.regcache_state.last_access[i] = NULL; return; } } /* otherwise just load the 32-bit value into the requested register */ r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = (unsigned long long *) addr; r4300->recomp.regcache_state.dirty[reg] = 0; r4300->recomp.regcache_state.is64bits[reg] = 0; if ((unsigned long long *) addr == r4300->recomp.regcache_state.r0) xor_reg32_reg32(reg, reg); else mov_xreg32_m32rel(reg, addr); } void allocate_register_32_manually_w(struct r4300_core* r4300, int reg, unsigned int *addr) { int i; /* check if we just happen to already have this r4300 reg cached in the requested x86 reg */ if (r4300->recomp.regcache_state.last_access[reg] != NULL && r4300->recomp.regcache_state.reg_content[reg] == (unsigned long long *) addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[reg]+1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[reg] = NULL; last++; } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.is64bits[reg] = 0; r4300->recomp.regcache_state.dirty[reg] = 1; return; } /* otherwise free up the requested x86 register */ if (r4300->recomp.regcache_state.last_access[reg]) free_register(r4300, reg); else { while (r4300->recomp.regcache_state.free_since[reg] <= r4300->recomp.dst) { r4300->recomp.regcache_state.free_since[reg]->reg_cache_infos.needed_registers[reg] = NULL; r4300->recomp.regcache_state.free_since[reg]++; } } /* if the r4300 register is already cached in a different x86 register, then free it and bind to the requested x86 register */ for (i = 0; i < 8; i++) { if (r4300->recomp.regcache_state.last_access[i] != NULL && r4300->recomp.regcache_state.reg_content[i] == (unsigned long long *) addr) { struct precomp_instr *last = r4300->recomp.regcache_state.last_access[i] + 1; while (last <= r4300->recomp.dst) { last->reg_cache_infos.needed_registers[i] = NULL; last++; } r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = r4300->recomp.regcache_state.reg_content[i]; r4300->recomp.regcache_state.dirty[reg] = 1; r4300->recomp.regcache_state.is64bits[reg] = 0; /* free the previous x86 register used to cache this r4300 register */ r4300->recomp.regcache_state.free_since[i] = r4300->recomp.dst+1; r4300->recomp.regcache_state.last_access[i] = NULL; return; } } /* otherwise just set up the requested register as 32-bit */ r4300->recomp.regcache_state.last_access[reg] = r4300->recomp.dst; r4300->recomp.regcache_state.reg_content[reg] = (unsigned long long *) addr; r4300->recomp.regcache_state.dirty[reg] = 1; r4300->recomp.regcache_state.is64bits[reg] = 0; } // 0x48 0x83 0xEC 0x8 sub rsp, byte 8 // 0x48 0xA1 0xXXXXXXXXXXXXXXXX mov rax, qword (&code start) // 0x48 0x05 0xXXXXXXXX add rax, dword (local_addr) // 0x48 0x89 0x04 0x24 mov [rsp], rax // 0x48 0xB8 0xXXXXXXXXXXXXXXXX mov rax, ®[0] // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rdi, [rax + XXXXXXXX] // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rsi, [rax + XXXXXXXX] // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rbp, [rax + XXXXXXXX] // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rdx, [rax + XXXXXXXX] // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rcx, [rax + XXXXXXXX] // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rbx, [rax + XXXXXXXX] // 0x48 0x8B (reg<<3)|0x80 0xXXXXXXXX mov rax, [rax + XXXXXXXX] // 0xC3 ret // total : 84 bytes static void build_wrapper(struct r4300_core* r4300, struct precomp_instr *instr, unsigned char* pCode, struct precomp_block* block) { int i; #if defined(PROFILE_R4300) long long x86addr = (long long) pCode; int mipsop = -4; if (fwrite(&mipsop, 1, 4, r4300->recomp.pfProfile) != 4 || // write 4-byte MIPS opcode fwrite(&x86addr, 1, sizeof(char *), r4300->recomp.pfProfile) != sizeof(char *)) // write pointer to dynamically generated x86 code for this MIPS instruction DebugMessage(M64MSG_ERROR, "Error writing R4300 instruction address profiling data"); #endif *pCode++ = 0x48; *pCode++ = 0x83; *pCode++ = 0xEC; *pCode++ = 0x08; *pCode++ = 0x48; *pCode++ = 0xA1; *((unsigned long long *) pCode) = (unsigned long long) (&block->code); pCode += 8; *pCode++ = 0x48; *pCode++ = 0x05; *((unsigned int *) pCode) = (unsigned int) instr->local_addr; pCode += 4; *pCode++ = 0x48; *pCode++ = 0x89; *pCode++ = 0x04; *pCode++ = 0x24; *pCode++ = 0x48; *pCode++ = 0xB8; *((unsigned long long *) pCode) = (unsigned long long) &r4300_regs(r4300)[0]; pCode += 8; for (i=7; i>=0; i--) { long long riprel; if (instr->reg_cache_infos.needed_registers[i] != NULL) { *pCode++ = 0x48; *pCode++ = 0x8B; *pCode++ = 0x80 | (i << 3); riprel = (long long) ((unsigned char *) instr->reg_cache_infos.needed_registers[i] - (unsigned char *) &r4300_regs(r4300)[0]); *((int *) pCode) = (int) riprel; pCode += 4; if (riprel >= 0x7fffffffLL || riprel < -0x80000000LL) { DebugMessage(M64MSG_ERROR, "build_wrapper error: regs[%i] offset too big for relative address from %p to %p", i, (void*)(&r4300_regs(r4300)[0]), instr->reg_cache_infos.needed_registers[i]); OSAL_BREAKPOINT_INTERRUPT; } } } *pCode++ = 0xC3; } void build_wrappers(struct r4300_core* r4300, struct precomp_instr *instr, int start, int end, struct precomp_block* block) { int i, reg; for (i=start; i #include "backends/api/audio_out_backend.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/ri/ri_controller.h" #include "device/rcp/vi/vi_controller.h" #include "device/rdram/rdram.h" #define AI_STATUS_BUSY UINT32_C(0x40000000) #define AI_STATUS_FULL UINT32_C(0x80000000) static uint32_t get_remaining_dma_length(struct ai_controller* ai) { unsigned int* next_ai_event; unsigned int remaining_dma_duration; const uint32_t* cp0_regs; if (ai->fifo[0].duration == 0) return 0; cp0_update_count(ai->mi->r4300); next_ai_event = get_event(&ai->mi->r4300->cp0.q, AI_INT); if (next_ai_event == NULL) return 0; cp0_regs = r4300_cp0_regs(&ai->mi->r4300->cp0); if ((int)(cp0_regs[CP0_COUNT_REG] - *next_ai_event) >= 0) return 0; remaining_dma_duration = *next_ai_event - cp0_regs[CP0_COUNT_REG]; uint64_t dma_length = (uint64_t)remaining_dma_duration * ai->fifo[0].length / ai->fifo[0].duration; return dma_length&~7; } static unsigned int get_dma_duration(struct ai_controller* ai) { unsigned int samples_per_sec = ai->vi->clock / (1 + ai->regs[AI_DACRATE_REG]); unsigned int bytes_per_sample = 4; /* XXX: assume 16bit stereo - should depends on bitrate instead */ unsigned int cpu_counts_per_sec = ai->vi->delay == 0 ? ai->vi->clock : ai->vi->delay * ai->vi->expected_refresh_rate; /* estimate cpu counts/sec using VI */ return ai->regs[AI_LEN_REG] * (cpu_counts_per_sec / (bytes_per_sample * samples_per_sec)); } static void do_dma(struct ai_controller* ai, struct ai_dma* dma) { /* lazy initialization of sample format */ if (ai->samples_format_changed) { unsigned int frequency = (ai->regs[AI_DACRATE_REG] == 0) ? 44100 /* default sample rate */ : ai->vi->clock / (1 + ai->regs[AI_DACRATE_REG]); ai->iaout->set_frequency(ai->aout, frequency); ai->samples_format_changed = 0; } ai->last_read = dma->length; if (ai->delayed_carry) dma->address += 0x2000; if (((dma->address + dma->length) & 0x1FFF) == 0) ai->delayed_carry = 1; else ai->delayed_carry = 0; /* schedule end of dma event */ cp0_update_count(ai->mi->r4300); add_interrupt_event(&ai->mi->r4300->cp0, AI_INT, dma->duration); } static void fifo_push(struct ai_controller* ai) { unsigned int duration = get_dma_duration(ai) * ai->dma_modifier; if (ai->regs[AI_STATUS_REG] & AI_STATUS_BUSY) { ai->fifo[1].address = ai->regs[AI_DRAM_ADDR_REG]; ai->fifo[1].length = ai->regs[AI_LEN_REG] & ~UINT32_C(7); ai->fifo[1].duration = duration; ai->regs[AI_STATUS_REG] |= AI_STATUS_FULL; } else { ai->fifo[0].address = ai->regs[AI_DRAM_ADDR_REG]; ai->fifo[0].length = ai->regs[AI_LEN_REG] & ~UINT32_C(7); ai->fifo[0].duration = duration; ai->regs[AI_STATUS_REG] |= AI_STATUS_BUSY; do_dma(ai, &ai->fifo[0]); } } static void fifo_pop(struct ai_controller* ai) { if (ai->regs[AI_STATUS_REG] & AI_STATUS_FULL) { ai->fifo[0].address = ai->fifo[1].address; ai->fifo[0].length = ai->fifo[1].length; ai->fifo[0].duration = ai->fifo[1].duration; ai->regs[AI_STATUS_REG] &= ~AI_STATUS_FULL; do_dma(ai, &ai->fifo[0]); } else { ai->regs[AI_STATUS_REG] &= ~AI_STATUS_BUSY; ai->delayed_carry = 0; } } void init_ai(struct ai_controller* ai, struct mi_controller* mi, struct ri_controller* ri, struct vi_controller* vi, void* aout, const struct audio_out_backend_interface* iaout, float dma_modifier) { ai->mi = mi; ai->ri = ri; ai->vi = vi; ai->aout = aout; ai->iaout = iaout; ai->dma_modifier = dma_modifier; } void poweron_ai(struct ai_controller* ai) { memset(ai->regs, 0, AI_REGS_COUNT*sizeof(uint32_t)); memset(ai->fifo, 0, AI_DMA_FIFO_SIZE*sizeof(struct ai_dma)); ai->samples_format_changed = 0; ai->last_read = 0; ai->delayed_carry = 0; } void read_ai_regs(void* opaque, uint32_t address, uint32_t* value) { struct ai_controller* ai = (struct ai_controller*)opaque; uint32_t reg = ai_reg(address); if (reg == AI_LEN_REG) { *value = get_remaining_dma_length(ai); if (*value < ai->last_read) { unsigned int diff = ai->fifo[0].length - ai->last_read; unsigned char *p = (unsigned char*)&ai->ri->rdram->dram[ai->fifo[0].address/4]; ai->iaout->push_samples(ai->aout, p + diff, ai->last_read - *value); ai->last_read = *value; } } else { *value = ai->regs[reg]; } } void write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct ai_controller* ai = (struct ai_controller*)opaque; uint32_t reg = ai_reg(address); switch (reg) { case AI_LEN_REG: masked_write(&ai->regs[AI_LEN_REG], value, mask); if (ai->regs[AI_LEN_REG] != 0) { fifo_push(ai); } else { /* stop sound */ } return; case AI_STATUS_REG: clear_rcp_interrupt(ai->mi, MI_INTR_AI); return; case AI_DACRATE_REG: /* lazy audio format setting */ if ((ai->regs[reg]) != (value & mask)) ai->samples_format_changed = 1; masked_write(&ai->regs[reg], value, mask); return; } masked_write(&ai->regs[reg], value, mask); } void ai_end_of_dma_event(void* opaque) { struct ai_controller* ai = (struct ai_controller*)opaque; if (ai->last_read != 0) { unsigned int diff = ai->fifo[0].length - ai->last_read; unsigned char *p = (unsigned char*)&ai->ri->rdram->dram[ai->fifo[0].address/4]; ai->iaout->push_samples(ai->aout, p + diff, ai->last_read); ai->last_read = 0; } fifo_pop(ai); raise_rcp_interrupt(ai->mi, MI_INTR_AI); } mupen64plus-core-src-2.6.0/src/device/rcp/ai/ai_controller.h000066400000000000000000000060061464506436200236600ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - ai_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_AI_AI_CONTROLLER_H #define M64P_DEVICE_RCP_AI_AI_CONTROLLER_H #include #include #include "osal/preproc.h" struct mi_controller; struct ri_controller; struct vi_controller; struct audio_out_backend_interface; enum ai_registers { AI_DRAM_ADDR_REG, AI_LEN_REG, AI_CONTROL_REG, AI_STATUS_REG, AI_DACRATE_REG, AI_BITRATE_REG, AI_REGS_COUNT }; struct ai_dma { uint32_t address; uint32_t length; unsigned int duration; }; enum { AI_DMA_FIFO_SIZE = 2 }; struct ai_controller { uint32_t regs[AI_REGS_COUNT]; struct ai_dma fifo[AI_DMA_FIFO_SIZE]; unsigned int samples_format_changed; uint32_t last_read; uint32_t delayed_carry; float dma_modifier; struct mi_controller* mi; struct ri_controller* ri; struct vi_controller* vi; void* aout; const struct audio_out_backend_interface* iaout; }; static osal_inline uint32_t ai_reg(uint32_t address) { return (address & 0xffff) >> 2; } void init_ai(struct ai_controller* ai, struct mi_controller* mi, struct ri_controller* ri, struct vi_controller* vi, void* aout, const struct audio_out_backend_interface* iaout, float dma_modifier); void poweron_ai(struct ai_controller* ai); void read_ai_regs(void* opaque, uint32_t address, uint32_t* value); void write_ai_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void ai_end_of_dma_event(void* opaque); #endif mupen64plus-core-src-2.6.0/src/device/rcp/mi/000077500000000000000000000000001464506436200206655ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rcp/mi/mi_controller.c000066400000000000000000000117541464506436200237110ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - mi_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "mi_controller.h" #include #include "device/r4300/cp0.h" #include "device/r4300/interrupt.h" #include "device/r4300/r4300_core.h" static int update_mi_init_mode(uint32_t* mi_init_mode, uint32_t w) { int clear_dp = 0; /* set init_length */ *mi_init_mode &= ~0x7f; *mi_init_mode |= w & 0x7f; /* clear / set init_mode */ if (w & 0x80) *mi_init_mode &= ~0x80; if (w & 0x100) *mi_init_mode |= 0x80; /* clear / set ebus test_mode */ if (w & 0x200) *mi_init_mode &= ~0x100; if (w & 0x400) *mi_init_mode |= 0x100; /* clear DP interrupt */ if (w & 0x800) clear_dp = 1; /* clear / set RDRAM reg_mode */ if (w & 0x1000) *mi_init_mode &= ~0x200; if (w & 0x2000) *mi_init_mode |= 0x200; return clear_dp; } static void update_mi_intr_mask(uint32_t* mi_intr_mask, uint32_t w) { if (w & 0x1) *mi_intr_mask &= ~MI_INTR_SP; if (w & 0x2) *mi_intr_mask |= MI_INTR_SP; if (w & 0x4) *mi_intr_mask &= ~MI_INTR_SI; if (w & 0x8) *mi_intr_mask |= MI_INTR_SI; if (w & 0x10) *mi_intr_mask &= ~MI_INTR_AI; if (w & 0x20) *mi_intr_mask |= MI_INTR_AI; if (w & 0x40) *mi_intr_mask &= ~MI_INTR_VI; if (w & 0x80) *mi_intr_mask |= MI_INTR_VI; if (w & 0x100) *mi_intr_mask &= ~MI_INTR_PI; if (w & 0x200) *mi_intr_mask |= MI_INTR_PI; if (w & 0x400) *mi_intr_mask &= ~MI_INTR_DP; if (w & 0x800) *mi_intr_mask |= MI_INTR_DP; } void init_mi(struct mi_controller* mi, struct r4300_core* r4300) { mi->r4300 = r4300; } void poweron_mi(struct mi_controller* mi) { memset(mi->regs, 0, MI_REGS_COUNT*sizeof(uint32_t)); mi->regs[MI_VERSION_REG] = 0x02020102; } void read_mi_regs(void* opaque, uint32_t address, uint32_t* value) { struct mi_controller* mi = (struct mi_controller*)opaque; uint32_t reg = mi_reg(address); *value = mi->regs[reg]; } void write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct mi_controller* mi = (struct mi_controller*)opaque; uint32_t reg = mi_reg(address); int* cp0_cycle_count = r4300_cp0_cycle_count(&mi->r4300->cp0); switch(reg) { case MI_INIT_MODE_REG: if (update_mi_init_mode(&mi->regs[MI_INIT_MODE_REG], value & mask) != 0) { clear_rcp_interrupt(mi, MI_INTR_DP); } break; case MI_INTR_MASK_REG: update_mi_intr_mask(&mi->regs[MI_INTR_MASK_REG], value & mask); r4300_check_interrupt(mi->r4300, CP0_CAUSE_IP2, mi->regs[MI_INTR_REG] & mi->regs[MI_INTR_MASK_REG]); cp0_update_count(mi->r4300); if (*cp0_cycle_count >= 0) gen_interrupt(mi->r4300); break; } } /* interrupt execution is immediate (if not masked) * Should only be called inside interrupt event handlers. * For other cases use signal_rcp_interrupt */ void raise_rcp_interrupt(struct mi_controller* mi, uint32_t mi_intr) { mi->regs[MI_INTR_REG] |= mi_intr; if (mi->regs[MI_INTR_REG] & mi->regs[MI_INTR_MASK_REG]) raise_maskable_interrupt(mi->r4300, CP0_CAUSE_IP2); } /* interrupt execution is scheduled (if not masked) */ void signal_rcp_interrupt(struct mi_controller* mi, uint32_t mi_intr) { mi->regs[MI_INTR_REG] |= mi_intr; r4300_check_interrupt(mi->r4300, CP0_CAUSE_IP2, mi->regs[MI_INTR_REG] & mi->regs[MI_INTR_MASK_REG]); } void clear_rcp_interrupt(struct mi_controller* mi, uint32_t mi_intr) { mi->regs[MI_INTR_REG] &= ~mi_intr; r4300_check_interrupt(mi->r4300, CP0_CAUSE_IP2, mi->regs[MI_INTR_REG] & mi->regs[MI_INTR_MASK_REG]); } mupen64plus-core-src-2.6.0/src/device/rcp/mi/mi_controller.h000066400000000000000000000051241464506436200237100ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - mi_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_MI_MI_CONTROLLER_H #define M64P_DEVICE_RCP_MI_MI_CONTROLLER_H #include #include "osal/preproc.h" struct r4300_core; enum mi_registers { MI_INIT_MODE_REG, MI_VERSION_REG, MI_INTR_REG, MI_INTR_MASK_REG, MI_REGS_COUNT }; enum mi_intr { MI_INTR_SP = 0x01, MI_INTR_SI = 0x02, MI_INTR_AI = 0x04, MI_INTR_VI = 0x08, MI_INTR_PI = 0x10, MI_INTR_DP = 0x20 }; struct mi_controller { uint32_t regs[MI_REGS_COUNT]; struct r4300_core* r4300; }; static osal_inline uint32_t mi_reg(uint32_t address) { return (address & 0xffff) >> 2; } void init_mi(struct mi_controller* mi, struct r4300_core* r4300); void poweron_mi(struct mi_controller* mi); void read_mi_regs(void* opaque, uint32_t address, uint32_t* value); void write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void raise_rcp_interrupt(struct mi_controller* mi, uint32_t mi_intr); void signal_rcp_interrupt(struct mi_controller* mi, uint32_t mi_intr); void clear_rcp_interrupt(struct mi_controller* mi, uint32_t mi_intr); #endif mupen64plus-core-src-2.6.0/src/device/rcp/pi/000077500000000000000000000000001464506436200206705ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rcp/pi/pi_controller.c000066400000000000000000000171531464506436200237160ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - pi_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "pi_controller.h" #define M64P_CORE_PROTOTYPES 1 #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/device.h" #include "device/dd/dd_controller.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/rdp/rdp_core.h" #include "device/rcp/ri/ri_controller.h" #define __STDC_FORMAT_MACROS #include int validate_pi_request(struct pi_controller* pi) { if (pi->regs[PI_STATUS_REG] & (PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY)) { pi->regs[PI_STATUS_REG] |= PI_STATUS_ERROR; return 0; } return 1; } static void dma_pi_read(struct pi_controller* pi) { if (!validate_pi_request(pi)) return; uint32_t cart_addr = pi->regs[PI_CART_ADDR_REG] & ~UINT32_C(1); uint32_t dram_addr = pi->regs[PI_DRAM_ADDR_REG] & 0xfffffe; uint32_t length = (pi->regs[PI_RD_LEN_REG] & UINT32_C(0x00ffffff)) + 1; const uint8_t* dram = (uint8_t*)pi->ri->rdram->dram; const struct pi_dma_handler* handler = NULL; void* opaque = NULL; pi->get_pi_dma_handler(pi->cart, pi->dd, cart_addr, &opaque, &handler); if (handler == NULL) { DebugMessage(M64MSG_WARNING, "Unknown PI DMA read: 0x%" PRIX32 " -> 0x%" PRIX32 " (0x%" PRIX32 ")", dram_addr, cart_addr, length); return; } pre_framebuffer_read(&pi->dp->fb, dram_addr); /* PI seems to treat the first 128 bytes differently, see https://n64brew.dev/wiki/Peripheral_Interface#Unaligned_DMA_transfer */ if (length >= 0x7f && (length & 1)) length += 1; unsigned int cycles = handler->dma_read(opaque, dram, dram_addr, cart_addr, length); /* Mark DMA as busy */ pi->regs[PI_STATUS_REG] |= PI_STATUS_DMA_BUSY; /* Update PI_DRAM_ADDR_REG and PI_CART_ADDR_REG */ pi->regs[PI_DRAM_ADDR_REG] = (pi->regs[PI_DRAM_ADDR_REG] + length + 7) & ~7; pi->regs[PI_CART_ADDR_REG] = (pi->regs[PI_CART_ADDR_REG] + length + 1) & ~1; /* schedule end of dma interrupt event */ cp0_update_count(pi->mi->r4300); add_interrupt_event(&pi->mi->r4300->cp0, PI_INT, cycles); } static void dma_pi_write(struct pi_controller* pi) { if (!validate_pi_request(pi)) return; uint32_t cart_addr = pi->regs[PI_CART_ADDR_REG] & ~UINT32_C(1); uint32_t dram_addr = pi->regs[PI_DRAM_ADDR_REG] & 0xfffffe; uint32_t length = (pi->regs[PI_WR_LEN_REG] & UINT32_C(0x00ffffff)) + 1; uint8_t* dram = (uint8_t*)pi->ri->rdram->dram; const struct pi_dma_handler* handler = NULL; void* opaque = NULL; pi->get_pi_dma_handler(pi->cart, pi->dd, cart_addr, &opaque, &handler); if (handler == NULL) { DebugMessage(M64MSG_WARNING, "Unknown PI DMA write: 0x%" PRIX32 " -> 0x%" PRIX32 " (0x%" PRIX32 ")", cart_addr, dram_addr, length); return; } /* PI seems to treat the first 128 bytes differently, see https://n64brew.dev/wiki/Peripheral_Interface#Unaligned_DMA_transfer */ if (length >= 0x7f && (length & 1)) length += 1; if (length <= 0x80) length -= dram_addr & 0x7; unsigned int cycles = handler->dma_write(opaque, dram, dram_addr, cart_addr, length); post_framebuffer_write(&pi->dp->fb, dram_addr, length); /* Mark DMA as busy */ pi->regs[PI_STATUS_REG] |= PI_STATUS_DMA_BUSY; /* Update PI_DRAM_ADDR_REG and PI_CART_ADDR_REG */ pi->regs[PI_DRAM_ADDR_REG] = (pi->regs[PI_DRAM_ADDR_REG] + length + 7) & ~7; pi->regs[PI_CART_ADDR_REG] = (pi->regs[PI_CART_ADDR_REG] + length + 1) & ~1; /* schedule end of dma interrupt event */ cp0_update_count(pi->mi->r4300); add_interrupt_event(&pi->mi->r4300->cp0, PI_INT, cycles); } void init_pi(struct pi_controller* pi, pi_dma_handler_getter get_pi_dma_handler, struct cart* cart, struct dd_controller* dd, struct mi_controller* mi, struct ri_controller* ri, struct rdp_core* dp) { pi->get_pi_dma_handler = get_pi_dma_handler; pi->cart = cart; pi->dd = dd; pi->mi = mi; pi->ri = ri; pi->dp = dp; } void poweron_pi(struct pi_controller* pi) { memset(pi->regs, 0, PI_REGS_COUNT*sizeof(uint32_t)); } void read_pi_regs(void* opaque, uint32_t address, uint32_t* value) { struct pi_controller* pi = (struct pi_controller*)opaque; uint32_t reg = pi_reg(address); *value = pi->regs[reg]; if (reg == PI_WR_LEN_REG || reg == PI_RD_LEN_REG) *value = 0x7F; else if (reg == PI_CART_ADDR_REG) *value &= 0xFFFFFFFE; else if (reg == PI_DRAM_ADDR_REG) *value &= 0xFFFFFE; } void write_pi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct pi_controller* pi = (struct pi_controller*)opaque; uint32_t reg = pi_reg(address); switch (reg) { case PI_CART_ADDR_REG: if (pi->dd != NULL) { masked_write(&pi->regs[PI_CART_ADDR_REG], value, mask); return; } break; case PI_RD_LEN_REG: masked_write(&pi->regs[PI_RD_LEN_REG], value, mask); dma_pi_read(pi); return; case PI_WR_LEN_REG: masked_write(&pi->regs[PI_WR_LEN_REG], value, mask); dma_pi_write(pi); return; case PI_STATUS_REG: if (value & mask & PI_STATUS_CLR_INTR) { pi->regs[reg] &= ~PI_STATUS_INTERRUPT; clear_rcp_interrupt(pi->mi, MI_INTR_PI); } if (value & mask & PI_STATUS_RESET) pi->regs[PI_STATUS_REG] = 0; return; case PI_BSD_DOM1_LAT_REG: case PI_BSD_DOM1_PWD_REG: case PI_BSD_DOM1_PGS_REG: case PI_BSD_DOM1_RLS_REG: case PI_BSD_DOM2_LAT_REG: case PI_BSD_DOM2_PWD_REG: case PI_BSD_DOM2_PGS_REG: case PI_BSD_DOM2_RLS_REG: masked_write(&pi->regs[reg], value & 0xff, mask); return; } masked_write(&pi->regs[reg], value, mask); } void pi_end_of_dma_event(void* opaque) { struct pi_controller* pi = (struct pi_controller*)opaque; pi->regs[PI_STATUS_REG] &= ~(PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY); pi->regs[PI_STATUS_REG] |= PI_STATUS_INTERRUPT; raise_rcp_interrupt(pi->mi, MI_INTR_PI); } mupen64plus-core-src-2.6.0/src/device/rcp/pi/pi_controller.h000066400000000000000000000072301464506436200237160ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - pi_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_PI_PI_CONTROLLER_H #define M64P_DEVICE_RCP_PI_PI_CONTROLLER_H #include #include #include "osal/preproc.h" struct cart; struct dd_controller; struct mi_controller; struct ri_controller; struct rdp_core; enum pi_registers { PI_DRAM_ADDR_REG, PI_CART_ADDR_REG, PI_RD_LEN_REG, PI_WR_LEN_REG, PI_STATUS_REG, PI_BSD_DOM1_LAT_REG, PI_BSD_DOM1_PWD_REG, PI_BSD_DOM1_PGS_REG, PI_BSD_DOM1_RLS_REG, PI_BSD_DOM2_LAT_REG, PI_BSD_DOM2_PWD_REG, PI_BSD_DOM2_PGS_REG, PI_BSD_DOM2_RLS_REG, PI_REGS_COUNT }; enum { /* PI_STATUS - read */ PI_STATUS_DMA_BUSY = 0x01, PI_STATUS_IO_BUSY = 0x02, PI_STATUS_ERROR = 0x04, PI_STATUS_INTERRUPT = 0x08, /* PI_STATUS - write */ PI_STATUS_RESET = 0x01, PI_STATUS_CLR_INTR = 0x02 }; struct pi_dma_handler { unsigned int (*dma_read)(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); unsigned int (*dma_write)(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length); }; typedef void (*pi_dma_handler_getter)(struct cart* cart, struct dd_controller* dd, uint32_t address, void** opaque, const struct pi_dma_handler** handler); struct pi_controller { uint32_t regs[PI_REGS_COUNT]; pi_dma_handler_getter get_pi_dma_handler; struct cart* cart; struct dd_controller* dd; struct mi_controller* mi; struct ri_controller* ri; struct rdp_core* dp; }; static osal_inline uint32_t pi_reg(uint32_t address) { return (address & 0xffff) >> 2; } void init_pi(struct pi_controller* pi, pi_dma_handler_getter get_pi_dma_handler, struct cart* cart, struct dd_controller* dd, struct mi_controller* mi, struct ri_controller* ri, struct rdp_core* dp); void poweron_pi(struct pi_controller* pi); void read_pi_regs(void* opaque, uint32_t address, uint32_t* value); void write_pi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void pi_end_of_dma_event(void* opaque); int validate_pi_request(struct pi_controller* pi); #endif mupen64plus-core-src-2.6.0/src/device/rcp/rdp/000077500000000000000000000000001464506436200210455ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rcp/rdp/fb.c000066400000000000000000000163421464506436200216060ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - fb.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "fb.h" #include "api/m64p_types.h" #include "api/callbacks.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rdram/rdram.h" #include "osal/preproc.h" #include "plugin/plugin.h" #include static osal_inline size_t fb_buffer_size(const FrameBufferInfo* fb_info) { return fb_info->width * fb_info->height * fb_info->size; } void pre_framebuffer_read(struct fb* fb, uint32_t address) { if (!fb->infos[0].addr) { return; } size_t i; for (i = 0; i < FB_INFOS_COUNT; ++i) { /* skip empty fb info */ if (fb->infos[i].addr == 0) { continue; } /* if address in within a fb and its page is dirty, * notify GFX plugin and mark page as not dirty */ uint32_t begin = fb->infos[i].addr; uint32_t end = fb->infos[i].addr + fb_buffer_size(&fb->infos[i]) - 1; if ((address >= begin) && (address <= end) && (fb->dirty_page[address >> 12])) { gfx.fBRead(address); fb->dirty_page[address >> 12] = 0; } } } void post_framebuffer_write(struct fb* fb, uint32_t address, uint32_t length) { if (!fb->infos[0].addr) { return; } size_t i, j; unsigned char size; if (length % 4 == 0) size = 4; else if (length % 2 == 0) size = 2; else size = 1; for (i = 0; i < FB_INFOS_COUNT; ++i) { /* skip empty fb info */ if (fb->infos[i].addr == 0) { continue; } /* if address in within a fb notify GFX plugin */ uint32_t begin = fb->infos[i].addr; uint32_t end = fb->infos[i].addr + fb_buffer_size(&fb->infos[i]) - 1; for (j = 0; j < length; j += size) { if ((address + j >= begin) && (address + j <= end)) { gfx.fBWrite(address + j, size); } } } } void init_fb(struct fb* fb, struct memory* mem, struct rdram* rdram, struct r4300_core* r4300) { fb->mem = mem; fb->rdram = rdram; fb->r4300 = r4300; } void poweron_fb(struct fb* fb) { memset(fb->dirty_page, 0, FB_DIRTY_PAGES_COUNT*sizeof(fb->dirty_page[0])); memset(fb->infos, 0, FB_INFOS_COUNT*sizeof(fb->infos[0])); fb->once = 1; } void read_rdram_fb(void* opaque, uint32_t address, uint32_t* value) { struct fb* fb = (struct fb*)opaque; pre_framebuffer_read(fb, address); read_rdram_dram(fb->rdram, address, value); } void write_rdram_fb(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct fb* fb = (struct fb*)opaque; write_rdram_dram(fb->rdram, address, value, mask); uint32_t addr = address & ~0x3; size_t size = 4; switch(mask) { case 0x000000ff: addr += (3 ^ S8); size = 1; break; case 0x0000ff00: addr += (2 ^ S8); size = 1; break; case 0x00ff0000: addr += (1 ^ S8); size = 1; break; case 0xff000000: addr += (0 ^ S8); size = 1; break; case 0x0000ffff: addr += (2 ^ S16); size = 2; break; case 0xffff0000: addr += (0 ^ S16); size = 2; break; case 0xffffff00: addr += (0 ^ Sh16); size = 3; break; case 0x00ffffff: addr += (1 ^ Sh16); size = 3; break; case 0xffffffff: addr += 0; size = 4; break; default: DebugMessage(M64MSG_WARNING, "Unknown mask %08x !!!", mask); } post_framebuffer_write(fb, addr, size); } #define R(x) read_ ## x #define W(x) write_ ## x #define RW(x) R(x), W(x) void protect_framebuffers(struct fb* fb) { size_t i, j; struct mem_mapping fb_mapping = { 0, 0, M64P_MEM_RDRAM, { fb, RW(rdram_fb) } }; /* check API support */ if (!(gfx.fBGetFrameBufferInfo && gfx.fBRead && gfx.fBWrite) || fb->r4300->emumode == EMUMODE_DYNAREC /* Dynarecs currently miss some of the read/writes needed for FBInfo */) { return; } /* ask fb info to gfx plugin */ gfx.fBGetFrameBufferInfo(fb->infos); /* return early if not FB info is present */ if (fb->infos[0].addr == 0) { return; } for (i = 0; i < FB_INFOS_COUNT; ++i) { /* skip empty fb info */ if (fb->infos[i].addr == 0) { continue; } /* map fb rw handlers */ fb_mapping.begin = fb->infos[i].addr; fb_mapping.end = fb->infos[i].addr + fb_buffer_size(&fb->infos[i]) - 1; apply_mem_mapping(fb->mem, &fb_mapping); /* mark all pages that are within a fb as dirty */ for (j = fb_mapping.begin >> 12; j <= (fb_mapping.end >> 12); ++j) { fb->dirty_page[j] = 1; } /* disable dynarec "fast memory" code generation to avoid direct memory accesses */ if (fb->once) { fb->once = 0; #ifndef NEW_DYNAREC fb->r4300->recomp.fast_memory = 0; #endif /* also need to invalidate cached code to regen non fast memory code path */ invalidate_r4300_cached_code(fb->r4300, 0, 0); } } } void unprotect_framebuffers(struct fb* fb) { size_t i; struct mem_mapping ram_mapping = { 0, 0, M64P_MEM_RDRAM, { fb->rdram, RW(rdram_dram) } }; /* return early if FB info is not supported or empty */ if (!fb->infos[0].addr) { return; } for (i = 0; i < FB_INFOS_COUNT; ++i) { /* skip empty fb info */ if (fb->infos[i].addr == 0) { continue; } /* restore ram rw handlers */ ram_mapping.begin = fb->infos[i].addr; ram_mapping.end = fb->infos[i].addr + fb_buffer_size(&fb->infos[i]) - 1; apply_mem_mapping(fb->mem, &ram_mapping); } } mupen64plus-core-src-2.6.0/src/device/rcp/rdp/fb.h000066400000000000000000000047651464506436200216210ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - fb.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_RDP_FB_H #define M64P_DEVICE_RCP_RDP_FB_H #include #include "api/m64p_plugin.h" struct memory; struct rdram; struct r4300_core; enum { FB_INFOS_COUNT = 6 }; enum { FB_DIRTY_PAGES_COUNT = 0x800 }; struct fb { struct memory* mem; struct rdram* rdram; struct r4300_core* r4300; unsigned char dirty_page[FB_DIRTY_PAGES_COUNT]; FrameBufferInfo infos[FB_INFOS_COUNT]; unsigned int once; }; void init_fb(struct fb* fb, struct memory* mem, struct rdram* rdram, struct r4300_core* r4300); void poweron_fb(struct fb* fb); void read_rdram_fb(void* opaque, uint32_t address, uint32_t* value); void write_rdram_fb(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void protect_framebuffers(struct fb* fb); void unprotect_framebuffers(struct fb* fb); void pre_framebuffer_read(struct fb* fb, uint32_t address); void post_framebuffer_write(struct fb* fb, uint32_t address, uint32_t length); #endif mupen64plus-core-src-2.6.0/src/device/rcp/rdp/rdp_core.c000066400000000000000000000114111464506436200230040ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rdp_core.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "rdp_core.h" #include #include "device/memory/memory.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/rsp/rsp_core.h" #include "plugin/plugin.h" static void update_dpc_status(struct rdp_core* dp, uint32_t w) { /* clear / set xbus_dmem_dma */ if (w & DPC_CLR_XBUS_DMEM_DMA) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_XBUS_DMEM_DMA; if (w & DPC_SET_XBUS_DMEM_DMA) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_XBUS_DMEM_DMA; /* clear / set freeze */ if (w & DPC_CLR_FREEZE) { dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FREEZE; if (dp->do_on_unfreeze & DELAY_DP_INT) signal_rcp_interrupt(dp->mi, MI_INTR_DP); if (dp->do_on_unfreeze & DELAY_UPDATESCREEN) gfx.updateScreen(); dp->do_on_unfreeze = 0; } if (w & DPC_SET_FREEZE) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FREEZE; /* clear / set flush */ if (w & DPC_CLR_FLUSH) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FLUSH; if (w & DPC_SET_FLUSH) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FLUSH; /* clear clock counter */ if (w & DPC_CLR_CLOCK_CTR) dp->dpc_regs[DPC_CLOCK_REG] = 0; } void init_rdp(struct rdp_core* dp, struct rsp_core* sp, struct mi_controller* mi, struct memory* mem, struct rdram* rdram, struct r4300_core* r4300) { dp->sp = sp; dp->mi = mi; init_fb(&dp->fb, mem, rdram, r4300); } void poweron_rdp(struct rdp_core* dp) { memset(dp->dpc_regs, 0, DPC_REGS_COUNT*sizeof(uint32_t)); memset(dp->dps_regs, 0, DPS_REGS_COUNT*sizeof(uint32_t)); dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK; dp->do_on_unfreeze = 0; poweron_fb(&dp->fb); } void read_dpc_regs(void* opaque, uint32_t address, uint32_t* value) { struct rdp_core* dp = (struct rdp_core*)opaque; uint32_t reg = dpc_reg(address); *value = dp->dpc_regs[reg]; } void write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rdp_core* dp = (struct rdp_core*)opaque; uint32_t reg = dpc_reg(address); switch(reg) { case DPC_STATUS_REG: update_dpc_status(dp, value & mask); case DPC_CURRENT_REG: case DPC_CLOCK_REG: case DPC_BUFBUSY_REG: case DPC_PIPEBUSY_REG: case DPC_TMEM_REG: return; } masked_write(&dp->dpc_regs[reg], value, mask); switch(reg) { case DPC_START_REG: dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG]; break; case DPC_END_REG: unprotect_framebuffers(&dp->fb); gfx.processRDPList(); protect_framebuffers(&dp->fb); signal_rcp_interrupt(dp->mi, MI_INTR_DP); break; } } void read_dps_regs(void* opaque, uint32_t address, uint32_t* value) { struct rdp_core* dp = (struct rdp_core*)opaque; uint32_t reg = dps_reg(address); *value = dp->dps_regs[reg]; } void write_dps_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rdp_core* dp = (struct rdp_core*)opaque; uint32_t reg = dps_reg(address); masked_write(&dp->dps_regs[reg], value, mask); } void rdp_interrupt_event(void* opaque) { struct rdp_core* dp = (struct rdp_core*)opaque; raise_rcp_interrupt(dp->mi, MI_INTR_DP); } mupen64plus-core-src-2.6.0/src/device/rcp/rdp/rdp_core.h000066400000000000000000000074751464506436200230300ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rdp_core.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_RDP_RDP_CORE_H #define M64P_DEVICE_RCP_RDP_RDP_CORE_H #include #include "fb.h" #include "osal/preproc.h" struct mi_controller; struct rsp_core; enum { /* DPC status - read */ DPC_STATUS_XBUS_DMEM_DMA = 0x001, DPC_STATUS_FREEZE = 0x002, DPC_STATUS_FLUSH = 0x004, DPC_STATUS_START_GCLK = 0x008, DPC_STATUS_CBUF_READY = 0x080, DPC_STATUS_END_VALID = 0x200, DPC_STATUS_START_VALID = 0x400, /* DPC status - write */ DPC_CLR_XBUS_DMEM_DMA = 0x001, DPC_SET_XBUS_DMEM_DMA = 0x002, DPC_CLR_FREEZE = 0x004, DPC_SET_FREEZE = 0x008, DPC_CLR_FLUSH = 0x010, DPC_SET_FLUSH = 0x020, DPC_CLR_TMEM_CTR = 0x040, DPC_CLR_PIPE_CTR = 0x080, DPC_CLR_CMD_CTR = 0x100, DPC_CLR_CLOCK_CTR = 0x200 }; enum dpc_registers { DPC_START_REG, DPC_END_REG, DPC_CURRENT_REG, DPC_STATUS_REG, DPC_CLOCK_REG, DPC_BUFBUSY_REG, DPC_PIPEBUSY_REG, DPC_TMEM_REG, DPC_REGS_COUNT }; enum dps_registers { DPS_TBIST_REG, DPS_TEST_MODE_REG, DPS_BUFTEST_ADDR_REG, DPS_BUFTEST_DATA_REG, DPS_REGS_COUNT }; enum { DELAY_DP_INT = 0x001, DELAY_UPDATESCREEN = 0x002 }; struct rdp_core { uint32_t dpc_regs[DPC_REGS_COUNT]; uint32_t dps_regs[DPS_REGS_COUNT]; unsigned char do_on_unfreeze; struct fb fb; struct rsp_core* sp; struct mi_controller* mi; }; static osal_inline uint32_t dpc_reg(uint32_t address) { return (address & 0xffff) >> 2; } static osal_inline uint32_t dps_reg(uint32_t address) { return (address & 0xffff) >> 2; } void init_rdp(struct rdp_core* dp, struct rsp_core* sp, struct mi_controller* mi, struct memory* mem, struct rdram* rdram, struct r4300_core* r4300); void poweron_rdp(struct rdp_core* dp); void read_dpc_regs(void* opaque, uint32_t address, uint32_t* value); void write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void read_dps_regs(void* opaque, uint32_t address, uint32_t* value); void write_dps_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void rdp_interrupt_event(void* opaque); #endif mupen64plus-core-src-2.6.0/src/device/rcp/ri/000077500000000000000000000000001464506436200206725ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rcp/ri/ri_controller.c000066400000000000000000000043131464506436200237140ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - ri_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "ri_controller.h" #include #include "device/memory/memory.h" void init_ri(struct ri_controller* ri, struct rdram* rdram) { ri->rdram = rdram; } void poweron_ri(struct ri_controller* ri) { memset(ri->regs, 0, RI_REGS_COUNT*sizeof(uint32_t)); } void read_ri_regs(void* opaque, uint32_t address, uint32_t* value) { struct ri_controller* ri = (struct ri_controller*)opaque; uint32_t reg = ri_reg(address); *value = ri->regs[reg]; } void write_ri_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct ri_controller* ri = (struct ri_controller*)opaque; uint32_t reg = ri_reg(address); masked_write(&ri->regs[reg], value, mask); } mupen64plus-core-src-2.6.0/src/device/rcp/ri/ri_controller.h000066400000000000000000000052061464506436200237230ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - ri_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_RI_RI_CONTROLLER_H #define M64P_DEVICE_RCP_RI_RI_CONTROLLER_H #include #include #include "osal/preproc.h" struct rdram; enum ri_registers { RI_MODE_REG, RI_CONFIG_REG, RI_CURRENT_LOAD_REG, RI_SELECT_REG, RI_REFRESH_REG, RI_LATENCY_REG, RI_ERROR_REG, RI_WERROR_REG, RI_REGS_COUNT }; struct ri_controller { uint32_t regs[RI_REGS_COUNT]; struct rdram* rdram; }; static osal_inline uint32_t ri_reg(uint32_t address) { return (address & 0xffff) >> 2; } static osal_inline uint16_t ri_address_to_id_field(uint32_t address) { /* XXX: pure guessing, need harware test */ return (uint16_t)(((address >> 20) == 0x03f) ? (address & 0x0007fc00) >> 10 /* RDRAM registers id_field: [19..10] */ : (address & 0x00f00000) >> 20); /* RDRAM memory id_field: [23..20] */ } void init_ri(struct ri_controller* ri, struct rdram* rdram); void poweron_ri(struct ri_controller* ri); void read_ri_regs(void* opaque, uint32_t address, uint32_t* value); void write_ri_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); #endif mupen64plus-core-src-2.6.0/src/device/rcp/rsp/000077500000000000000000000000001464506436200210645ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rcp/rsp/rsp_core.c000066400000000000000000000317011464506436200230460ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rsp_core.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "rsp_core.h" #include #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/rdp/rdp_core.h" #include "device/rcp/ri/ri_controller.h" #include "device/rdram/rdram.h" #include "main/main.h" #if defined(PROFILE) #include "main/profile.h" #endif #include "plugin/plugin.h" #include "api/callbacks.h" static void do_sp_dma(struct rsp_core* sp, const struct sp_dma* dma) { unsigned int i,j; unsigned int l = dma->length; unsigned int length = ((l & 0xfff) | 7) + 1; unsigned int count = ((l >> 12) & 0xff) + 1; unsigned int skip = ((l >> 20) & 0xfff); unsigned int memaddr = dma->memaddr & 0xff8; unsigned int dramaddr = dma->dramaddr & 0xfffff8; unsigned char *spmem = (unsigned char*)sp->mem + (dma->memaddr & 0x1000); unsigned char *dram = (unsigned char*)sp->ri->rdram->dram; if (dma->dir == SP_DMA_READ) { for(j=0; jdp->fb, dramaddr - length, length); dramaddr+=skip; } sp->regs[SP_MEM_ADDR_REG] = memaddr & 0xfff; sp->regs[SP_DRAM_ADDR_REG] = dramaddr & 0xffffff; sp->regs[SP_RD_LEN_REG] = 0xff8; } else { for(j=0; jdp->fb, dramaddr); for(i=0; iregs[SP_MEM_ADDR_REG] = memaddr & 0xfff; sp->regs[SP_DRAM_ADDR_REG] = dramaddr & 0xffffff; sp->regs[SP_RD_LEN_REG] = 0xff8; } /* schedule end of dma event */ cp0_update_count(sp->mi->r4300); add_interrupt_event(&sp->mi->r4300->cp0, RSP_DMA_EVT, (count * length) / 8); } static void fifo_push(struct rsp_core* sp, uint32_t dir) { if (sp->regs[SP_DMA_FULL_REG]) { DebugMessage(M64MSG_WARNING, "RSP DMA attempted but FIFO queue already full."); return; } if (sp->regs[SP_DMA_BUSY_REG]) { sp->fifo[1].dir = dir; sp->fifo[1].length = dir == SP_DMA_READ ? sp->regs[SP_WR_LEN_REG] : sp->regs[SP_RD_LEN_REG]; sp->fifo[1].memaddr = sp->regs[SP_MEM_ADDR_REG]; sp->fifo[1].dramaddr = sp->regs[SP_DRAM_ADDR_REG]; sp->regs[SP_DMA_FULL_REG] = 1; sp->regs[SP_STATUS_REG] |= SP_STATUS_DMA_FULL; } else { sp->fifo[0].dir = dir; sp->fifo[0].length = dir == SP_DMA_READ ? sp->regs[SP_WR_LEN_REG] : sp->regs[SP_RD_LEN_REG]; sp->fifo[0].memaddr = sp->regs[SP_MEM_ADDR_REG]; sp->fifo[0].dramaddr = sp->regs[SP_DRAM_ADDR_REG]; sp->regs[SP_DMA_BUSY_REG] = 1; sp->regs[SP_STATUS_REG] |= SP_STATUS_DMA_BUSY; do_sp_dma(sp, &sp->fifo[0]); } } static void fifo_pop(struct rsp_core* sp) { if (sp->regs[SP_DMA_FULL_REG]) { sp->fifo[0].dir = sp->fifo[1].dir; sp->fifo[0].length = sp->fifo[1].length; sp->fifo[0].memaddr = sp->fifo[1].memaddr; sp->fifo[0].dramaddr = sp->fifo[1].dramaddr; sp->regs[SP_DMA_FULL_REG] = 0; sp->regs[SP_STATUS_REG] &= ~SP_STATUS_DMA_FULL; do_sp_dma(sp, &sp->fifo[0]); } else { sp->regs[SP_DMA_BUSY_REG] = 0; sp->regs[SP_STATUS_REG] &= ~SP_STATUS_DMA_BUSY; } } static void update_sp_status(struct rsp_core* sp, uint32_t w) { /* clear / set halt */ if ((w & 0x3) == 0x1) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT; if ((w & 0x3) == 0x2) sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT; /* clear broke */ if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE; /* clear SP interrupt */ if ((w & 0x18) == 0x8) { clear_rcp_interrupt(sp->mi, MI_INTR_SP); } /* set SP interrupt */ if ((w & 0x18) == 0x10) { signal_rcp_interrupt(sp->mi, MI_INTR_SP); } /* clear / set single step */ if ((w & 0x60) == 0x20) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP; if ((w & 0x60) == 0x40) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP; /* clear / set interrupt on break */ if ((w & 0x180) == 0x80) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK; if ((w & 0x180) == 0x100) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK; /* clear / set signal 0 */ if ((w & 0x600) == 0x200) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0; if ((w & 0x600) == 0x400) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0; /* clear / set signal 1 */ if ((w & 0x1800) == 0x800) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1; if ((w & 0x1800) == 0x1000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1; /* clear / set signal 2 */ if ((w & 0x6000) == 0x2000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2; if ((w & 0x6000) == 0x4000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2; /* clear / set signal 3 */ if ((w & 0x18000) == 0x8000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3; if ((w & 0x18000) == 0x10000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3; /* clear / set signal 4 */ if ((w & 0x60000) == 0x20000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4; if ((w & 0x60000) == 0x40000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4; /* clear / set signal 5 */ if ((w & 0x180000) == 0x80000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5; if ((w & 0x180000) == 0x100000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5; /* clear / set signal 6 */ if ((w & 0x600000) == 0x200000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6; if ((w & 0x600000) == 0x400000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6; /* clear / set signal 7 */ if ((w & 0x1800000) == 0x800000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7; if ((w & 0x1800000) == 0x1000000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7; if (sp->rsp_task_locked && (get_event(&sp->mi->r4300->cp0.q, SP_INT))) return; if (!((w & 0x3) == 1) && !(w & 0x4) && !sp->rsp_task_locked) return; if (!(sp->regs[SP_STATUS_REG] & SP_STATUS_HALT)) do_SP_Task(sp); } void init_rsp(struct rsp_core* sp, uint32_t* sp_mem, struct mi_controller* mi, struct rdp_core* dp, struct ri_controller* ri) { sp->mem = sp_mem; sp->mi = mi; sp->dp = dp; sp->ri = ri; } void poweron_rsp(struct rsp_core* sp) { memset(sp->mem, 0, SP_MEM_SIZE); memset(sp->regs, 0, SP_REGS_COUNT*sizeof(uint32_t)); memset(sp->regs2, 0, SP_REGS2_COUNT*sizeof(uint32_t)); memset(sp->fifo, 0, SP_DMA_FIFO_SIZE*sizeof(struct sp_dma)); sp->rsp_task_locked = 0; sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP; sp->regs[SP_STATUS_REG] = 1; sp->regs[SP_RD_LEN_REG] = 0xff8; sp->regs[SP_WR_LEN_REG] = 0xff8; } void read_rsp_mem(void* opaque, uint32_t address, uint32_t* value) { struct rsp_core* sp = (struct rsp_core*)opaque; uint32_t addr = rsp_mem_address(address); *value = sp->mem[addr]; } void write_rsp_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rsp_core* sp = (struct rsp_core*)opaque; uint32_t addr = rsp_mem_address(address); masked_write(&sp->mem[addr], value, mask); } void read_rsp_regs(void* opaque, uint32_t address, uint32_t* value) { struct rsp_core* sp = (struct rsp_core*)opaque; uint32_t reg = rsp_reg(address); *value = sp->regs[reg]; if (reg == SP_SEMAPHORE_REG) { sp->regs[SP_SEMAPHORE_REG] = 1; } } void write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rsp_core* sp = (struct rsp_core*)opaque; uint32_t reg = rsp_reg(address); switch(reg) { case SP_STATUS_REG: update_sp_status(sp, value & mask); case SP_DMA_FULL_REG: case SP_DMA_BUSY_REG: return; } masked_write(&sp->regs[reg], value, mask); switch(reg) { case SP_RD_LEN_REG: fifo_push(sp, SP_DMA_WRITE); break; case SP_WR_LEN_REG: fifo_push(sp, SP_DMA_READ); break; case SP_SEMAPHORE_REG: sp->regs[SP_SEMAPHORE_REG] = 0; break; } } void read_rsp_regs2(void* opaque, uint32_t address, uint32_t* value) { struct rsp_core* sp = (struct rsp_core*)opaque; uint32_t reg = rsp_reg2(address); *value = sp->regs2[reg]; if (reg == SP_PC_REG) *value &= 0xffc; } void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rsp_core* sp = (struct rsp_core*)opaque; uint32_t reg = rsp_reg2(address); if (reg == SP_PC_REG) mask &= 0xffc; masked_write(&sp->regs2[reg], value, mask); } void do_SP_Task(struct rsp_core* sp) { uint32_t save_pc = sp->regs2[SP_PC_REG] & ~0xfff; uint32_t sp_delay_time; if (sp->mem[0xfc0/4] == 1) { unprotect_framebuffers(&sp->dp->fb); //gfx.processDList(); sp->regs2[SP_PC_REG] &= 0xfff; #if defined(PROFILE) timed_section_start(TIMED_SECTION_GFX); #endif rsp.doRspCycles(0xffffffff); #if defined(PROFILE) timed_section_end(TIMED_SECTION_GFX); #endif sp->regs2[SP_PC_REG] |= save_pc; new_frame(); if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP) { sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP; if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) { sp->dp->do_on_unfreeze |= DELAY_DP_INT; } else { cp0_update_count(sp->mi->r4300); add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, 4000); } } sp_delay_time = 1000; protect_framebuffers(&sp->dp->fb); } else if (sp->mem[0xfc0/4] == 2) { //audio.processAList(); sp->regs2[SP_PC_REG] &= 0xfff; #if defined(PROFILE) timed_section_start(TIMED_SECTION_AUDIO); #endif rsp.doRspCycles(0xffffffff); #if defined(PROFILE) timed_section_end(TIMED_SECTION_AUDIO); #endif sp->regs2[SP_PC_REG] |= save_pc; sp_delay_time = 4000; } else { sp->regs2[SP_PC_REG] &= 0xfff; rsp.doRspCycles(0xffffffff); sp->regs2[SP_PC_REG] |= save_pc; sp_delay_time = 0; } sp->rsp_task_locked = 0; sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP; if ((sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE)) == 0) { sp->rsp_task_locked = 1; sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP; sp->mi->regs[MI_INTR_REG] |= MI_INTR_SP; } if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP) { cp0_update_count(sp->mi->r4300); add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, sp_delay_time); sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_SP; } sp->regs[SP_STATUS_REG] &= ~(SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT); } void rsp_interrupt_event(void* opaque) { struct rsp_core* sp = (struct rsp_core*)opaque; if (!sp->rsp_task_locked) { sp->regs[SP_STATUS_REG] |= SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT; } if ((sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK) != 0) { raise_rcp_interrupt(sp->mi, MI_INTR_SP); } } void rsp_end_of_dma_event(void* opaque) { struct rsp_core* sp = (struct rsp_core*)opaque; fifo_pop(sp); } mupen64plus-core-src-2.6.0/src/device/rcp/rsp/rsp_core.h000066400000000000000000000102731464506436200230540ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rsp_core.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_RSP_RSP_CORE_H #define M64P_DEVICE_RCP_RSP_RSP_CORE_H #include #include "osal/preproc.h" struct mi_controller; struct rdp_core; struct ri_controller; enum { SP_MEM_SIZE = 0x2000 }; enum { /* SP_STATUS - read */ SP_STATUS_HALT = 0x0001, SP_STATUS_BROKE = 0x0002, SP_STATUS_DMA_BUSY = 0x0004, SP_STATUS_DMA_FULL = 0x0008, SP_STATUS_IO_FULL = 0x0010, SP_STATUS_SSTEP = 0x0020, SP_STATUS_INTR_BREAK = 0x0040, SP_STATUS_SIG0 = 0x0080, SP_STATUS_YIELD = 0x0080, SP_STATUS_SIG1 = 0x0100, SP_STATUS_YIELDED = 0x0100, SP_STATUS_SIG2 = 0x0200, SP_STATUS_TASKDONE = 0x0200, SP_STATUS_SIG3 = 0x0400, SP_STATUS_SIG4 = 0x0800, SP_STATUS_SIG5 = 0x1000, SP_STATUS_SIG6 = 0x2000, SP_STATUS_SIG7 = 0x4000, }; enum sp_registers { SP_MEM_ADDR_REG, SP_DRAM_ADDR_REG, SP_RD_LEN_REG, SP_WR_LEN_REG, SP_STATUS_REG, SP_DMA_FULL_REG, SP_DMA_BUSY_REG, SP_SEMAPHORE_REG, SP_REGS_COUNT }; enum sp_registers2 { SP_PC_REG, SP_IBIST_REG, SP_REGS2_COUNT }; enum sp_dma_dir { SP_DMA_READ, SP_DMA_WRITE }; enum { SP_DMA_FIFO_SIZE = 2} ; struct sp_dma { uint32_t dir; uint32_t length; uint32_t memaddr; uint32_t dramaddr; }; struct rsp_core { uint32_t* mem; uint32_t regs[SP_REGS_COUNT]; uint32_t regs2[SP_REGS2_COUNT]; uint32_t rsp_task_locked; struct mi_controller* mi; struct rdp_core* dp; struct ri_controller* ri; struct sp_dma fifo[SP_DMA_FIFO_SIZE]; }; static osal_inline uint32_t rsp_mem_address(uint32_t address) { return (address & 0x1fff) >> 2; } static osal_inline uint32_t rsp_reg(uint32_t address) { return (address & 0xffff) >> 2; } static osal_inline uint32_t rsp_reg2(uint32_t address) { return (address & 0xffff) >> 2; } void init_rsp(struct rsp_core* sp, uint32_t* sp_mem, struct mi_controller* mi, struct rdp_core* dp, struct ri_controller* ri); void poweron_rsp(struct rsp_core* sp); void read_rsp_mem(void* opaque, uint32_t address, uint32_t* value); void write_rsp_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void read_rsp_regs(void* opaque, uint32_t address, uint32_t* value); void write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void read_rsp_regs2(void* opaque, uint32_t address, uint32_t* value); void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void do_SP_Task(struct rsp_core* sp); void rsp_interrupt_event(void* opaque); void rsp_end_of_dma_event(void* opaque); #endif mupen64plus-core-src-2.6.0/src/device/rcp/si/000077500000000000000000000000001464506436200206735ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rcp/si/si_controller.c000066400000000000000000000131111464506436200237120ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - si_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "si_controller.h" #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/memory/memory.h" #include "device/pif/pif.h" #include "device/r4300/r4300_core.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/ri/ri_controller.h" #include "device/rdram/rdram.h" #include "osal/preproc.h" static int validate_dma(struct si_controller* si, uint32_t reg) { if ((si->regs[reg] & 0x1fffffff) != 0x1fc007c0) { DebugMessage(M64MSG_ERROR, "Unknown SI DMA PIF address: %08x", si->regs[reg]); return 0; } /* if DMA already busy, error, and ignore request */ if (si->regs[SI_STATUS_REG] & SI_STATUS_DMA_BUSY) { si->regs[SI_STATUS_REG] |= SI_STATUS_DMA_ERROR; return 0; } return 1; } static void copy_pif_rdram(struct si_controller* si) { size_t i; /* DRAM address must be word-aligned */ uint32_t dram_addr = si->regs[SI_DRAM_ADDR_REG] & ~UINT32_C(3); uint32_t* pif_ram = (uint32_t*)si->pif->ram; uint32_t* dram = (uint32_t*)(&si->ri->rdram->dram[rdram_dram_address(dram_addr)]); if (si->dma_dir == SI_DMA_WRITE) { for(i = 0; i < (PIF_RAM_SIZE / 4); ++i) { pif_ram[i] = fromhl(dram[i]); } } else if (si->dma_dir == SI_DMA_READ) { for(i = 0; i < (PIF_RAM_SIZE / 4); ++i) { dram[i] = tohl(pif_ram[i]); } } } static void dma_si_write(struct si_controller* si) { if (!validate_dma(si, SI_PIF_ADDR_WR64B_REG)) return; si->dma_dir = SI_DMA_WRITE; copy_pif_rdram(si); cp0_update_count(si->mi->r4300); si->regs[SI_STATUS_REG] |= SI_STATUS_DMA_BUSY; add_interrupt_event(&si->mi->r4300->cp0, SI_INT, si->dma_duration + add_random_interrupt_time(si->mi->r4300)); } static void dma_si_read(struct si_controller* si) { if (!validate_dma(si, SI_PIF_ADDR_RD64B_REG)) return; si->dma_dir = SI_DMA_READ; update_pif_ram(si->pif); cp0_update_count(si->mi->r4300); si->regs[SI_STATUS_REG] |= SI_STATUS_DMA_BUSY; add_interrupt_event(&si->mi->r4300->cp0, SI_INT, si->dma_duration + add_random_interrupt_time(si->mi->r4300)); } void init_si(struct si_controller* si, unsigned int dma_duration, struct mi_controller* mi, struct pif* pif, struct ri_controller* ri) { si->dma_duration = dma_duration; si->mi = mi; si->pif = pif; si->ri = ri; } void poweron_si(struct si_controller* si) { memset(si->regs, 0, SI_REGS_COUNT*sizeof(uint32_t)); si->dma_dir = SI_NO_DMA; } void read_si_regs(void* opaque, uint32_t address, uint32_t* value) { struct si_controller* si = (struct si_controller*)opaque; uint32_t reg = si_reg(address); *value = si->regs[reg]; } void write_si_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct si_controller* si = (struct si_controller*)opaque; uint32_t reg = si_reg(address); switch (reg) { case SI_DRAM_ADDR_REG: masked_write(&si->regs[SI_DRAM_ADDR_REG], value, mask); break; case SI_PIF_ADDR_RD64B_REG: masked_write(&si->regs[SI_PIF_ADDR_RD64B_REG], value, mask); dma_si_read(si); break; case SI_PIF_ADDR_WR64B_REG: masked_write(&si->regs[SI_PIF_ADDR_WR64B_REG], value, mask); dma_si_write(si); break; case SI_STATUS_REG: /* clear si interrupt */ si->regs[SI_STATUS_REG] &= ~SI_STATUS_INTERRUPT; clear_rcp_interrupt(si->mi, MI_INTR_SI); break; } } void si_end_of_dma_event(void* opaque) { struct si_controller* si = (struct si_controller*)opaque; /* DRAM -> PIF : start the PIF processing */ if (si->dma_dir == SI_DMA_WRITE) process_pif_ram(si->pif); /* PIF -> DRAM : copy to RDRAM */ else if (si->dma_dir == SI_DMA_READ) copy_pif_rdram(si); /* end DMA */ si->dma_dir = SI_NO_DMA; si->regs[SI_STATUS_REG] &= ~(SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY); /* raise si interrupt */ si->regs[SI_STATUS_REG] |= SI_STATUS_INTERRUPT; raise_rcp_interrupt(si->mi, MI_INTR_SI); } mupen64plus-core-src-2.6.0/src/device/rcp/si/si_controller.h000066400000000000000000000055701464506436200237310ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - si_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_SI_SI_CONTROLLER_H #define M64P_DEVICE_RCP_SI_SI_CONTROLLER_H #include #include "osal/preproc.h" struct mi_controller; struct ri_controller; struct pif; enum si_dma_dir { SI_NO_DMA, SI_DMA_READ, SI_DMA_WRITE }; enum si_registers { SI_DRAM_ADDR_REG, SI_PIF_ADDR_RD64B_REG, SI_R2_REG, /* reserved */ SI_R3_REG, /* reserved */ SI_PIF_ADDR_WR64B_REG, SI_R5_REG, /* reserved */ SI_STATUS_REG, SI_REGS_COUNT }; enum { /* SI_STATUS - read */ SI_STATUS_DMA_BUSY = 0x0001, SI_STATUS_IO_BUSY = 0x0002, SI_STATUS_DMA_ERROR = 0x0008, SI_STATUS_INTERRUPT = 0x1000, }; struct si_controller { uint32_t regs[SI_REGS_COUNT]; unsigned char dma_dir; unsigned int dma_duration; struct mi_controller* mi; struct pif* pif; struct ri_controller* ri; }; static osal_inline uint32_t si_reg(uint32_t address) { return (address & 0xffff) >> 2; } void init_si(struct si_controller* si, unsigned int dma_duration, struct mi_controller* mi, struct pif* pif, struct ri_controller* ri); void poweron_si(struct si_controller* si); void read_si_regs(void* opaque, uint32_t address, uint32_t* value); void write_si_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void si_end_of_dma_event(void* opaque); #endif mupen64plus-core-src-2.6.0/src/device/rcp/vi/000077500000000000000000000000001464506436200206765ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rcp/vi/vi_controller.c000066400000000000000000000136031464506436200237260ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - vi_controller.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "vi_controller.h" #include #include "api/m64p_types.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rcp/mi/mi_controller.h" #include "main/main.h" #include "plugin/plugin.h" unsigned int vi_clock_from_tv_standard(m64p_system_type tv_standard) { switch(tv_standard) { case SYSTEM_PAL: return 49656530; case SYSTEM_MPAL: return 48628316; case SYSTEM_NTSC: default: return 48681812; } } unsigned int vi_expected_refresh_rate_from_tv_standard(m64p_system_type tv_standard) { switch (tv_standard) { case SYSTEM_PAL: return 50; case SYSTEM_NTSC: case SYSTEM_MPAL: default: return 60; } } void set_vi_vertical_interrupt(struct vi_controller* vi) { if (!get_event(&vi->mi->r4300->cp0.q, VI_INT) && (vi->regs[VI_V_INTR_REG] < vi->regs[VI_V_SYNC_REG])) { cp0_update_count(vi->mi->r4300); add_interrupt_event(&vi->mi->r4300->cp0, VI_INT, vi->delay); } } void init_vi(struct vi_controller* vi, unsigned int clock, unsigned int expected_refresh_rate, struct mi_controller* mi, struct rdp_core* dp) { vi->clock = clock; vi->expected_refresh_rate = expected_refresh_rate; vi->mi = mi; vi->dp = dp; } void poweron_vi(struct vi_controller* vi) { memset(vi->regs, 0, VI_REGS_COUNT*sizeof(uint32_t)); vi->field = 0; vi->delay = 0; vi->count_per_scanline = 0; } void read_vi_regs(void* opaque, uint32_t address, uint32_t* value) { struct vi_controller* vi = (struct vi_controller*)opaque; uint32_t reg = vi_reg(address); const uint32_t* cp0_regs = r4300_cp0_regs(&vi->mi->r4300->cp0); if (reg == VI_CURRENT_REG) { uint32_t* next_vi = get_event(&vi->mi->r4300->cp0.q, VI_INT); if (next_vi != NULL) { cp0_update_count(vi->mi->r4300); vi->regs[VI_CURRENT_REG] = (vi->delay - (*next_vi - cp0_regs[CP0_COUNT_REG])) / vi->count_per_scanline; /* wrap around VI_CURRENT_REG if needed */ if (vi->regs[VI_CURRENT_REG] >= vi->regs[VI_V_SYNC_REG]) vi->regs[VI_CURRENT_REG] -= vi->regs[VI_V_SYNC_REG]; } /* update current field */ vi->regs[VI_CURRENT_REG] = (vi->regs[VI_CURRENT_REG] & (~1)) | vi->field; } *value = vi->regs[reg]; } void write_vi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct vi_controller* vi = (struct vi_controller*)opaque; uint32_t reg = vi_reg(address); switch(reg) { case VI_STATUS_REG: if ((vi->regs[VI_STATUS_REG] & mask) != (value & mask)) { masked_write(&vi->regs[VI_STATUS_REG], value, mask); gfx.viStatusChanged(); } return; case VI_WIDTH_REG: if ((vi->regs[VI_WIDTH_REG] & mask) != (value & mask)) { masked_write(&vi->regs[VI_WIDTH_REG], value, mask); gfx.viWidthChanged(); } return; case VI_CURRENT_REG: clear_rcp_interrupt(vi->mi, MI_INTR_VI); return; case VI_V_SYNC_REG: if ((vi->regs[VI_V_SYNC_REG] & mask) != (value & mask)) { masked_write(&vi->regs[VI_V_SYNC_REG], value, mask); vi->count_per_scanline = (vi->clock / vi->expected_refresh_rate) / (vi->regs[VI_V_SYNC_REG] + 1); vi->delay = (vi->regs[VI_V_SYNC_REG] + 1) * vi->count_per_scanline; set_vi_vertical_interrupt(vi); } return; case VI_V_INTR_REG: masked_write(&vi->regs[VI_V_INTR_REG], value, mask); set_vi_vertical_interrupt(vi); return; } masked_write(&vi->regs[reg], value, mask); } void vi_vertical_interrupt_event(void* opaque) { struct vi_controller* vi = (struct vi_controller*)opaque; if (vi->dp->do_on_unfreeze & DELAY_DP_INT) vi->dp->do_on_unfreeze |= DELAY_UPDATESCREEN; else gfx.updateScreen(); /* allow main module to do things on VI event */ new_vi(); /* toggle vi field if in interlaced mode */ vi->field ^= (vi->regs[VI_STATUS_REG] >> 6) & 0x1; /* schedule next vertical interrupt */ uint32_t next_vi = *get_event(&vi->mi->r4300->cp0.q, VI_INT) + vi->delay; remove_interrupt_event(&vi->mi->r4300->cp0); add_interrupt_event_count(&vi->mi->r4300->cp0, VI_INT, next_vi); /* trigger interrupt */ raise_rcp_interrupt(vi->mi, MI_INTR_VI); } mupen64plus-core-src-2.6.0/src/device/rcp/vi/vi_controller.h000066400000000000000000000057401464506436200237360ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - vi_controller.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_VI_VI_CONTROLLER_H #define M64P_DEVICE_RCP_VI_VI_CONTROLLER_H #include #include "api/m64p_types.h" #include "osal/preproc.h" struct mi_controller; struct rdp_core; enum vi_registers { VI_STATUS_REG, VI_ORIGIN_REG, VI_WIDTH_REG, VI_V_INTR_REG, VI_CURRENT_REG, VI_BURST_REG, VI_V_SYNC_REG, VI_H_SYNC_REG, VI_LEAP_REG, VI_H_START_REG, VI_V_START_REG, VI_V_BURST_REG, VI_X_SCALE_REG, VI_Y_SCALE_REG, VI_REGS_COUNT }; struct vi_controller { uint32_t regs[VI_REGS_COUNT]; unsigned int field; unsigned int delay; unsigned int clock; unsigned int expected_refresh_rate; unsigned int count_per_scanline; struct mi_controller* mi; struct rdp_core* dp; }; static osal_inline uint32_t vi_reg(uint32_t address) { return (address & 0xffff) >> 2; } unsigned int vi_clock_from_tv_standard(m64p_system_type tv_standard); unsigned int vi_expected_refresh_rate_from_tv_standard(m64p_system_type tv_standard); void set_vi_vertical_interrupt(struct vi_controller* vi); void init_vi(struct vi_controller* vi, unsigned int clock, unsigned int expected_refresh_rate, struct mi_controller* mi, struct rdp_core* dp); void poweron_vi(struct vi_controller* vi); void read_vi_regs(void* opaque, uint32_t address, uint32_t* value); void write_vi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void vi_vertical_interrupt_event(void* opaque); #endif mupen64plus-core-src-2.6.0/src/device/rdram/000077500000000000000000000000001464506436200206015ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/device/rdram/rdram.c000066400000000000000000000205711464506436200220570ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rdram.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "rdram.h" #include "api/m64p_types.h" #include "api/callbacks.h" #include "device/device.h" #include "device/memory/memory.h" #include "device/r4300/r4300_core.h" #include "device/rcp/ri/ri_controller.h" #include #define RDRAM_BCAST_ADDRESS_MASK UINT32_C(0x00080000) /* XXX: deduce # of RDRAM modules from it's total size * Assume only 2Mo RDRAM modules. * Proper way of doing it would be to declare in init_rdram * what kind of modules we insert and deduce dram_size from * that configuration. */ static size_t get_modules_count(const struct rdram* rdram) { return (rdram->dram_size) / 0x200000; } static uint8_t cc_value(uint32_t mode_reg) { return ((mode_reg & 0x00000040) >> 6) | ((mode_reg & 0x00004000) >> 13) | ((mode_reg & 0x00400000) >> 20) | ((mode_reg & 0x00000080) >> 4) | ((mode_reg & 0x00008000) >> 11) | ((mode_reg & 0x00800000) >> 18); } static osal_inline uint16_t idfield_value(uint32_t device_id) { return ((((device_id >> 26) & 0x3f) << 0) | (((device_id >> 23) & 0x01) << 6) | (((device_id >> 16) & 0xff) << 7) | (((device_id >> 7) & 0x01) << 15)); } static size_t get_module(const struct rdram* rdram, uint32_t address) { size_t module; size_t modules = get_modules_count(rdram); uint16_t id_field = ri_address_to_id_field(address); for (module = 0; module < modules; ++module) { if (id_field == idfield_value(rdram->regs[module][RDRAM_DEVICE_ID_REG])) { return module; } } /* can happen during memory detection because * it probes potentialy non present RDRAM */ return RDRAM_MAX_MODULES_COUNT; } static void read_rdram_dram_corrupted(void* opaque, uint32_t address, uint32_t* value) { struct rdram* rdram = (struct rdram*)opaque; uint32_t addr = rdram_dram_address(address); size_t module; *value = rdram->dram[addr]; module = get_module(rdram, address); if (module == RDRAM_MAX_MODULES_COUNT) { *value = 0; return; } /* corrupt read value if CC value is not calibrated */ uint32_t mode = rdram->regs[module][RDRAM_MODE_REG] ^ UINT32_C(0xc0c0c0c0); if ((mode & 0x80000000) && (cc_value(mode) == 0)) { *value = 0; } } static void map_corrupt_rdram(struct rdram* rdram, int corrupt) { struct mem_mapping mapping; mapping.begin = MM_RDRAM_DRAM; mapping.end = MM_RDRAM_DRAM + rdram->dram_size - 1; mapping.type = M64P_MEM_RDRAM; mapping.handler.opaque = rdram; mapping.handler.read32 = (corrupt) ? read_rdram_dram_corrupted : read_rdram_dram; mapping.handler.write32 = write_rdram_dram; apply_mem_mapping(rdram->r4300->mem, &mapping); #ifndef NEW_DYNAREC rdram->r4300->recomp.fast_memory = (corrupt) ? 0 : 1; invalidate_r4300_cached_code(rdram->r4300, 0, 0); #endif } void init_rdram(struct rdram* rdram, uint32_t* dram, size_t dram_size, struct r4300_core* r4300) { rdram->dram = dram; rdram->dram_size = dram_size; rdram->r4300 = r4300; } void poweron_rdram(struct rdram* rdram) { size_t module; size_t modules = get_modules_count(rdram); memset(rdram->regs, 0, RDRAM_MAX_MODULES_COUNT*RDRAM_REGS_COUNT*sizeof(uint32_t)); memset(rdram->dram, 0, rdram->dram_size); DebugMessage(M64MSG_INFO, "Initializing %u RDRAM modules for a total of %u MB", (uint32_t) modules, (uint32_t) rdram->dram_size / (1024*1024)); for (module = 0; module < modules; ++module) { rdram->regs[module][RDRAM_CONFIG_REG] = UINT32_C(0xb5190010); rdram->regs[module][RDRAM_DEVICE_ID_REG] = UINT32_C(0x00000000); rdram->regs[module][RDRAM_DELAY_REG] = UINT32_C(0x230b0223); rdram->regs[module][RDRAM_MODE_REG] = UINT32_C(0xc4c0c0c0); rdram->regs[module][RDRAM_REF_ROW_REG] = UINT32_C(0x00000000); rdram->regs[module][RDRAM_MIN_INTERVAL_REG] = UINT32_C(0x0040c0e0); rdram->regs[module][RDRAM_ADDR_SELECT_REG] = UINT32_C(0x00000000); rdram->regs[module][RDRAM_DEVICE_MANUF_REG] = UINT32_C(0x00000500); } } void read_rdram_regs(void* opaque, uint32_t address, uint32_t* value) { struct rdram* rdram = (struct rdram*)opaque; uint32_t reg = rdram_reg(address); size_t module; if (address & RDRAM_BCAST_ADDRESS_MASK) { DebugMessage(M64MSG_WARNING, "Reading from broadcast address is unsupported %08x", address); return; } module = get_module(rdram, address); if (module == RDRAM_MAX_MODULES_COUNT) { *value = 0; return; } *value = rdram->regs[module][reg]; /* some bits are inverted when read */ if (reg == RDRAM_MODE_REG) { *value ^= UINT32_C(0xc0c0c0c0); } } void write_rdram_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rdram* rdram = (struct rdram*)opaque; uint32_t reg = rdram_reg(address); size_t module; size_t modules = get_modules_count(rdram); /* HACK: Detect when current Control calibration is about to start, * so we can set corrupted rdram_dram handler */ if (address & RDRAM_BCAST_ADDRESS_MASK && reg == RDRAM_DELAY_REG) { map_corrupt_rdram(rdram, 1); } /* HACK: Detect when current Control calibration is over, * so we can restore the original rdram_dram handler * and let dynarec have it's fast_memory enabled. */ if (address & RDRAM_BCAST_ADDRESS_MASK && reg == RDRAM_MODE_REG) { map_corrupt_rdram(rdram, 0); /* HACK: In the IPL3 procedure, at this point, * the amount of detected memory can be found in s4 */ size_t ipl3_rdram_size = r4300_regs(rdram->r4300)[20] & UINT32_C(0x0fffffff); if (ipl3_rdram_size != rdram->dram_size) { DebugMessage(M64MSG_WARNING, "IPL3 detected %u MB of RDRAM != %u MB", (uint32_t) ipl3_rdram_size / (1024*1024), (uint32_t) rdram->dram_size / (1024*1024)); } } if (address & RDRAM_BCAST_ADDRESS_MASK) { for (module = 0; module < modules; ++module) { masked_write(&rdram->regs[module][reg], value, mask); } } else { module = get_module(rdram, address); if (module != RDRAM_MAX_MODULES_COUNT) { masked_write(&rdram->regs[module][reg], value, mask); } } } void read_rdram_dram(void* opaque, uint32_t address, uint32_t* value) { struct rdram* rdram = (struct rdram*)opaque; uint32_t addr = rdram_dram_address(address); if (address < rdram->dram_size) { *value = rdram->dram[addr]; } else { *value = 0; } } void write_rdram_dram(void* opaque, uint32_t address, uint32_t value, uint32_t mask) { struct rdram* rdram = (struct rdram*)opaque; uint32_t addr = rdram_dram_address(address); if (address < rdram->dram_size) { masked_write(&rdram->dram[addr], value, mask); } } mupen64plus-core-src-2.6.0/src/device/rdram/rdram.h000066400000000000000000000056331464506436200220660ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rdram.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_DEVICE_RCP_RI_RDRAM_H #define M64P_DEVICE_RCP_RI_RDRAM_H #include #include #include "osal/preproc.h" struct r4300_core; enum rdram_registers { RDRAM_CONFIG_REG, RDRAM_DEVICE_ID_REG, RDRAM_DELAY_REG, RDRAM_MODE_REG, RDRAM_REF_INTERVAL_REG, RDRAM_REF_ROW_REG, RDRAM_RAS_INTERVAL_REG, RDRAM_MIN_INTERVAL_REG, RDRAM_ADDR_SELECT_REG, RDRAM_DEVICE_MANUF_REG, RDRAM_REGS_COUNT }; /* IPL3 rdram initialization accepts up to 8 RDRAM modules */ enum { RDRAM_MAX_MODULES_COUNT = 8 }; struct rdram { uint32_t regs[RDRAM_MAX_MODULES_COUNT][RDRAM_REGS_COUNT]; uint32_t* dram; size_t dram_size; struct r4300_core* r4300; }; static osal_inline uint32_t rdram_reg(uint32_t address) { return (address & 0x3ff) >> 2; } static osal_inline uint32_t rdram_dram_address(uint32_t address) { return (address & 0xffffff) >> 2; } void init_rdram(struct rdram* rdram, uint32_t* dram, size_t dram_size, struct r4300_core* r4300); void poweron_rdram(struct rdram* rdram); void read_rdram_regs(void* opaque, uint32_t address, uint32_t* value); void write_rdram_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); void read_rdram_dram(void* opaque, uint32_t address, uint32_t* value); void write_rdram_dram(void* opaque, uint32_t address, uint32_t value, uint32_t mask); #endif mupen64plus-core-src-2.6.0/src/main/000077500000000000000000000000001464506436200171615ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/main/cheat.c000066400000000000000000000411611464506436200204140ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cheat.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * Copyright (C) 2008 Okaygo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* gameshark and xploder64 reference: http://doc.kodewerx.net/hacking_n64.html */ #include #include #define __STDC_FORMAT_MACROS #include #include #include #include #include #include "cheat.h" #include "eventloop.h" #include "list.h" #include "api/callbacks.h" #include "api/m64p_types.h" #include "device/r4300/r4300_core.h" #include "device/rdram/rdram.h" #include "osal/preproc.h" /* local definitions */ #define CHEAT_CODE_MAGIC_VALUE UINT32_C(0xDEAD0000) typedef struct cheat_code { uint32_t address; uint32_t value; uint32_t old_value; struct list_head list; } cheat_code_t; typedef struct cheat { char *name; int enabled; int was_enabled; struct list_head cheat_codes; struct list_head list; } cheat_t; /* private functions */ static uint16_t read_address_16bit(struct r4300_core* r4300, uint32_t address) { return *(uint16_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16))); } static uint8_t read_address_8bit(struct r4300_core* r4300, uint32_t address) { return *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8))); } static void update_address_16bit(struct r4300_core* r4300, uint32_t address, uint16_t new_value) { *(uint16_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16))) = new_value; /* mask out bit 24 which is used by GS codes to specify 8/16 bits */ address &= 0xfeffffff; invalidate_r4300_cached_code(r4300, address, 2); } static void update_address_8bit(struct r4300_core* r4300, uint32_t address, uint8_t new_value) { *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8))) = new_value; invalidate_r4300_cached_code(r4300, address, 1); } static int address_equal_to_8bit(struct r4300_core* r4300, uint32_t address, uint8_t value) { uint8_t value_read; value_read = *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8))); return value_read == value; } static int address_equal_to_16bit(struct r4300_core* r4300, uint32_t address, uint16_t value) { uint16_t value_read; value_read = *(unsigned short *)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16))); return value_read == value; } /* individual application - returns 0 if we are supposed to skip the next cheat * (only really used on conditional codes) */ static int execute_cheat(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t* old_value) { switch (address & 0xFF000000) { case 0x80000000: case 0x88000000: case 0xA0000000: case 0xA8000000: case 0xF0000000: /* if pointer to old value is valid and uninitialized, write current value to it */ if (old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) { *old_value = read_address_8bit(r4300, address); } update_address_8bit(r4300, address, (uint8_t)value); return 1; case 0x81000000: case 0x89000000: case 0xA1000000: case 0xA9000000: case 0xF1000000: /* if pointer to old value is valid and uninitialized, write current value to it */ if (old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) { *old_value = read_address_16bit(r4300, address); } update_address_16bit(r4300, address, (uint16_t)value); return 1; case 0xD0000000: case 0xD8000000: return address_equal_to_8bit(r4300, address, (uint8_t)value); case 0xD1000000: case 0xD9000000: return address_equal_to_16bit(r4300, address, (uint16_t)value); case 0xD2000000: case 0xDB000000: return !(address_equal_to_8bit(r4300, address, (uint8_t)value)); case 0xD3000000: case 0xDA000000: return !(address_equal_to_16bit(r4300, address, (uint16_t)value)); case 0xEE000000: /* most likely, this doesnt do anything. */ execute_cheat(r4300, 0xF1000318, 0x0040, NULL); execute_cheat(r4300, 0xF100031A, 0x0000, NULL); return 1; default: return 1; } } static cheat_t *find_or_create_cheat(struct cheat_ctx* ctx, const char *name) { cheat_t *cheat; int found = 0; list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) { if (strcmp(cheat->name, name) == 0) { found = 1; break; } } if (found) { /* delete any pre-existing cheat codes */ cheat_code_t *code, *safe; list_for_each_entry_safe_t(code, safe, &cheat->cheat_codes, cheat_code_t, list) { list_del(&code->list); free(code); } cheat->enabled = 0; cheat->was_enabled = 0; } else { cheat = malloc(sizeof(*cheat)); cheat->name = strdup(name); cheat->enabled = 0; cheat->was_enabled = 0; INIT_LIST_HEAD(&cheat->cheat_codes); list_add_tail(&cheat->list, &ctx->active_cheats); } return cheat; } /* public functions */ void cheat_init(struct cheat_ctx* ctx) { ctx->mutex = SDL_CreateMutex(); INIT_LIST_HEAD(&ctx->active_cheats); } void cheat_uninit(struct cheat_ctx* ctx) { if (ctx->mutex != NULL) { SDL_DestroyMutex(ctx->mutex); } ctx->mutex = NULL; } void cheat_apply_cheats(struct cheat_ctx* ctx, struct r4300_core* r4300, int entry) { cheat_t *cheat; cheat_code_t *code; int cond_failed; if (list_empty(&ctx->active_cheats)) return; if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) { DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_apply_cheats()"); return; } list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) { if (cheat->enabled) { cheat->was_enabled = 1; switch(entry) { case ENTRY_BOOT: list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) { /* code should only be written once at boot time */ if ((code->address & 0xF0000000) == 0xF0000000) { execute_cheat(r4300, code->address, code->value, &code->old_value); } } break; case ENTRY_VI: /* a cheat starts without failed preconditions */ cond_failed = 0; list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) { /* conditional cheat codes */ if ((code->address & 0xF0000000) == 0xD0000000) { /* if code needs GS button pressed and it's not, skip it */ if (((code->address & 0xFF000000) == 0xD8000000 || (code->address & 0xFF000000) == 0xD9000000 || (code->address & 0xFF000000) == 0xDA000000 || (code->address & 0xFF000000) == 0xDB000000) && !event_gameshark_active()) { /* if condition false, skip next code non-test code */ cond_failed = 1; } /* if condition false, skip next code non-test code */ if (!execute_cheat(r4300, code->address, code->value, NULL)) { cond_failed = 1; } } else { /* preconditions were false for this non-test code * reset the condition state and skip the cheat */ if (cond_failed) { cond_failed = 0; continue; } switch (code->address & 0xFF000000) { /* GS button triggers cheat code */ case 0x88000000: case 0x89000000: case 0xA8000000: case 0xA9000000: if (event_gameshark_active()) { execute_cheat(r4300, code->address, code->value, NULL); } break; /* normal cheat code */ default: /* exclude boot-time cheat codes */ if ((code->address & 0xF0000000) != 0xF0000000) { execute_cheat(r4300, code->address, code->value, &code->old_value); } break; } } } break; default: break; } } /* if cheat was enabled, but is now disabled, restore old memory values */ else if (cheat->was_enabled) { cheat->was_enabled = 0; switch(entry) { case ENTRY_VI: list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) { /* set memory back to old value and clear saved copy of old value */ if(code->old_value != CHEAT_CODE_MAGIC_VALUE) { execute_cheat(r4300, code->address, code->old_value, NULL); code->old_value = CHEAT_CODE_MAGIC_VALUE; } } break; default: break; } } } SDL_UnlockMutex(ctx->mutex); } void cheat_delete_all(struct cheat_ctx* ctx) { cheat_t *cheat, *safe_cheat; cheat_code_t *code, *safe_code; if (list_empty(&ctx->active_cheats)) return; if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) { DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_delete_all()"); return; } list_for_each_entry_safe_t(cheat, safe_cheat, &ctx->active_cheats, cheat_t, list) { free(cheat->name); list_for_each_entry_safe_t(code, safe_code, &cheat->cheat_codes, cheat_code_t, list) { list_del(&code->list); free(code); } list_del(&cheat->list); free(cheat); } SDL_UnlockMutex(ctx->mutex); } int cheat_set_enabled(struct cheat_ctx* ctx, const char* name, int enabled) { cheat_t *cheat = NULL; if (list_empty(&ctx->active_cheats)) return 0; if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) { DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_set_enabled()"); return 0; } list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) { if (strcmp(name, cheat->name) == 0) { cheat->enabled = enabled; SDL_UnlockMutex(ctx->mutex); return 1; } } SDL_UnlockMutex(ctx->mutex); return 0; } int cheat_add_new(struct cheat_ctx* ctx, const char* name, m64p_cheat_code* code_list, int num_codes) { cheat_t *cheat; int i, j; if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) { DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_add_new()"); return 0; } /* create a new cheat function or erase the codes in an existing cheat function */ cheat = find_or_create_cheat(ctx, name); if (cheat == NULL) { SDL_UnlockMutex(ctx->mutex); return 0; } /* default for new cheats is enabled */ cheat->enabled = 1; for (i = 0; i < num_codes; i++) { /* if this is a 'patch' code, convert it and dump out all of the individual codes */ if ((code_list[i].address & 0xFFFF0000) == 0x50000000 && i < num_codes - 1) { int code_count = ((code_list[i].address & 0xFF00) >> 8); int incr_addr = code_list[i].address & 0xFF; int incr_value = code_list[i].value; int cur_addr = code_list[i+1].address; int cur_value = code_list[i+1].value; i += 1; for (j = 0; j < code_count; j++) { cheat_code_t *code = malloc(sizeof(*code)); code->address = cur_addr; code->value = cur_value; code->old_value = CHEAT_CODE_MAGIC_VALUE; list_add_tail(&code->list, &cheat->cheat_codes); cur_addr += incr_addr; cur_value += incr_value; } } else { /* just a normal code */ cheat_code_t *code = malloc(sizeof(*code)); code->address = code_list[i].address; code->value = code_list[i].value; code->old_value = CHEAT_CODE_MAGIC_VALUE; list_add_tail(&code->list, &cheat->cheat_codes); } } SDL_UnlockMutex(ctx->mutex); return 1; } static char *strtok_compat(char *str, const char *delim, char **saveptr) { char *p; if (str == NULL) str = *saveptr; if (str == NULL) return NULL; str += strspn(str, delim); if ((p = strpbrk(str, delim)) != NULL) { *saveptr = p + 1; *p = '\0'; } else { *saveptr = NULL; } return str; } static int cheat_parse_hacks_code(char *code, m64p_cheat_code **hack) { char *saveptr = NULL; char *input, *token; int num_codes; m64p_cheat_code *hackbuf; int ret; *hack = NULL; /* count number of possible cheatcodes */ input = code; num_codes = 0; while ((strchr(input, ','))) { input++; num_codes++; } num_codes++; /* allocate buffer */ hackbuf = malloc(sizeof(*hackbuf) * num_codes); if (!hackbuf) return 0; /* parse cheatcodes */ input = code; num_codes = 0; while ((token = strtok_compat(input, ",", &saveptr))) { input = NULL; ret = sscanf(token, "%08" SCNx32 " %04X", &hackbuf[num_codes].address, (unsigned int*)&hackbuf[num_codes].value); if (ret == 2) num_codes++; } if (num_codes == 0) free(hackbuf); else *hack = hackbuf; return num_codes; } int cheat_add_hacks(struct cheat_ctx* ctx, const char* rom_cheats) { char *cheat_raw = NULL; char *saveptr = NULL; char *input, *token; unsigned int i = 0; int num_codes; char cheatname[32]; m64p_cheat_code *hack; if (!rom_cheats) return 0; /* copy ini entry for tokenizing */ cheat_raw = strdup(rom_cheats); if (!cheat_raw) goto out; /* split into cheats for the cheat engine */ input = cheat_raw; while ((token = strtok_compat(input, ";", &saveptr))) { input = NULL; snprintf(cheatname, sizeof(cheatname), "HACK%u", i); cheatname[sizeof(cheatname) - 1] = '\0'; /* parse and add cheat */ num_codes = cheat_parse_hacks_code(token, &hack); if (num_codes <= 0) continue; cheat_add_new(ctx, cheatname, hack, num_codes); free(hack); i++; } out: free(cheat_raw); return 0; } mupen64plus-core-src-2.6.0/src/main/cheat.h000066400000000000000000000043751464506436200204270ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - cheat.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Okaygo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_MAIN_CHEAT_H #define M64P_MAIN_CHEAT_H #include "api/m64p_types.h" #include "list.h" #include #define ENTRY_BOOT 0 #define ENTRY_VI 1 struct SDL_mutex; struct r4300_core; struct cheat_ctx { struct SDL_mutex* mutex; struct list_head active_cheats; }; void cheat_apply_cheats(struct cheat_ctx* ctx, struct r4300_core* r4300, int entry); void cheat_init(struct cheat_ctx* ctx); void cheat_uninit(struct cheat_ctx* ctx); int cheat_add_new(struct cheat_ctx* ctx, const char* name, m64p_cheat_code* code_list, int num_codes); int cheat_set_enabled(struct cheat_ctx* ctx, const char* name, int enabled); void cheat_delete_all(struct cheat_ctx* ctx); int cheat_add_hacks(struct cheat_ctx* ctx, const char* rom_cheats); #endif mupen64plus-core-src-2.6.0/src/main/eventloop.c000066400000000000000000000762241464506436200213530ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - eventloop.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008-2009 Richard Goedeken * * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include #include #if ! SDL_VERSION_ATLEAST(1,3,0) #define SDL_SCANCODE_ESCAPE SDLK_ESCAPE #define SDL_NUM_SCANCODES SDLK_LAST #define SDL_SCANCODE_F5 SDLK_F5 #define SDL_SCANCODE_F7 SDLK_F7 #define SDL_SCANCODE_F9 SDLK_F9 #define SDL_SCANCODE_F10 SDLK_F10 #define SDL_SCANCODE_F11 SDLK_F11 #define SDL_SCANCODE_F12 SDLK_F12 #define SDL_SCANCODE_P SDLK_p #define SDL_SCANCODE_M SDLK_m #define SDL_SCANCODE_RIGHTBRACKET SDLK_RIGHTBRACKET #define SDL_SCANCODE_LEFTBRACKET SDLK_LEFTBRACKET #define SDL_SCANCODE_F SDLK_f #define SDL_SCANCODE_Y SDLK_y #define SDL_SCANCODE_SLASH SDLK_SLASH #define SDL_SCANCODE_G SDLK_g #define SDL_SCANCODE_RETURN SDLK_RETURN #define SDL_SCANCODE_0 SDLK_0 #define SDL_SCANCODE_1 SDLK_1 #define SDL_SCANCODE_2 SDLK_2 #define SDL_SCANCODE_3 SDLK_3 #define SDL_SCANCODE_4 SDLK_4 #define SDL_SCANCODE_5 SDLK_5 #define SDL_SCANCODE_6 SDLK_6 #define SDL_SCANCODE_7 SDLK_7 #define SDL_SCANCODE_8 SDLK_8 #define SDL_SCANCODE_9 SDLK_9 #define SDL_SCANCODE_UNKNOWN SDLK_UNKNOWN #define SDL_SetEventFilter(func, data) SDL_SetEventFilter(func) #define event_sdl_filter(userdata, event) event_sdl_filter(const event) #else SDL_JoystickID l_iJoyInstanceID[10]; #endif #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "api/config.h" #include "api/m64p_config.h" #include "api/m64p_types.h" #include "eventloop.h" #include "main.h" #include "plugin/plugin.h" #include "sdl_key_converter.h" #include "util.h" /* version number for CoreEvents config section */ #define CONFIG_PARAM_VERSION 1.00 static m64p_handle l_CoreEventsConfig = NULL; /********************************************************************************************************* * static variables and definitions for eventloop.c */ #define kbdSaveSlot "Kbd Mapping Slot " #define kbdFullscreen "Kbd Mapping Fullscreen" #define kbdStop "Kbd Mapping Stop" #define kbdPause "Kbd Mapping Pause" #define kbdSave "Kbd Mapping Save State" #define kbdLoad "Kbd Mapping Load State" #define kbdIncrement "Kbd Mapping Increment Slot" #define kbdReset "Kbd Mapping Reset" #define kbdSpeeddown "Kbd Mapping Speed Down" #define kbdSpeedup "Kbd Mapping Speed Up" #define kbdScreenshot "Kbd Mapping Screenshot" #define kbdMute "Kbd Mapping Mute" #define kbdIncrease "Kbd Mapping Increase Volume" #define kbdDecrease "Kbd Mapping Decrease Volume" #define kbdForward "Kbd Mapping Fast Forward" #define kbdAdvance "Kbd Mapping Frame Advance" #define kbdGameshark "Kbd Mapping Gameshark" #define kbdSpeedtoggle "Kbd Mapping Speed Limiter Toggle" typedef enum {joyFullscreen, joyStop, joyPause, joySave, joyLoad, joyIncrement, joyReset, joySpeedDown, joySpeedUp, joyScreenshot, joyMute, joyIncrease, joyDecrease, joyForward, joyAdvance, joyGameshark } eJoyCommand; #ifndef NO_KEYBINDINGS static const char *JoyCmdName[] = { "Joy Mapping Fullscreen", "Joy Mapping Stop", "Joy Mapping Pause", "Joy Mapping Save State", "Joy Mapping Load State", "Joy Mapping Increment Slot", "Joy Mapping Reset", "Joy Mapping Speed Down", "Joy Mapping Speed Up", "Joy Mapping Screenshot", "Joy Mapping Mute", "Joy Mapping Increase Volume", "Joy Mapping Decrease Volume", "Joy Mapping Fast Forward", "Joy Mapping Frame Advance", "Joy Mapping Gameshark"}; static const int NumJoyCommands = sizeof(JoyCmdName) / sizeof(const char *); static int JoyCmdActive[16][2]; /* if extra joystick commands are added above, make sure there is enough room in this array */ /* [i][0] is Command Active, [i][1] is Hotkey Active */ #endif /* NO_KEYBINDINGS */ static int GamesharkActive = 0; /********************************************************************************************************* * static functions for eventloop.c */ #ifndef NO_KEYBINDINGS /** MatchJoyCommand * This function processes an SDL event and updates the JoyCmdActive array if the * event matches with the given command. * * If the event activates a joystick command which was not previously active, then * a 1 is returned. If the event de-activates an command, a -1 is returned. Otherwise * (if the event does not match the command or active status didn't change), a 0 is returned. */ static int MatchJoyCommand(const SDL_Event *event, eJoyCommand cmd) { const char *multi_event_str = ConfigGetParamString(l_CoreEventsConfig, JoyCmdName[cmd]); const int orig_cmd_value = (JoyCmdActive[cmd][1] << 1) | JoyCmdActive[cmd][0]; int dev_number, input_number, input_value; char axis_direction; /* Empty string or non-joystick command */ if (multi_event_str == NULL || strlen(multi_event_str) < 4 || multi_event_str[0] != 'J') return 0; /* Make copy of the event config string that we can hack it up with strtok */ char tokenized_event_str[128]; strncpy(tokenized_event_str, multi_event_str, 127); tokenized_event_str[127] = '\0'; /* Iterate over comma-separated config phrases */ char *phrase_str = strtok(tokenized_event_str, ","); while (phrase_str != NULL) { int iHotkey, has_hotkey = 0; /* Check for invalid phrase */ if (strlen(phrase_str) < 4 || phrase_str[0] != 'J') { phrase_str = strtok(NULL, ","); continue; } /* Get device (joystick) number */ if (phrase_str[1] == '*') { dev_number = -1; } else if (phrase_str[1] >= '0' && phrase_str[1] <= '9') { dev_number = phrase_str[1] - '0'; #if SDL_VERSION_ATLEAST(2,0,0) dev_number = l_iJoyInstanceID[dev_number]; #endif } else { phrase_str = strtok(NULL, ","); continue; } /* Iterate over JoyAction/JoyHotkey action fields */ for (iHotkey = 0; iHotkey < 2; iHotkey++) { const char *action_str = NULL; if (iHotkey == 0) { action_str = phrase_str + 2; } else { char *hotkey_str = strchr(phrase_str, '/'); if (hotkey_str == NULL || strlen(hotkey_str) < 3) { break; } action_str = hotkey_str+1; has_hotkey = 1; } /* Evaluate action based on type of joystick input expected */ switch (action_str[0]) { /* Axis */ case 'A': if (event->type != SDL_JOYAXISMOTION) break; if (sscanf(action_str, "A%d%c", &input_number, &axis_direction) != 2) break; if ((dev_number != 1 && dev_number != event->jaxis.which) || input_number != event->jaxis.axis) break; if (axis_direction == '+') { if (event->jaxis.value >= 15000) JoyCmdActive[cmd][iHotkey] = 1; else if (event->jaxis.value <= 8000) JoyCmdActive[cmd][iHotkey] = 0; break; } else if (axis_direction == '-') { if (event->jaxis.value <= -15000) JoyCmdActive[cmd][iHotkey] = 1; else if (event->jaxis.value >= -8000) JoyCmdActive[cmd][iHotkey] = 0; break; } break; /* Hat */ case 'H': if (event->type != SDL_JOYHATMOTION) break; if (sscanf(action_str, "H%dV%d", &input_number, &input_value) != 2) break; if ((dev_number != -1 && dev_number != event->jhat.which) || input_number != event->jhat.hat) break; if ((event->jhat.value & input_value) == input_value) JoyCmdActive[cmd][iHotkey] = 1; else if ((event->jhat.value & input_value) != input_value) JoyCmdActive[cmd][iHotkey] = 0; break; /* Button. */ case 'B': if (event->type != SDL_JOYBUTTONDOWN && event->type != SDL_JOYBUTTONUP) break; if (sscanf(action_str, "B%d", &input_number) != 1) break; if ((dev_number != -1 && dev_number != event->jbutton.which) || input_number != event->jbutton.button) break; if (event->type == SDL_JOYBUTTONDOWN) JoyCmdActive[cmd][iHotkey] = 1; else if (event->type == SDL_JOYBUTTONUP) JoyCmdActive[cmd][iHotkey] = 0; break; default: /* bad configuration parameter */ break; } } /* Iterate over JoyAction/JoyHotkey action fields */ /* Detect changes in command activation status */ const int new_cmd_value = (JoyCmdActive[cmd][1] << 1) | JoyCmdActive[cmd][0]; const int active_mask = has_hotkey ? 3 : 1; if ((orig_cmd_value & active_mask) != active_mask && (new_cmd_value & active_mask) == active_mask) return 1; if ((orig_cmd_value & active_mask) == active_mask && (new_cmd_value & active_mask) != active_mask) return -1; /* get next comma-separated command phrase from event string */ phrase_str = strtok(NULL, ","); } /* Iterate over comma-separated config phrases */ /* nothing found */ return 0; } #endif /* NO_KEYBINDINGS */ /********************************************************************************************************* * sdl event filter */ static int SDLCALL event_sdl_filter(void *userdata, SDL_Event *event) { #ifndef NO_KEYBINDINGS int cmd, action; #endif /* NO_KEYBINDINGS */ switch(event->type) { // user clicked on window close button case SDL_QUIT: main_stop(); break; case SDL_KEYDOWN: #if SDL_VERSION_ATLEAST(1,3,0) if (event->key.repeat) return 0; event_sdl_keydown(event->key.keysym.scancode, event->key.keysym.mod); #else event_sdl_keydown(event->key.keysym.sym, event->key.keysym.mod); #endif return 0; case SDL_KEYUP: #if SDL_VERSION_ATLEAST(1,3,0) event_sdl_keyup(event->key.keysym.scancode, event->key.keysym.mod); #else event_sdl_keyup(event->key.keysym.sym, event->key.keysym.mod); #endif return 0; #if SDL_VERSION_ATLEAST(1,3,0) case SDL_WINDOWEVENT: switch (event->window.event) { case SDL_WINDOWEVENT_RESIZED: // call the video plugin. if the video plugin supports resizing, it will resize its viewport and call // VidExt_ResizeWindow to update the window manager handling our opengl output window gfx.resizeVideoOutput(event->window.data1, event->window.data2); return 0; // consumed the event break; case SDL_WINDOWEVENT_MOVED: gfx.moveScreen(event->window.data1, event->window.data2); return 0; // consumed the event break; } break; #else case SDL_VIDEORESIZE: // call the video plugin. if the video plugin supports resizing, it will resize its viewport and call // VidExt_ResizeWindow to update the window manager handling our opengl output window gfx.resizeVideoOutput(event->resize.w, event->resize.h); return 0; // consumed the event break; #ifdef WIN32 case SDL_SYSWMEVENT: if(event->syswm.msg->msg == WM_MOVE) gfx.moveScreen(0,0); // The video plugin is responsible for getting the new window position return 0; // consumed the event break; #endif #endif #ifndef NO_KEYBINDINGS // if joystick action is detected, check if it's mapped to a special function case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: case SDL_JOYHATMOTION: for (cmd = 0; cmd < NumJoyCommands; cmd++) { action = MatchJoyCommand(event, (eJoyCommand) cmd); if (action == 1) /* command was just activated (button down, etc) */ { if (cmd == joyFullscreen) gfx.changeWindow(); else if (cmd == joyStop) main_stop(); else if (cmd == joyPause) main_toggle_pause(); else if (cmd == joySave) main_state_save(1, NULL); /* save in mupen64plus format using current slot */ else if (cmd == joyLoad) main_state_load(NULL); /* load using current slot */ else if (cmd == joyIncrement) main_state_inc_slot(); else if (cmd == joyReset) main_reset(0); else if (cmd == joySpeedDown) main_speeddown(5); else if (cmd == joySpeedUp) main_speedup(5); else if (cmd == joyScreenshot) main_take_next_screenshot(); else if (cmd == joyMute) main_volume_mute(); else if (cmd == joyDecrease) main_volume_down(); else if (cmd == joyIncrease) main_volume_up(); else if (cmd == joyForward) main_set_fastforward(1); else if (cmd == joyAdvance) main_advance_one(); else if (cmd == joyGameshark) event_set_gameshark(1); } else if (action == -1) /* command was just de-activated (button up, etc) */ { if (cmd == joyForward) main_set_fastforward(0); else if (cmd == joyGameshark) event_set_gameshark(0); } } return 0; break; #endif /* NO_KEYBINDINGS */ } return 1; // add this event to SDL queue } /********************************************************************************************************* * global functions */ void event_initialize(void) { #ifndef NO_KEYBINDINGS int i, j; /* set initial state of all joystick commands to 'off' */ for (i = 0; i < NumJoyCommands; i++) for (j = 0; j < 2; j++) JoyCmdActive[i][j] = 0; /* activate any joysticks which are referenced in the joystick event command strings */ const int NumJoysticks = SDL_NumJoysticks(); if (NumJoysticks > 0) { for (i = 0; i < NumJoyCommands; i++) { const char *multi_event_str = ConfigGetParamString(l_CoreEventsConfig, JoyCmdName[i]); /* Empty string or invalid command */ if (multi_event_str == NULL || strlen(multi_event_str) < 4 || multi_event_str[0] != 'J') continue; /* Make copy of the event config string that we can hack it up with strtok */ char tokenized_event_str[128]; strncpy(tokenized_event_str, multi_event_str, 127); tokenized_event_str[127] = '\0'; /* Iterate over comma-separated config phrases */ char *phrase_str = strtok(tokenized_event_str, ","); while (phrase_str != NULL) { /* Check for invalid phrase */ if (strlen(phrase_str) < 4 || phrase_str[0] != 'J') { phrase_str = strtok(NULL, ","); continue; } /* Get device (joystick) number(s) to initialize */ int joy_min, joy_max; if (phrase_str[1] == '*') { joy_min = 0; joy_max = NumJoysticks - 1; } else if (phrase_str[1] >= '0' && phrase_str[1] <= '9') { joy_min = joy_max = phrase_str[1] - '0'; } else { phrase_str = strtok(NULL, ","); continue; } /* initialize them */ int device; for (device = joy_min; device <= joy_max; device++) { if (!SDL_WasInit(SDL_INIT_JOYSTICK)) SDL_InitSubSystem(SDL_INIT_JOYSTICK); #if SDL_VERSION_ATLEAST(2,0,0) SDL_Joystick *thisJoy = SDL_JoystickOpen(device); l_iJoyInstanceID[device] = SDL_JoystickInstanceID(thisJoy); #else if (!SDL_JoystickOpened(device)) SDL_JoystickOpen(device); #endif } phrase_str = strtok(NULL, ","); } /* Iterate over comma-separated config phrases */ } } #endif /* NO_KEYBINDINGS */ /* set up SDL event filter and disable key repeat */ #if !SDL_VERSION_ATLEAST(2,0,0) SDL_EnableKeyRepeat(0, 0); #endif SDL_SetEventFilter(event_sdl_filter, NULL); #if defined(WIN32) && !SDL_VERSION_ATLEAST(1,3,0) SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); if (SDL_EventState(SDL_SYSWMEVENT, SDL_QUERY) != SDL_ENABLE) DebugMessage(M64MSG_WARNING, "Failed to change event state: %s", SDL_GetError()); #endif } int event_set_core_defaults(void) { float fConfigParamsVersion; if (ConfigOpenSection("CoreEvents", &l_CoreEventsConfig) != M64ERR_SUCCESS || l_CoreEventsConfig == NULL) { DebugMessage(M64MSG_ERROR, "Failed to open CoreEvents config section."); return 0; /* fail */ } if (ConfigGetParameter(l_CoreEventsConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS) { DebugMessage(M64MSG_WARNING, "No version number in 'CoreEvents' config section. Setting defaults."); ConfigDeleteSection("CoreEvents"); ConfigOpenSection("CoreEvents", &l_CoreEventsConfig); } else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION)) { DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'CoreEvents' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION); ConfigDeleteSection("CoreEvents"); ConfigOpenSection("CoreEvents", &l_CoreEventsConfig); } else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f) { /* handle upgrades */ float fVersion = CONFIG_PARAM_VERSION; ConfigSetParameter(l_CoreEventsConfig, "Version", M64TYPE_FLOAT, &fVersion); DebugMessage(M64MSG_INFO, "Updating parameter set version in 'CoreEvents' config section to %.2f", fVersion); } ConfigSetDefaultFloat(l_CoreEventsConfig, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus CoreEvents config parameter set version number. Please don't change this version number."); /* Keyboard presses mapped to core functions */ #ifndef NO_KEYBINDINGS char kbdSaveSlotStr[sizeof(kbdSaveSlot)+1]; char kbdSaveSlotHelpStr[27]; int key = SDL_SCANCODE_UNKNOWN; for (int slot = 0; slot < 10; slot++) { #if ! SDL_VERSION_ATLEAST(1,3,0) key = SDL_SCANCODE_0 + slot; #else key = slot == 0 ? SDL_SCANCODE_0 : SDL_SCANCODE_1 + (slot - 1); #endif sprintf(kbdSaveSlotStr, "%s%i", kbdSaveSlot, slot); sprintf(kbdSaveSlotHelpStr, "SDL keysym for save slot %i", slot); ConfigSetDefaultInt(l_CoreEventsConfig, kbdSaveSlotStr, sdl_native2keysym(key), kbdSaveSlotHelpStr); } ConfigSetDefaultInt(l_CoreEventsConfig, kbdStop, sdl_native2keysym(SDL_SCANCODE_ESCAPE), "SDL keysym for stopping the emulator"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdFullscreen, sdl_native2keysym(SDL_NUM_SCANCODES), "SDL keysym for switching between fullscreen/windowed modes"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdSave, sdl_native2keysym(SDL_SCANCODE_F5), "SDL keysym for saving the emulator state"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdLoad, sdl_native2keysym(SDL_SCANCODE_F7), "SDL keysym for loading the emulator state"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdIncrement, sdl_native2keysym(SDL_SCANCODE_UNKNOWN), "SDL keysym for advancing the save state slot"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdReset, sdl_native2keysym(SDL_SCANCODE_F9), "SDL keysym for resetting the emulator"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdSpeeddown, sdl_native2keysym(SDL_SCANCODE_F10), "SDL keysym for slowing down the emulator"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdSpeedup, sdl_native2keysym(SDL_SCANCODE_F11), "SDL keysym for speeding up the emulator"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdScreenshot, sdl_native2keysym(SDL_SCANCODE_F12), "SDL keysym for taking a screenshot"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdPause, sdl_native2keysym(SDL_SCANCODE_P), "SDL keysym for pausing the emulator"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdMute, sdl_native2keysym(SDL_SCANCODE_M), "SDL keysym for muting/unmuting the sound"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdIncrease, sdl_native2keysym(SDL_SCANCODE_RIGHTBRACKET),"SDL keysym for increasing the volume"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdDecrease, sdl_native2keysym(SDL_SCANCODE_LEFTBRACKET), "SDL keysym for decreasing the volume"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdForward, sdl_native2keysym(SDL_SCANCODE_F), "SDL keysym for temporarily going really fast"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdSpeedtoggle, sdl_native2keysym(SDL_SCANCODE_Y), "SDL keysym for toggling the framerate limiter"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdAdvance, sdl_native2keysym(SDL_SCANCODE_SLASH), "SDL keysym for advancing by one frame when paused"); ConfigSetDefaultInt(l_CoreEventsConfig, kbdGameshark, sdl_native2keysym(SDL_SCANCODE_G), "SDL keysym for pressing the game shark button"); /* Joystick events mapped to core functions */ ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyStop], "", "Joystick event string for stopping the emulator"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyFullscreen], "", "Joystick event string for switching between fullscreen/windowed modes"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joySave], "", "Joystick event string for saving the emulator state"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyLoad], "", "Joystick event string for loading the emulator state"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyIncrement], "", "Joystick event string for advancing the save state slot"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyReset], "", "Joystick event string for resetting the emulator"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joySpeedDown], "", "Joystick event string for slowing down the emulator"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joySpeedUp], "", "Joystick event string for speeding up the emulator"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyScreenshot], "", "Joystick event string for taking a screenshot"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyPause], "", "Joystick event string for pausing the emulator"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyMute], "", "Joystick event string for muting/unmuting the sound"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyIncrease], "", "Joystick event string for increasing the volume"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyDecrease], "", "Joystick event string for decreasing the volume"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyForward], "", "Joystick event string for fast-forward"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyAdvance], "", "Joystick event string for advancing by one frame when paused"); ConfigSetDefaultString(l_CoreEventsConfig, JoyCmdName[joyGameshark], "", "Joystick event string for pressing the game shark button"); #endif /* NO_KEYBINDINGS */ return 1; } #ifndef NO_KEYBINDINGS static int get_saveslot_from_keysym(int keysym) { char kbdSaveSlotStr[sizeof(kbdSaveSlot)+1]; int kbdSaveSlotKey; for (int slot = 0; slot < 10; slot++) { sprintf(kbdSaveSlotStr, "%s%i", kbdSaveSlot, slot); kbdSaveSlotKey = ConfigGetParamInt(l_CoreEventsConfig, kbdSaveSlotStr); if (keysym == sdl_keysym2native(kbdSaveSlotKey)) return slot; } return -1; } #endif /* NO_KEYBINDINGS */ /********************************************************************************************************* * sdl keyup/keydown handlers */ void event_sdl_keydown(int keysym, int keymod) { #ifndef NO_KEYBINDINGS int slot; /* check for the only hard-coded key command: Alt-enter for fullscreen */ if (keysym == SDL_SCANCODE_RETURN && keymod & (KMOD_LALT | KMOD_RALT)) gfx.changeWindow(); /* check all of the configurable commands */ else if ((slot = get_saveslot_from_keysym(keysym)) >= 0) main_state_set_slot(slot); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdStop))) main_stop(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdFullscreen))) gfx.changeWindow(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdSave))) main_state_save(0, NULL); /* save in mupen64plus format using current slot */ else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdLoad))) main_state_load(NULL); /* load using current slot */ else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdIncrement))) main_state_inc_slot(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdReset))) main_reset(0); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdSpeeddown))) main_speeddown(5); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdSpeedtoggle))) main_speedlimiter_toggle(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdSpeedup))) main_speedup(5); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdScreenshot))) main_take_next_screenshot(); /* screenshot will be taken at the end of frame rendering */ else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdPause))) main_toggle_pause(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdMute))) main_volume_mute(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdIncrease))) main_volume_up(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdDecrease))) main_volume_down(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdForward))) main_set_fastforward(1); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdAdvance))) main_advance_one(); else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdGameshark))) { event_set_gameshark(1); } else #endif /* NO_KEYBINDINGS */ { /* pass all other keypresses to the input plugin */ input.keyDown(keymod, keysym); } } void event_sdl_keyup(int keysym, int keymod) { #ifndef NO_KEYBINDINGS if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdStop))) { return; } else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdForward))) { main_set_fastforward(0); } else if (keysym == sdl_keysym2native(ConfigGetParamInt(l_CoreEventsConfig, kbdGameshark))) { event_set_gameshark(0); } else #endif /* NO_KEYBINDINGS */ { input.keyUp(keymod, keysym); } } int event_gameshark_active(void) { return GamesharkActive; } void event_set_gameshark(int active) { // if boolean value doesn't change then just return if (!active == !GamesharkActive) return; // set the button state GamesharkActive = (active ? 1 : 0); // notify front-end application that gameshark button state has changed StateChanged(M64CORE_INPUT_GAMESHARK, GamesharkActive); } mupen64plus-core-src-2.6.0/src/main/eventloop.h000066400000000000000000000035511464506436200213510ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - eventloop.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(EVENTLOOP_H) #define EVENTLOOP_H extern int event_set_core_defaults(void); extern void event_initialize(void); extern void event_sdl_keydown(int keysym, int keymod); extern void event_sdl_keyup(int keysym, int keymod); extern int event_gameshark_active(void); extern void event_set_gameshark(int active); #endif /* define(EVENTLOOP_H) */ mupen64plus-core-src-2.6.0/src/main/lirc.c000066400000000000000000000100261464506436200202550ustar00rootroot00000000000000/*************************************************************************** lirc.c - handle lirc input events to Mupen64Plus ------------------- begin : Friday 11 Jan 2008 copyright : (C) 2008 by DarkJezter ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // Functions for LIRC support #ifdef WITH_LIRC #include #include #include #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "lirc.h" #include "main.h" #include "plugin/plugin.h" #include "savestates.h" static struct lirc_config *g_config; static int g_lircfd = 0; void lircStart(void) { if((g_lircfd = lirc_init("mupen64plus", 1)) != -1) { g_config = NULL; if(lirc_readconfig(NULL, &g_config, NULL) == 0) DebugMessage(M64MSG_INFO, "LIRC input system started successfully"); else DebugMessage(M64MSG_WARNING, "LIRC disabled: Error reading lircrc!"); } else DebugMessage(M64MSG_WARNING, "LIRC disabled: Error contacting daemon!"); } void lircStop(void) { if(g_lircfd!=-1) { if(g_config != NULL) { lirc_freeconfig(g_config); g_config = NULL; } lirc_deinit(); DebugMessage(M64MSG_INFO, "LIRC system shut down"); } } void lircCheckInput(void) { struct pollfd lircpoll; lircpoll.fd = g_lircfd; lircpoll.events = POLLIN; if(poll(&lircpoll, 1, 0) > 0) { char *code; char *c; int ret; if(lirc_nextcode(&code) == 0 && code != NULL) { while((ret = lirc_code2char(g_config, code, &c)) == 0 && c!=NULL) { char *c_ind = c; while(*c_ind != '\0') { *c_ind = toupper(*c_ind); c_ind++; } DebugMessage(M64MSG_VERBOSE, "LIRC Execing command \"%s\"", c); if(strcmp(c, "SAVE") == 0) main_state_save(1, NULL); /* save in mupen64plus format using current slot */ else if(strcmp(c, "LOAD") == 0) main_state_load(NULL); /* load using current slot */ else if(strcmp(c, "QUIT") == 0) main_stop(); else if(strcmp(c, "FULLSCREEN") == 0) gfx.changeWindow(); else if(strcmp(c, "MUTE") == 0) main_volume_mute(); else if(strcmp(c, "VOL+") == 0) main_volume_up(); else if(strcmp(c, "VOL-") == 0) main_volume_down(); else if(strcmp(c, "SCREENSHOT") == 0) main_take_next_screenshot(); else if(strcmp(c, "SPEED+") == 0) main_speedup(5); else if(strcmp(c, "SPEED-") == 0) main_speeddown(5); else if(strcmp(c, "ADVANCE") == 0) main_advance_one(); else if(strcmp(c, "PAUSE") == 0) main_toggle_pause(); else { int val = ((int)c[0])-((int) '0'); if (val >= 0 && val <= 9) savestates_select_slot( val ); } } free(code); } } } #endif //WITH_LIRC mupen64plus-core-src-2.6.0/src/main/lirc.h000066400000000000000000000021411464506436200202610ustar00rootroot00000000000000/*************************************************************************** lirc.h - description ------------------- begin : Friday 11 Jan 2008 copyright : (C) 2008 by DarkJezter ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef __LIRC_H__ #define __LIRC_H__ extern void lircStart(void); extern void lircStop(void); extern void lircCheckInput(void); #endif //__LIRC_H__ mupen64plus-core-src-2.6.0/src/main/list.h000066400000000000000000000077041464506436200203150ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - util.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 Mupen64plus development team * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __LIST_H__ #define __LIST_H__ #include #include "osal/preproc.h" struct list_head { struct list_head *prev; struct list_head *next; }; #define LIST_HEAD(list) \ struct list_head list = { &(list), &(list) } static osal_inline void INIT_LIST_HEAD(struct list_head *head) { head->next = head; head->prev = head; } static osal_inline void list_add(struct list_head *new_item, struct list_head *head) { struct list_head *next = head->next; next->prev = new_item; new_item->next = next; new_item->prev = head; head->next = new_item; } static osal_inline void list_add_tail(struct list_head *new_item, struct list_head *head) { struct list_head *prev = head->prev; prev->next = new_item; new_item->next = head; new_item->prev = prev; head->prev = new_item; } static osal_inline void list_del(struct list_head *entry) { struct list_head *next = entry->next; struct list_head *prev = entry->prev; next->prev = prev; prev->next = next; } static osal_inline void list_del_init(struct list_head *entry) { list_del(entry); INIT_LIST_HEAD(entry); } static osal_inline int list_empty(const struct list_head *head) { return (head->next == head); } #ifdef __GNUC__ #define container_of(ptr, type, member) __extension__ ({ \ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #else #define container_of(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member))) #endif #define list_entry(ptr, type, member) container_of(ptr, type, member) #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_entry_t(pos, head, type, member) \ for (pos = list_entry((head)->next, type, member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, type, member)) #define list_for_each_safe(pos, safe, head) \ for (pos = (head)->next, safe = pos->next; pos != (head); \ pos = safe, safe = pos->next) #define list_for_each_entry_safe_t(pos, safe, head, type, member) \ for (pos = list_entry((head)->next, type, member), \ safe = list_entry(pos->member.next, type, member); \ &pos->member != (head); \ pos = safe, \ safe = list_entry(safe->member.next, type, member)) #endif mupen64plus-core-src-2.6.0/src/main/main.c000066400000000000000000002101151464506436200202510ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - main.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 CasualJames * * Copyright (C) 2008-2009 Richard Goedeken * * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This is MUPEN64's main entry point. It contains code that is common * to both the gui and non-gui versions of mupen64. See * gui subdirectories for the gui-specific code. * if you want to implement an interface, you should look here */ #include #include #include #include #include #include #include #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "api/config.h" #include "api/debugger.h" #include "api/m64p_config.h" #include "api/m64p_types.h" #include "api/m64p_vidext.h" #include "api/vidext.h" #include "backends/api/audio_out_backend.h" #include "backends/api/clock_backend.h" #include "backends/api/controller_input_backend.h" #include "backends/api/joybus.h" #include "backends/api/rumble_backend.h" #include "backends/api/storage_backend.h" #include "backends/api/video_capture_backend.h" #include "backends/plugins_compat/plugins_compat.h" #include "backends/clock_ctime_plus_delta.h" #include "backends/file_storage.h" #include "cheat.h" #include "device/device.h" #include "device/dd/disk.h" #include "device/controllers/vru_controller.h" #include "device/controllers/paks/biopak.h" #include "device/controllers/paks/mempak.h" #include "device/controllers/paks/rumblepak.h" #include "device/controllers/paks/transferpak.h" #include "device/gb/gb_cart.h" #include "device/pif/bootrom_hle.h" #include "eventloop.h" #include "main.h" #include "osal/files.h" #include "osal/preproc.h" #include "osd/osd.h" #include "plugin/plugin.h" #if defined(PROFILE) #include "profile.h" #endif #include "rom.h" #include "savestates.h" #include "screenshot.h" #include "util.h" #include "netplay.h" #ifdef DBG #include "debugger/dbg_debugger.h" #endif #ifdef WITH_LIRC #include "lirc.h" #endif //WITH_LIRC /* version number for Core config section */ #define CONFIG_PARAM_VERSION 1.01 /** globals **/ m64p_handle g_CoreConfig = NULL; m64p_frame_callback g_FrameCallback = NULL; int g_RomWordsLittleEndian = 0; // after loading, ROM words are in native N64 byte order (big endian). We will swap them on x86 int g_EmulatorRunning = 0; // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread int g_rom_pause; struct cheat_ctx g_cheat_ctx; /* g_mem_base is global to allow plugins early access (before device is initialized). * Do not use this variable directly in emulation code. * Initialization and DeInitialization of this variable is done at CoreStartup and CoreShutdown. */ void* g_mem_base = NULL; uint32_t g_start_address = UINT32_C(0xa4000040); struct device g_dev; m64p_media_loader g_media_loader; int g_gs_vi_counter = 0; /** static (local) variables **/ static int l_CurrentFrame = 0; // frame counter static int l_TakeScreenshot = 0; // Tell OSD Rendering callback to take a screenshot just before drawing the OSD static int l_SpeedFactor = 100; // percentage of nominal game speed at which emulator is running static int l_FrameAdvance = 0; // variable to check if we pause on next frame static int l_MainSpeedLimit = 1; // insert delay during vi_interrupt to keep speed at real-time static osd_message_t *l_msgVol = NULL; static osd_message_t *l_msgFF = NULL; static osd_message_t *l_msgPause = NULL; /* compatible paks */ enum { PAK_MAX_SIZE = 5 }; static size_t l_paks_idx[GAME_CONTROLLERS_COUNT]; static void* l_paks[GAME_CONTROLLERS_COUNT][PAK_MAX_SIZE]; static const struct pak_interface* l_ipaks[PAK_MAX_SIZE]; static size_t l_pak_type_idx[6]; /* PRNG state - used for Mempaks ID generation */ static struct xoshiro256pp_state l_mpk_idgen; /********************************************************************************************************* * static functions */ static const char *get_savepathdefault(const char *configpath) { static char path[1024]; if (!configpath || (strlen(configpath) == 0)) { snprintf(path, 1024, "%ssave%c", ConfigGetUserDataPath(), OSAL_DIR_SEPARATORS[0]); path[1023] = 0; } else { snprintf(path, 1024, "%s%c", configpath, OSAL_DIR_SEPARATORS[0]); path[1023] = 0; } /* create directory if it doesn't exist */ osal_mkdirp(path, 0700); return path; } static char *get_save_filename(void) { static char filename[256]; int format = ConfigGetParamInt(g_CoreConfig, "SaveFilenameFormat"); if (format == 0) { snprintf(filename, 256, "%s", ROM_PARAMS.headername); } else /* if (format == 1) */ { if (strstr(ROM_SETTINGS.goodname, "(unknown rom)") == NULL) { snprintf(filename, 256, "%.32s-%.8s", ROM_SETTINGS.goodname, ROM_SETTINGS.MD5); } else if (ROM_HEADER.Name[0] != 0) { snprintf(filename, 256, "%s-%.8s", ROM_PARAMS.headername, ROM_SETTINGS.MD5); } else { snprintf(filename, 256, "unknown-%.8s", ROM_SETTINGS.MD5); } } /* sanitize filename */ string_replace_chars(filename, ":<>\"/\\|?*", '_'); return filename; } static char *get_mempaks_path(void) { char *path; size_t size = 0; /* check if old file path exists, if it does then use that */ path = formatstr("%s%s.mpk", get_savesrampath(), ROM_SETTINGS.goodname); if (get_file_size(path, &size) == file_ok && size > 0) { return path; } free(path); /* else use new path */ return formatstr("%s%s.mpk", get_savesrampath(), get_save_filename()); } static char *get_eeprom_path(void) { char *path; size_t size = 0; /* check if old file path exists, if it does then use that */ path = formatstr("%s%s.eep", get_savesrampath(), ROM_SETTINGS.goodname); if (get_file_size(path, &size) == file_ok && size > 0) { return path; } free(path); /* else use new path */ return formatstr("%s%s.eep", get_savesrampath(), get_save_filename()); } static char *get_sram_path(void) { char *path; size_t size = 0; /* check if old file path exists, if it does then use that */ path = formatstr("%s%s.sra", get_savesrampath(), ROM_SETTINGS.goodname); if (get_file_size(path, &size) == file_ok && size > 0) { return path; } free(path); /* else use new path */ return formatstr("%s%s.sra", get_savesrampath(), get_save_filename()); } static char *get_flashram_path(void) { char *path; size_t size = 0; /* check if old file path exists, if it does then use that */ path = formatstr("%s%s.fla", get_savesrampath(), ROM_SETTINGS.goodname); if (get_file_size(path, &size) == file_ok && size > 0) { return path; } free(path); /* else use new path */ return formatstr("%s%s.fla", get_savesrampath(), get_save_filename()); } static char *get_gb_ram_path(const char* gbrom, unsigned int control_id) { return formatstr("%s%s.%u.sav", get_savesrampath(), gbrom, control_id); } static char *get_dd_disk_save_path(const char* disk, int format) { char* filename = NULL; int len = strlen(disk); int has_expected_ext = (len >= 4 && (strcmp(disk + len - 4, ".ndd") == 0 || strcmp(disk + len - 4, ".d64") == 0)); switch (format) { case 0: /* *.ndr,*.d6r, full disk content */ if (has_expected_ext) { /* file has .ndd / .d64, so adjust existing extension */ filename = formatstr("%s%s", get_savesrampath(), disk); len = strlen(filename); filename[len-1] = 'r'; } else { /* file doesn't have .ndd / .d64 extension, so fallback to .ndr */ filename = formatstr("%s%s.ndr", get_savesrampath(), disk); } break; case 1: /* *.ram, only RAM part is persisted */ if (has_expected_ext) { /* file has .ndd / .d64, so adjust existing extension */ filename = formatstr("%s%s", get_savesrampath(), disk); len = strlen(filename); filename[len-3] = 'r'; filename[len-2] = 'a'; filename[len-1] = 'm'; } else { /* file doesn't have .ndd / .d64 extension, so fallback to .ram */ filename = formatstr("%s%s.ram", get_savesrampath(), disk); } break; default: DebugMessage(M64MSG_WARNING, "Unexpected DD save format: %d", format); break; } return filename; } static m64p_error init_video_capture_backend(const struct video_capture_backend_interface** ivcap, void** vcap, m64p_handle config, const char* key) { m64p_error err; const char* name = ConfigGetParamString(config, key); if (name == NULL) { DebugMessage(M64MSG_WARNING, "Couldn't get %s value. Using NULL value instead.", key); } /* try to find desired backend (by name) */ *ivcap = get_video_capture_backend(name); /* handle not found case */ if (*ivcap == NULL) { /* default to dummy backend */ *ivcap = get_video_capture_backend(NULL); DebugMessage(M64MSG_WARNING, "Could not find %s video_capture_backend_interface. Using %s instead.", name, (*ivcap)->name); } /* build section name */ char* section = formatstr("%s:%s", key, (*ivcap)->name); /* init backend */ err = (*ivcap)->init(vcap, section); if (err == M64ERR_SUCCESS) { DebugMessage(M64MSG_INFO, "Using video capture backend: %s", (*ivcap)->name); } else { DebugMessage(M64MSG_ERROR, "Failed to initialize video capture backend %s: %s", (*ivcap)->name, CoreErrorMessage(err)); *ivcap = NULL; } free(section); return err; } /********************************************************************************************************* * helper functions */ const char *get_savestatepath(void) { /* try to get the SaveStatePath string variable in the Core configuration section */ return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveStatePath")); } const char *get_savesrampath(void) { /* try to get the SaveSRAMPath string variable in the Core configuration section */ return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveSRAMPath")); } const char *get_savestatefilename(void) { /* return same file name as save files */ return get_save_filename(); } void main_message(m64p_msg_level level, unsigned int corner, const char *format, ...) { va_list ap; char buffer[2049]; va_start(ap, format); vsnprintf(buffer, 2047, format, ap); buffer[2048]='\0'; va_end(ap); /* send message to on-screen-display if enabled */ if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay")) osd_new_message((enum osd_corner) corner, "%s", buffer); /* send message to front-end */ DebugMessage(level, "%s", buffer); } static void main_check_inputs(void) { #ifdef WITH_LIRC lircCheckInput(); #endif SDL_PumpEvents(); } /********************************************************************************************************* * global functions, for adjusting the core emulator behavior */ int main_set_core_defaults(void) { float fConfigParamsVersion; int bUpgrade = 0; if (ConfigGetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS) { DebugMessage(M64MSG_WARNING, "No version number in 'Core' config section. Setting defaults."); ConfigDeleteSection("Core"); ConfigOpenSection("Core", &g_CoreConfig); } else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION)) { DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Core' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION); ConfigDeleteSection("Core"); ConfigOpenSection("Core", &g_CoreConfig); } else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f) { float fVersion = (float) CONFIG_PARAM_VERSION; ConfigSetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fVersion); DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Core' config section to %.2f", fVersion); bUpgrade = 1; } /* parameters controlling the operation of the core */ ConfigSetDefaultFloat(g_CoreConfig, "Version", (float) CONFIG_PARAM_VERSION, "Mupen64Plus Core config parameter set version number. Please don't change this version number."); ConfigSetDefaultBool(g_CoreConfig, "OnScreenDisplay", 1, "Draw on-screen display if True, otherwise don't draw OSD"); #if defined(DYNAREC) ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 2, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more"); #else ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 1, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more"); #endif ConfigSetDefaultBool(g_CoreConfig, "NoCompiledJump", 0, "Disable compiled jump commands in dynamic recompiler (should be set to False) "); ConfigSetDefaultBool(g_CoreConfig, "DisableExtraMem", 0, "Disable 4MB expansion RAM pack. May be necessary for some games"); ConfigSetDefaultInt(g_CoreConfig, "CountPerOp", 0, "Force number of cycles per emulated instruction"); ConfigSetDefaultInt(g_CoreConfig, "CountPerOpDenomPot", 0, "Reduce number of cycles per update by power of two when set greater than 0 (overclock)"); ConfigSetDefaultBool(g_CoreConfig, "AutoStateSlotIncrement", 0, "Increment the save state slot after each save operation"); ConfigSetDefaultInt(g_CoreConfig, "CurrentStateSlot", 0, "Save state slot (0-9) to use when saving/loading the emulator state"); ConfigSetDefaultBool(g_CoreConfig, "EnableDebugger", 0, "Activate the R4300 debugger when ROM execution begins, if core was built with Debugger support"); ConfigSetDefaultString(g_CoreConfig, "ScreenshotPath", "", "Path to directory where screenshots are saved. If this is blank, the default value of ${UserDataPath}/screenshot will be used"); ConfigSetDefaultString(g_CoreConfig, "SaveStatePath", "", "Path to directory where emulator save states (snapshots) are saved. If this is blank, the default value of ${UserDataPath}/save will be used"); ConfigSetDefaultString(g_CoreConfig, "SaveSRAMPath", "", "Path to directory where SRAM/EEPROM data (in-game saves) are stored. If this is blank, the default value of ${UserDataPath}/save will be used"); ConfigSetDefaultString(g_CoreConfig, "SharedDataPath", "", "Path to a directory to search when looking for shared data files"); ConfigSetDefaultBool(g_CoreConfig, "RandomizeInterrupt", 1, "Randomize PI/SI Interrupt Timing"); ConfigSetDefaultInt(g_CoreConfig, "SiDmaDuration", -1, "Duration of SI DMA (-1: use per game settings)"); ConfigSetDefaultString(g_CoreConfig, "GbCameraVideoCaptureBackend1", DEFAULT_VIDEO_CAPTURE_BACKEND, "Gameboy Camera Video Capture backend"); ConfigSetDefaultInt(g_CoreConfig, "SaveDiskFormat", 1, "Disk Save Format (0: Full Disk Copy (*.ndr/*.d6r), 1: RAM Area Only (*.ram))"); ConfigSetDefaultInt(g_CoreConfig, "SaveFilenameFormat", 1, "Save (SRAM/State) Filename Format (0: ROM Header Name, 1: Automatic (including partial MD5 hash))"); /* handle upgrades */ if (bUpgrade) { if (fConfigParamsVersion < 1.01f) { // added separate SaveSRAMPath parameter in v1.01 const char *pccSaveStatePath = ConfigGetParamString(g_CoreConfig, "SaveStatePath"); if (pccSaveStatePath != NULL) ConfigSetParameter(g_CoreConfig, "SaveSRAMPath", M64TYPE_STRING, pccSaveStatePath); } } /* set config parameters for keyboard and joystick commands */ return event_set_core_defaults(); } void main_speeddown(int percent) { if (netplay_is_init()) return; if (l_SpeedFactor - percent > 10) /* 10% minimum speed */ { l_SpeedFactor -= percent; main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor); audio.setSpeedFactor(l_SpeedFactor); StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor); } } void main_speedup(int percent) { if (netplay_is_init()) return; if (l_SpeedFactor + percent < 300) /* 300% maximum speed */ { l_SpeedFactor += percent; main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor); audio.setSpeedFactor(l_SpeedFactor); StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor); } } static void main_speedset(int percent) { if (netplay_is_init()) return; if (percent < 1 || percent > 1000) { DebugMessage(M64MSG_WARNING, "Invalid speed setting %i percent", percent); return; } // disable fast-forward if it's enabled main_set_fastforward(0); // set speed l_SpeedFactor = percent; main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor); audio.setSpeedFactor(l_SpeedFactor); StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor); } void main_set_fastforward(int enable) { if (netplay_is_init()) return; static int ff_state = 0; static int SavedSpeedFactor = 100; if (enable && !ff_state) { ff_state = 1; /* activate fast-forward */ SavedSpeedFactor = l_SpeedFactor; l_SpeedFactor = 250; audio.setSpeedFactor(l_SpeedFactor); StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor); // set fast-forward indicator l_msgFF = osd_new_message(OSD_TOP_RIGHT, "Fast Forward"); osd_message_set_static(l_msgFF); osd_message_set_user_managed(l_msgFF); } else if (!enable && ff_state) { ff_state = 0; /* de-activate fast-forward */ l_SpeedFactor = SavedSpeedFactor; audio.setSpeedFactor(l_SpeedFactor); StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor); // remove message osd_delete_message(l_msgFF); l_msgFF = NULL; } } static void main_set_speedlimiter(int enable) { if (netplay_is_init() && !netplay_lag()) return; l_MainSpeedLimit = enable ? 1 : 0; } void main_speedlimiter_toggle(void) { if (netplay_is_init()) return; l_MainSpeedLimit = !l_MainSpeedLimit; main_set_speedlimiter(l_MainSpeedLimit); if (l_MainSpeedLimit) /* fix naturally occuring audio desync */ { main_toggle_pause(); SDL_Delay(1000); main_toggle_pause(); main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Speed limiter enabled"); } else main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Speed limiter disabled"); } static int main_is_paused(void) { return (g_EmulatorRunning && g_rom_pause); } void main_toggle_pause(void) { if (!g_EmulatorRunning) return; if (netplay_is_init()) return; if (g_rom_pause) { DebugMessage(M64MSG_STATUS, "Emulation continued."); if(l_msgPause) { osd_delete_message(l_msgPause); l_msgPause = NULL; } StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING); } else { if(l_msgPause) osd_delete_message(l_msgPause); DebugMessage(M64MSG_STATUS, "Emulation paused."); l_msgPause = osd_new_message(OSD_MIDDLE_CENTER, "Paused"); osd_message_set_static(l_msgPause); osd_message_set_user_managed(l_msgPause); StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED); } g_rom_pause = !g_rom_pause; l_FrameAdvance = 0; } void main_advance_one(void) { l_FrameAdvance = 1; g_rom_pause = 0; StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING); } static void main_draw_volume_osd(void) { char msgString[64]; const char *volString; // this calls into the audio plugin volString = audio.volumeGetString(); if (volString == NULL) { strcpy(msgString, "Volume Not Supported."); } else { sprintf(msgString, "%s: %s", "Volume", volString); } // create a new message or update an existing one if (l_msgVol != NULL) osd_update_message(l_msgVol, "%s", msgString); else { l_msgVol = osd_new_message(OSD_MIDDLE_CENTER, "%s", msgString); osd_message_set_user_managed(l_msgVol); } } /* this function could be called as a result of a keypress, joystick/button movement, LIRC command, or 'testshots' command-line option timer */ void main_take_next_screenshot(void) { l_TakeScreenshot = l_CurrentFrame + 1; } void main_state_set_slot(int slot) { if (slot < 0 || slot > 9) { DebugMessage(M64MSG_WARNING, "Invalid savestate slot '%i' in main_state_set_slot(). Using 0", slot); slot = 0; } savestates_select_slot(slot); } void main_state_inc_slot(void) { savestates_inc_slot(); } void main_state_load(const char *filename) { if (netplay_is_init()) return; if (filename == NULL) // Save to slot savestates_set_job(savestates_job_load, savestates_type_m64p, NULL); else savestates_set_job(savestates_job_load, savestates_type_unknown, filename); } void main_state_save(int format, const char *filename) { if (netplay_is_init()) return; if (filename == NULL) // Save to slot savestates_set_job(savestates_job_save, savestates_type_m64p, NULL); else // Save to file savestates_set_job(savestates_job_save, (savestates_type)format, filename); } m64p_error main_core_state_query(m64p_core_param param, int *rval) { switch (param) { case M64CORE_EMU_STATE: if (!g_EmulatorRunning) *rval = M64EMU_STOPPED; else if (g_rom_pause) *rval = M64EMU_PAUSED; else *rval = M64EMU_RUNNING; break; case M64CORE_VIDEO_MODE: if (!VidExt_VideoRunning()) *rval = M64VIDEO_NONE; else if (VidExt_InFullscreenMode()) *rval = M64VIDEO_FULLSCREEN; else *rval = M64VIDEO_WINDOWED; break; case M64CORE_SAVESTATE_SLOT: *rval = savestates_get_slot(); break; case M64CORE_SPEED_FACTOR: *rval = l_SpeedFactor; break; case M64CORE_SPEED_LIMITER: *rval = l_MainSpeedLimit; break; case M64CORE_VIDEO_SIZE: { int width, height; if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; main_get_screen_size(&width, &height); *rval = (width << 16) + height; break; } case M64CORE_AUDIO_VOLUME: { if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; return main_volume_get_level(rval); } case M64CORE_AUDIO_MUTE: *rval = main_volume_get_muted(); break; case M64CORE_INPUT_GAMESHARK: *rval = event_gameshark_active(); break; // these are only used for callbacks; they cannot be queried or set case M64CORE_SCREENSHOT_CAPTURED: case M64CORE_STATE_LOADCOMPLETE: case M64CORE_STATE_SAVECOMPLETE: return M64ERR_INPUT_INVALID; default: return M64ERR_INPUT_INVALID; } return M64ERR_SUCCESS; } m64p_error main_core_state_set(m64p_core_param param, int val) { switch (param) { case M64CORE_EMU_STATE: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; if (val == M64EMU_STOPPED) { /* this stop function is asynchronous. The emulator may not terminate until later */ main_stop(); return M64ERR_SUCCESS; } else if (val == M64EMU_RUNNING) { if (main_is_paused()) main_toggle_pause(); return M64ERR_SUCCESS; } else if (val == M64EMU_PAUSED) { if (!main_is_paused()) main_toggle_pause(); return M64ERR_SUCCESS; } return M64ERR_INPUT_INVALID; case M64CORE_VIDEO_MODE: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; if (val == M64VIDEO_WINDOWED) { if (VidExt_InFullscreenMode()) gfx.changeWindow(); return M64ERR_SUCCESS; } else if (val == M64VIDEO_FULLSCREEN) { if (!VidExt_InFullscreenMode()) gfx.changeWindow(); return M64ERR_SUCCESS; } return M64ERR_INPUT_INVALID; case M64CORE_SAVESTATE_SLOT: if (val < 0 || val > 9) return M64ERR_INPUT_INVALID; savestates_select_slot(val); return M64ERR_SUCCESS; case M64CORE_SPEED_FACTOR: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; main_speedset(val); return M64ERR_SUCCESS; case M64CORE_SPEED_LIMITER: main_set_speedlimiter(val); return M64ERR_SUCCESS; case M64CORE_VIDEO_SIZE: { // the front-end app is telling us that the user has resized the video output frame, and so // we should try to update the video plugin accordingly. First, check state int width, height; if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; width = (val >> 16) & 0xffff; height = val & 0xffff; // then call the video plugin. if the video plugin supports resizing, it will resize its viewport and call // VidExt_ResizeWindow to update the window manager handling our opengl output window gfx.resizeVideoOutput(width, height); return M64ERR_SUCCESS; } case M64CORE_AUDIO_VOLUME: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; if (val < 0 || val > 100) return M64ERR_INPUT_INVALID; return main_volume_set_level(val); case M64CORE_AUDIO_MUTE: if ((main_volume_get_muted() && !val) || (!main_volume_get_muted() && val)) return main_volume_mute(); return M64ERR_SUCCESS; case M64CORE_INPUT_GAMESHARK: if (!g_EmulatorRunning) return M64ERR_INVALID_STATE; event_set_gameshark(val); return M64ERR_SUCCESS; // these are only used for callbacks; they cannot be queried or set case M64CORE_STATE_LOADCOMPLETE: case M64CORE_STATE_SAVECOMPLETE: return M64ERR_INPUT_INVALID; default: return M64ERR_INPUT_INVALID; } } m64p_error main_get_screen_size(int *width, int *height) { gfx.readScreen(NULL, width, height, 0); return M64ERR_SUCCESS; } m64p_error main_read_screen(void *pixels, int bFront) { int width_trash, height_trash; gfx.readScreen(pixels, &width_trash, &height_trash, bFront); return M64ERR_SUCCESS; } m64p_error main_volume_up(void) { int level = 0; audio.volumeUp(); main_draw_volume_osd(); main_volume_get_level(&level); StateChanged(M64CORE_AUDIO_VOLUME, level); return M64ERR_SUCCESS; } m64p_error main_volume_down(void) { int level = 0; audio.volumeDown(); main_draw_volume_osd(); main_volume_get_level(&level); StateChanged(M64CORE_AUDIO_VOLUME, level); return M64ERR_SUCCESS; } m64p_error main_volume_get_level(int *level) { *level = audio.volumeGetLevel(); return M64ERR_SUCCESS; } m64p_error main_volume_set_level(int level) { audio.volumeSetLevel(level); main_draw_volume_osd(); level = audio.volumeGetLevel(); StateChanged(M64CORE_AUDIO_VOLUME, level); return M64ERR_SUCCESS; } m64p_error main_volume_mute(void) { audio.volumeMute(); main_draw_volume_osd(); StateChanged(M64CORE_AUDIO_MUTE, main_volume_get_muted()); return M64ERR_SUCCESS; } int main_volume_get_muted(void) { return (audio.volumeGetLevel() == 0); } m64p_error main_reset(int do_hard_reset) { if (do_hard_reset) { hard_reset_device(&g_dev); } else { soft_reset_device(&g_dev); } return M64ERR_SUCCESS; } /********************************************************************************************************* * global functions, callbacks from the r4300 core or from other plugins */ static void video_plugin_render_callback(int bScreenRedrawn) { #ifdef M64P_OSD int bOSD = ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"); #endif /* M64P_OSD */ // if the flag is set to take a screenshot, then grab it now if (l_TakeScreenshot != 0) { // if the OSD is enabled, and the screen has not been recently redrawn, then we cannot take a screenshot now because // it contains the OSD text. Wait until the next redraw #ifdef M64P_OSD if (!bOSD || bScreenRedrawn) #endif /* M64P_OSD */ { TakeScreenshot(l_TakeScreenshot - 1); // current frame number +1 is in l_TakeScreenshot l_TakeScreenshot = 0; // reset flag } } #ifdef M64P_OSD // if the OSD is enabled, then draw it now if (bOSD) { osd_render(); } #endif /* M64P_OSD */ // if the input plugin specified a render callback, call it now if(input.renderCallback) { input.renderCallback(); } } void new_frame(void) { if (g_FrameCallback != NULL) (*g_FrameCallback)(l_CurrentFrame); /* advance the current frame */ l_CurrentFrame++; if (l_FrameAdvance) { g_rom_pause = 1; l_FrameAdvance = 0; StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED); } } static void apply_speed_limiter(void) { static unsigned long totalVIs = 0; static int resetOnce = 0; static int lastSpeedFactor = 100; static unsigned int StartFPSTime = 0; static const double defaultSpeedFactor = 100.0; unsigned int CurrentFPSTime = SDL_GetTicks(); // calculate frame duration based upon ROM setting (50/60hz) and mupen64plus speed adjustment const double VILimitMilliseconds = 1000.0 / g_dev.vi.expected_refresh_rate; const double SpeedFactorMultiple = defaultSpeedFactor/l_SpeedFactor; const double AdjustedLimit = VILimitMilliseconds * SpeedFactorMultiple; //if this is the first time or we are resuming from pause if(StartFPSTime == 0 || !resetOnce || lastSpeedFactor != l_SpeedFactor) { StartFPSTime = CurrentFPSTime; totalVIs = 0; resetOnce = 1; } else { ++totalVIs; } lastSpeedFactor = l_SpeedFactor; #if defined(PROFILE) timed_section_start(TIMED_SECTION_IDLE); #endif #ifdef DBG if(g_DebuggerActive) DebuggerCallback(DEBUG_UI_VI, 0); #endif double totalElapsedGameTime = AdjustedLimit*totalVIs; double elapsedRealTime = CurrentFPSTime - StartFPSTime; double sleepTime = totalElapsedGameTime - elapsedRealTime; //Reset if the sleep needed is an unreasonable value static const double minSleepNeeded = -50; static const double maxSleepNeeded = 50; if(sleepTime < minSleepNeeded || sleepTime > (maxSleepNeeded*SpeedFactorMultiple)) { resetOnce = 0; } if (sleepTime < minSleepNeeded) { totalVIs += (unsigned long)(minSleepNeeded/AdjustedLimit); } if(l_MainSpeedLimit && sleepTime > 0 && sleepTime < maxSleepNeeded*SpeedFactorMultiple) { while(sleepTime >= 0) { SDL_Delay((unsigned int) sleepTime); CurrentFPSTime = SDL_GetTicks(); elapsedRealTime = CurrentFPSTime - StartFPSTime; sleepTime = totalElapsedGameTime - elapsedRealTime; } } #if defined(PROFILE) timed_section_end(TIMED_SECTION_IDLE); #endif } /* TODO: make a GameShark module and move that there */ static void gs_apply_cheats(struct cheat_ctx* ctx) { struct r4300_core* r4300 = &g_dev.r4300; if (g_gs_vi_counter < 60) { if (g_gs_vi_counter == 0) cheat_apply_cheats(ctx, r4300, ENTRY_BOOT); g_gs_vi_counter++; } else { cheat_apply_cheats(ctx, r4300, ENTRY_VI); } } static void pause_loop(void) { if(g_rom_pause) { osd_render(); // draw Paused message in case gfx.updateScreen didn't do it VidExt_GL_SwapBuffers(); while(g_rom_pause) { SDL_Delay(10); main_check_inputs(); } } } /* called on vertical interrupt. * Allow the core to perform various things */ void new_vi(void) { #if defined(PROFILE) timed_sections_refresh(); #endif gs_apply_cheats(&g_cheat_ctx); apply_speed_limiter(); main_check_inputs(); pause_loop(); netplay_check_sync(&g_dev.r4300.cp0); } static void main_switch_pak(int control_id) { struct game_controller* cont = &g_dev.controllers[control_id]; change_pak(cont, l_paks[control_id][l_paks_idx[control_id]], l_ipaks[l_paks_idx[control_id]]); if (cont->ipak != NULL) { DebugMessage(M64MSG_INFO, "Controller %u pak changed to %s", control_id, cont->ipak->name); } else { DebugMessage(M64MSG_INFO, "Removing pak from controller %u", control_id); } } void main_switch_next_pak(int control_id) { if (l_ipaks[l_paks_idx[control_id]] == NULL || ++l_paks_idx[control_id] >= PAK_MAX_SIZE) { l_paks_idx[control_id] = 0; } main_switch_pak(control_id); } void main_switch_plugin_pak(int control_id) { //Don't switch to the selected pak if it's not available for the game if (l_ipaks[l_pak_type_idx[Controls[control_id].Plugin]] == NULL) { Controls[control_id].Plugin = PLUGIN_NONE; } l_paks_idx[control_id] = l_pak_type_idx[Controls[control_id].Plugin]; main_switch_pak(control_id); } static void open_mpk_file(struct file_storage* fstorage) { unsigned int i; int ret = open_file_storage(fstorage, GAME_CONTROLLERS_COUNT*MEMPAK_SIZE, get_mempaks_path()); if (ret == (int)file_open_error) { /* if file doesn't exists provide default content */ for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { /* Generate a random serial ID */ uint32_t serial[6]; size_t k; for (k = 0; k < 6; ++k) { serial[k] = xoshiro256pp_next(&l_mpk_idgen); } format_mempak(fstorage->data + i * MEMPAK_SIZE, serial, DEFAULT_MEMPAK_DEVICEID, DEFAULT_MEMPAK_BANKS, DEFAULT_MEMPAK_VERSION); } } } static void open_fla_file(struct file_storage* fstorage) { int ret = open_file_storage(fstorage, FLASHRAM_SIZE, get_flashram_path()); if (ret == (int)file_open_error) { /* if file doesn't exists provide default content */ format_flashram(fstorage->data); } } static void open_sra_file(struct file_storage* fstorage) { int ret = open_file_storage(fstorage, SRAM_SIZE, get_sram_path()); if (ret == (int)file_open_error) { /* if file doesn't exists provide default content */ format_sram(fstorage->data); } } static void open_eep_file(struct file_storage* fstorage) { /* Note: EEP files are all EEPROM_MAX_SIZE bytes long, * whatever the real EEPROM size is. */ enum { EEPROM_MAX_SIZE = 0x800 }; int ret = open_file_storage(fstorage, EEPROM_MAX_SIZE, get_eeprom_path()); if (ret == (int)file_open_error) { /* if file doesn't exists provide default content */ format_eeprom(fstorage->data, EEPROM_MAX_SIZE); } /* Truncate to 4k bit if necessary */ if (ROM_SETTINGS.savetype != SAVETYPE_EEPROM_16K) { fstorage->size = 0x200; } } static void load_dd_rom(uint8_t* rom, size_t* rom_size, uint8_t* disk_region) { /* set the DD rom region */ if (g_media_loader.set_dd_rom_region != NULL) { g_media_loader.set_dd_rom_region(g_media_loader.cb_data, *disk_region); } /* ask the core loader for DD disk filename */ char* dd_ipl_rom_filename = (g_media_loader.get_dd_rom == NULL) ? NULL : g_media_loader.get_dd_rom(g_media_loader.cb_data); if ((dd_ipl_rom_filename == NULL) || (strlen(dd_ipl_rom_filename) == 0)) { goto no_dd; } struct file_storage dd_rom; memset(&dd_rom, 0, sizeof(dd_rom)); if (open_rom_file_storage(&dd_rom, dd_ipl_rom_filename) != file_ok) { DebugMessage(M64MSG_ERROR, "Failed to load DD IPL ROM: %s. Disabling 64DD", dd_ipl_rom_filename); goto no_dd; } DebugMessage(M64MSG_INFO, "DD IPL ROM: %s", dd_ipl_rom_filename); /* load and swap DD IPL ROM */ *rom_size = g_ifile_storage_ro.size(&dd_rom); memcpy(rom, g_ifile_storage_ro.data(&dd_rom), *rom_size); close_file_storage(&dd_rom); /* fetch 1st word to identify IPL ROM format */ /* FIXME: use more robust ROM detection heuristic - do the same for regular ROMs */ uint32_t pi_bsd_dom1_config = 0 | ((uint32_t)rom[0] << 24) | ((uint32_t)rom[1] << 16) | ((uint32_t)rom[2] << 8) | ((uint32_t)rom[3] << 0); switch (pi_bsd_dom1_config) { case 0x80270740: /* Z64 - big endian */ to_big_endian_buffer(rom, 4, *rom_size/4); break; case 0x40072780: /* N64 - little endian */ to_little_endian_buffer(rom, 4, *rom_size/4); break; case 0x27804007: /* V64 - bi-endian */ swap_buffer(rom, 2, *rom_size/2); break; default: /* unknown */ DebugMessage(M64MSG_ERROR, "Invalid DD IPL ROM: Disabling 64DD."); *rom_size = 0; return; } return; no_dd: free(dd_ipl_rom_filename); *rom_size = 0; } static int load_dd_disk(struct dd_disk* dd_disk, const struct storage_backend_interface** dd_idisk) { /* ask the core loader for DD disk filename */ char* dd_disk_filename = (g_media_loader.get_dd_disk == NULL) ? NULL : g_media_loader.get_dd_disk(g_media_loader.cb_data); /* handle the no disk case */ if (dd_disk_filename == NULL || strlen(dd_disk_filename) == 0) { goto no_disk; } /* Get DD Disk size */ size_t dd_size = 0; if (get_file_size(dd_disk_filename, &dd_size) != file_ok) { DebugMessage(M64MSG_ERROR, "Can't get DD disk file size"); goto no_disk; } struct file_storage* fstorage = malloc(sizeof(struct file_storage)); struct file_storage* fstorage_save = malloc(sizeof(struct file_storage)); if (fstorage == NULL || fstorage_save == NULL) { DebugMessage(M64MSG_ERROR, "Failed to allocate DD file_storage"); if (fstorage != NULL) { free(fstorage); fstorage = NULL; } if (fstorage_save != NULL) { free(fstorage_save); fstorage_save = NULL; } goto no_disk; } /* Determine disk save format */ int save_format = ConfigGetParamInt(g_CoreConfig, "SaveDiskFormat"); /* MAME disks only support full disk save */ if (dd_size == MAME_FORMAT_DUMP_SIZE && save_format != 0) { DebugMessage(M64MSG_WARNING, "MAME disks only support full disk save format, switching to full disk format !"); save_format = 0; } /* Determine save file name */ char* save_filename = get_dd_disk_save_path(namefrompath(dd_disk_filename), save_format); if (save_filename == NULL) { DebugMessage(M64MSG_ERROR, "Failed to get DD save path, DD will be read-only."); save_format = -1; } /* Try loading *.{nd,d6}r file first (if SaveDiskFormat == 0) */ if (save_format == 0) { if (open_rom_file_storage(fstorage, save_filename) != file_ok) { DebugMessage(M64MSG_WARNING, "Failed to load DD Disk save: %s.", save_filename); /* Try loading regular disk file */ if (open_rom_file_storage(fstorage, dd_disk_filename) != file_ok) { DebugMessage(M64MSG_ERROR, "Failed to load DD Disk: %s.", dd_disk_filename); goto free_fstorage; } } } else { /* Try loading regular disk file */ if (open_rom_file_storage(fstorage, dd_disk_filename) != file_ok) { DebugMessage(M64MSG_ERROR, "Failed to load DD Disk: %s.", dd_disk_filename); goto free_fstorage; } } /* Force fstorage to point to save_filename, to redirect all writes to save file, * (and to avoid corrupting 64DD dump) * save_filename is now owned by fstorage. * dd_disk_filename is not owned anymore and must be freed individually. */ fstorage->filename = save_filename; /* Scan disk to deduce disk format and other parameters and expand its size for D64 */ unsigned int format = 0; unsigned int development = 0; size_t offset_sys = 0; size_t offset_id = 0; size_t offset_ram = 0; size_t size_ram = 0; uint8_t* new_data = scan_and_expand_disk_format(fstorage->data, fstorage->size, &format, &development, &offset_sys, &offset_id, &offset_ram, &size_ram); if (new_data == NULL) { DebugMessage(M64MSG_ERROR, "Wrong disk format"); goto wrong_disk_format; } else { fstorage->data = new_data; } /* Load RAM save data (if SaveDiskFormat == 1) */ if (save_format == 1) { if (read_from_file(save_filename, &fstorage->data[offset_ram], size_ram) != file_ok) { DebugMessage(M64MSG_WARNING, "Failed to load DD Disk RAM area (*.ram): %s.", save_filename); } } switch(save_format) { case 0: /* Full disk */ *dd_idisk = &g_istorage_disk_full; fstorage_save->filename = save_filename; fstorage_save->data = fstorage->data; fstorage_save->size = fstorage->size; fstorage_save->first_access = 1; break; case 1: /* RAM only */ *dd_idisk = &g_istorage_disk_ram_only; fstorage_save->filename = save_filename; fstorage_save->data = &fstorage->data[offset_ram]; fstorage_save->size = size_ram; fstorage_save->first_access = 1; break; default: /* read only */ *dd_idisk = &g_istorage_disk_read_only; free(fstorage_save); fstorage_save = NULL; } /* Setup dd_disk */ dd_disk->storage = fstorage; dd_disk->istorage = &g_ifile_storage_ro; dd_disk->save_storage = fstorage_save; dd_disk->isave_storage = (save_format >= 0) ? &g_ifile_storage : NULL; dd_disk->format = format; dd_disk->development = development; dd_disk->region = DDREGION_UNKNOWN; dd_disk->offset_sys = offset_sys; dd_disk->offset_id = offset_id; dd_disk->offset_ram = offset_ram; /* Generate LBA conversion table */ GenerateLBAToPhysTable(dd_disk); DebugMessage(M64MSG_INFO, "DD Disk: %s - %zu - %s", dd_disk_filename, (*dd_idisk)->size(dd_disk), get_disk_format_name(format)); /* Get region from disk and byteswap it as needed */ uint32_t w = *(uint32_t*)(*dd_idisk)->data(dd_disk); if (dd_disk->format == DISK_FORMAT_SDK) { swap_buffer(&w, sizeof(w), 1); } /* Set region in dd_disk */ if (w == DD_REGION_DV || development) { dd_disk->region = DDREGION_DEV; } else if (w == DD_REGION_JP) { dd_disk->region = DDREGION_JAPAN; } else if (w == DD_REGION_US) { dd_disk->region = DDREGION_US; } if (w == DD_REGION_JP || w == DD_REGION_US || w == DD_REGION_DV) { DebugMessage(M64MSG_WARNING, "Loading a saved disk"); } free(dd_disk_filename); return 1; wrong_disk_format: /* no need to close save_storage as it is a child of disk->storage */ close_file_storage(fstorage); free_fstorage: free(fstorage); free(fstorage_save); no_disk: free(dd_disk_filename); *dd_idisk = NULL; return 0; } static void close_dd_disk(struct dd_disk* disk) { if (disk->save_storage != NULL) { /* no need to close save_storage as it is a child of disk->storage */ free(disk->save_storage); disk->save_storage = NULL; } if (disk->storage != NULL) { close_file_storage(disk->storage); free(disk->storage); disk->storage = NULL; } } struct gb_cart_data { int control_id; struct file_storage rom_fstorage; struct file_storage ram_fstorage; void* gbcam_backend; const struct video_capture_backend_interface* igbcam_backend; }; static struct gb_cart_data l_gb_carts_data[GAME_CONTROLLERS_COUNT]; static void init_gb_rom(void* opaque, void** storage, const struct storage_backend_interface** istorage) { struct gb_cart_data* data = (struct gb_cart_data*)opaque; /* Ask the core loader for rom filename */ char* rom_filename = (g_media_loader.get_gb_cart_rom == NULL) ? NULL : g_media_loader.get_gb_cart_rom(g_media_loader.cb_data, data->control_id); /* Handle the no cart case */ if (rom_filename == NULL || strlen(rom_filename) == 0) { goto no_cart; } /* Open ROM file */ if (open_rom_file_storage(&data->rom_fstorage, rom_filename) != file_ok) { DebugMessage(M64MSG_ERROR, "Failed to load ROM file: %s", rom_filename); goto no_cart; } DebugMessage(M64MSG_INFO, "GB Loader ROM: %s - %zu", data->rom_fstorage.filename, data->rom_fstorage.size); /* init GB ROM storage */ *storage = &data->rom_fstorage; *istorage = &g_ifile_storage_ro; return; no_cart: free(rom_filename); *storage = NULL; *istorage = NULL; } static void release_gb_rom(void* opaque) { struct gb_cart_data* data = (struct gb_cart_data*)opaque; close_file_storage(&data->rom_fstorage); memset(&data->rom_fstorage, 0, sizeof(data->rom_fstorage)); } static void init_gb_ram(void* opaque, size_t ram_size, void** storage, const struct storage_backend_interface** istorage) { struct gb_cart_data* data = (struct gb_cart_data*)opaque; /* Ask the core loader for ram filename */ char* ram_filename = (g_media_loader.get_gb_cart_ram == NULL) ? NULL : g_media_loader.get_gb_cart_ram(g_media_loader.cb_data, data->control_id); /* Handle the no RAM case * if NULL or empty string generate a filename */ if (ram_filename == NULL || strlen(ram_filename) == 0) { free(ram_filename); ram_filename = get_gb_ram_path(namefrompath(data->rom_fstorage.filename), data->control_id+1); } /* Open RAM file * if file doesn't exists provide default content */ int err = open_file_storage(&data->ram_fstorage, ram_size, ram_filename); if (err == file_open_error) { memset(data->ram_fstorage.data, 0, data->ram_fstorage.size); DebugMessage(M64MSG_INFO, "Providing default RAM content"); } else if (err == file_read_error) { DebugMessage(M64MSG_WARNING, "Size mismatch between expected RAM size and effective file size"); } DebugMessage(M64MSG_INFO, "GB Loader RAM: %s - %zu", data->ram_fstorage.filename, data->ram_fstorage.size); /* init GB RAM storage */ *storage = &data->ram_fstorage; *istorage = &g_ifile_storage; } static void release_gb_ram(void* opaque) { struct gb_cart_data* data = (struct gb_cart_data*)opaque; close_file_storage(&data->ram_fstorage); memset(&data->ram_fstorage, 0, sizeof(data->ram_fstorage)); } void main_change_gb_cart(int control_id) { struct transferpak* tpk = &g_dev.transferpaks[control_id]; struct gb_cart* gb_cart = &g_dev.gb_carts[control_id]; struct gb_cart_data* data = &l_gb_carts_data[control_id]; /* reset gb_cart_data */ memset(data, 0, sizeof(*data)); data->control_id = control_id; init_gb_cart(gb_cart, data, init_gb_rom, release_gb_rom, data, init_gb_ram, release_gb_ram, NULL, &g_iclock_ctime_plus_delta, &data->control_id, &g_irumble_backend_plugin_compat, data->gbcam_backend, data->igbcam_backend); if (gb_cart->read_gb_cart == NULL) { gb_cart = NULL; } change_gb_cart(tpk, gb_cart); if (tpk->gb_cart != NULL) { const uint8_t* rom_data = gb_cart->irom_storage->data(gb_cart->rom_storage); DebugMessage(M64MSG_INFO, "Inserting GB cart %s into transferpak %u", rom_data + 0x134, control_id); } else { DebugMessage(M64MSG_INFO, "Removing GB cart from transferpak %u", control_id); } } /********************************************************************************************************* * emulation thread - runs the core */ m64p_error main_run(void) { size_t i, k; size_t rdram_size; uint32_t count_per_op; uint32_t count_per_op_denom_pot; uint32_t emumode; uint32_t disable_extra_mem; int32_t si_dma_duration; int32_t no_compiled_jump; int32_t randomize_interrupt; struct file_storage eep; struct file_storage fla; struct file_storage sra; size_t dd_rom_size; struct dd_disk dd_disk; m64p_error failure_rval; int control_ids[GAME_CONTROLLERS_COUNT]; struct controller_input_compat cin_compats[GAME_CONTROLLERS_COUNT]; struct file_storage mpk_storages[GAME_CONTROLLERS_COUNT]; struct file_storage mpk; void* gbcam_backend; const struct video_capture_backend_interface* igbcam_backend; /* XXX: select type of flashram from db */ uint32_t flashram_type = MX29L1100_ID; uint16_t eeprom_type = JDT_NONE; switch (ROM_SETTINGS.savetype) { case SAVETYPE_EEPROM_4K: eeprom_type = JDT_EEPROM_4K; break; case SAVETYPE_EEPROM_16K: eeprom_type = JDT_EEPROM_16K; break; } /* Seed MPK ID gen using current time */ uint64_t mpk_seed = !netplay_is_init() ? (uint64_t)time(NULL) : 0; l_mpk_idgen = xoshiro256pp_seed(mpk_seed); /* take the r4300 emulator mode from the config file at this point and cache it in a global variable */ emumode = ConfigGetParamInt(g_CoreConfig, "R4300Emulator"); /* set some other core parameters based on the config file values */ savestates_set_autoinc_slot(ConfigGetParamBool(g_CoreConfig, "AutoStateSlotIncrement")); savestates_select_slot(ConfigGetParamInt(g_CoreConfig, "CurrentStateSlot")); no_compiled_jump = ConfigGetParamBool(g_CoreConfig, "NoCompiledJump"); //We disable any randomness for netplay randomize_interrupt = !netplay_is_init() ? ConfigGetParamBool(g_CoreConfig, "RandomizeInterrupt") : 0; count_per_op = ConfigGetParamInt(g_CoreConfig, "CountPerOp"); count_per_op_denom_pot = ConfigGetParamInt(g_CoreConfig, "CountPerOpDenomPot"); if (ROM_SETTINGS.disableextramem) disable_extra_mem = ROM_SETTINGS.disableextramem; else disable_extra_mem = ConfigGetParamInt(g_CoreConfig, "DisableExtraMem"); if (count_per_op <= 0) count_per_op = ROM_SETTINGS.countperop; if (count_per_op_denom_pot > 20) count_per_op_denom_pot = 20; si_dma_duration = ConfigGetParamInt(g_CoreConfig, "SiDmaDuration"); if (si_dma_duration < 0) si_dma_duration = ROM_SETTINGS.sidmaduration; //During netplay, player 1 is the source of truth for these settings netplay_sync_settings(&count_per_op, &count_per_op_denom_pot, &disable_extra_mem, &si_dma_duration, &emumode, &no_compiled_jump); rdram_size = (disable_extra_mem == 0) ? 0x800000 : 0x400000; cheat_add_hacks(&g_cheat_ctx, ROM_PARAMS.cheats); /* do byte-swapping if it hasn't been done yet */ #if !defined(M64P_BIG_ENDIAN) if (g_RomWordsLittleEndian == 0) { swap_buffer((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM), 4, g_rom_size/4); g_RomWordsLittleEndian = 1; } #endif /* Fill-in l_pak_type_idx and l_ipaks according to game compatibility */ k = 0; if (ROM_SETTINGS.biopak) { l_ipaks[k++] = &g_ibiopak; } if (ROM_SETTINGS.mempak) { l_pak_type_idx[PLUGIN_MEMPAK] = k; l_ipaks[k] = &g_imempak; ++k; } if (ROM_SETTINGS.rumble) { l_pak_type_idx[PLUGIN_RUMBLE_PAK] = k; l_pak_type_idx[PLUGIN_RAW] = k; l_ipaks[k] = &g_irumblepak; ++k; } if (ROM_SETTINGS.transferpak) { l_pak_type_idx[PLUGIN_TRANSFER_PAK] = k; l_ipaks[k] = &g_itransferpak; ++k; } l_pak_type_idx[PLUGIN_NONE] = k; l_ipaks[k] = NULL; if (!ROM_SETTINGS.mempak) { l_pak_type_idx[PLUGIN_MEMPAK] = k; } if (!ROM_SETTINGS.rumble) { l_pak_type_idx[PLUGIN_RUMBLE_PAK] = k; l_pak_type_idx[PLUGIN_RAW] = k; } if (!ROM_SETTINGS.transferpak) { l_pak_type_idx[PLUGIN_TRANSFER_PAK] = k; } /* init GbCamera backend specified in the configuration file */ init_video_capture_backend(&igbcam_backend, &gbcam_backend, g_CoreConfig, "GbCameraVideoCaptureBackend1"); /* open GB cam video device */ igbcam_backend->open(gbcam_backend, M64282FP_SENSOR_W, M64282FP_SENSOR_H); /* open storage files, provide default content if not present */ open_mpk_file(&mpk); open_eep_file(&eep); open_fla_file(&fla); open_sra_file(&sra); /* Load 64DD IPL ROM and Disk */ const struct clock_backend_interface* dd_rtc_iclock = NULL; const struct storage_backend_interface* dd_idisk = NULL; memset(&dd_disk, 0, sizeof(dd_disk)); /* try to load DD disk first, if that succeeds, pass the region to load_dd_rom */ if (load_dd_disk(&dd_disk, &dd_idisk)) { dd_rtc_iclock = &g_iclock_ctime_plus_delta; load_dd_rom((uint8_t*)mem_base_u32(g_mem_base, MM_DD_ROM), &dd_rom_size, &dd_disk.region); } else { dd_rom_size = 0; } /* ensure the 64DD rom & disk are loaded, * otherwise we have to bail right now */ if (g_rom_size == 0 && dd_rom_size == 0) { goto on_disk_failure; } /* setup pif channel devices */ void* joybus_devices[PIF_CHANNELS_COUNT]; const struct joybus_device_interface* ijoybus_devices[PIF_CHANNELS_COUNT]; memset(&g_dev.gb_carts, 0, GAME_CONTROLLERS_COUNT*sizeof(*g_dev.gb_carts)); memset(&l_gb_carts_data, 0, GAME_CONTROLLERS_COUNT*sizeof(*l_gb_carts_data)); memset(cin_compats, 0, GAME_CONTROLLERS_COUNT*sizeof(*cin_compats)); netplay_read_registration(cin_compats); for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { //During netplay, we "trick" the input plugin //by replacing the regular control_id with the ID that is controlling the player during netplay control_ids[i] = netplay_is_init() ? netplay_get_controller(i) : (int)i; /* if input plugin requests RawData let the input plugin do the channel device processing */ if (Controls[i].RawData) { joybus_devices[i] = &control_ids[i]; ijoybus_devices[i] = &g_ijoybus_device_plugin_compat; } else if (Controls[i].Type == CONT_TYPE_VRU) { const struct game_controller_flavor* cont_flavor = &g_vru_controller_flavor; joybus_devices[i] = &g_dev.controllers[i]; ijoybus_devices[i] = &g_ijoybus_vru_controller; cin_compats[i].control_id = (int)i; cin_compats[i].cont = &g_dev.controllers[i]; cin_compats[i].last_pak_type = Controls[i].Plugin; cin_compats[i].last_input = 0; cin_compats[i].netplay_count = 0; cin_compats[i].event_first = NULL; Controls[i].Plugin = PLUGIN_NONE; /* init vru_controller */ init_game_controller(&g_dev.controllers[i], cont_flavor, &cin_compats[i], &g_icontroller_input_backend_plugin_compat, NULL, NULL); } /* otherwise let the core do the processing */ else { /* select appropriate controller * FIXME: assume for now that only standard controller is compatible * Use the rom db to know if other peripherals are compatibles (VRU, mouse, train, ...) */ const struct game_controller_flavor* cont_flavor = &g_standard_controller_flavor; joybus_devices[i] = &g_dev.controllers[i]; ijoybus_devices[i] = &g_ijoybus_device_controller; cin_compats[i].control_id = (int)i; cin_compats[i].cont = &g_dev.controllers[i]; cin_compats[i].tpk = &g_dev.transferpaks[i]; cin_compats[i].last_pak_type = Controls[i].Plugin; cin_compats[i].last_input = 0; cin_compats[i].netplay_count = 0; cin_compats[i].event_first = NULL; l_gb_carts_data[i].control_id = (int)i; l_gb_carts_data[i].gbcam_backend = gbcam_backend; l_gb_carts_data[i].igbcam_backend = igbcam_backend; l_paks_idx[i] = 0; //Don't use the selected pak if it's not available for the game, instead use NONE if (l_ipaks[l_pak_type_idx[Controls[i].Plugin]] == NULL) { Controls[i].Plugin = PLUGIN_NONE; } /* init all compatibles paks */ for(k = 0; k < PAK_MAX_SIZE; ++k) { /* Bio Pak */ if (l_ipaks[k] == &g_ibiopak) { init_biopak(&g_dev.biopaks[i], 64); l_paks[i][k] = &g_dev.biopaks[i]; if (Controls[i].Plugin == PLUGIN_BIO_PAK) { l_paks_idx[i] = k; } } /* Memory Pak */ else if (l_ipaks[k] == &g_imempak) { mpk_storages[i].data = mpk.data + i * MEMPAK_SIZE; mpk_storages[i].size = MEMPAK_SIZE; mpk_storages[i].filename = (void*)&mpk; /* OK for isubfile_storage */ init_mempak(&g_dev.mempaks[i], &mpk_storages[i], &g_isubfile_storage); l_paks[i][k] = &g_dev.mempaks[i]; if (Controls[i].Plugin == PLUGIN_MEMPAK) { l_paks_idx[i] = k; } } /* Rumble Pak */ else if (l_ipaks[k] == &g_irumblepak) { init_rumblepak(&g_dev.rumblepaks[i], &control_ids[i], &g_irumble_backend_plugin_compat); l_paks[i][k] = &g_dev.rumblepaks[i]; if (Controls[i].Plugin == PLUGIN_RUMBLE_PAK || Controls[i].Plugin == PLUGIN_RAW) { l_paks_idx[i] = k; } } /* Transfer Pak */ else if (l_ipaks[k] == &g_itransferpak) { /* init GB cart */ init_gb_cart(&g_dev.gb_carts[i], &l_gb_carts_data[i], init_gb_rom, release_gb_rom, &l_gb_carts_data[i], init_gb_ram, release_gb_ram, NULL, &g_iclock_ctime_plus_delta, &l_gb_carts_data[i].control_id, &g_irumble_backend_plugin_compat, l_gb_carts_data[i].gbcam_backend, l_gb_carts_data[i].igbcam_backend); init_transferpak(&g_dev.transferpaks[i], (g_dev.gb_carts[i].read_gb_cart == NULL) ? NULL : &g_dev.gb_carts[i]); l_paks[i][k] = &g_dev.transferpaks[i]; if (Controls[i].Plugin == PLUGIN_TRANSFER_PAK) { l_paks_idx[i] = k; } /* enable GB cart switch */ cin_compats[i].gb_cart_switch_enabled = 1; } /* No Pak */ else { l_ipaks[k] = NULL; l_paks[i][k] = NULL; if (Controls[i].Plugin == PLUGIN_NONE) { l_paks_idx[i] = k; } break; } } /* init game_controller */ init_game_controller(&g_dev.controllers[i], cont_flavor, &cin_compats[i], &g_icontroller_input_backend_plugin_compat, l_paks[i][l_paks_idx[i]], l_ipaks[l_paks_idx[i]]); if (l_ipaks[l_paks_idx[i]] != NULL) { DebugMessage(M64MSG_INFO, "Game controller %u (%s) has a %s plugged in", (uint32_t) i, cont_flavor->name, l_ipaks[l_paks_idx[i]]->name); } else { DebugMessage(M64MSG_INFO, "Game controller %u (%s) has nothing plugged in", (uint32_t) i, cont_flavor->name); } } } for (i = GAME_CONTROLLERS_COUNT; i < PIF_CHANNELS_COUNT; ++i) { joybus_devices[i] = &g_dev.cart; ijoybus_devices[i] = &g_ijoybus_device_cart; } init_device(&g_dev, g_mem_base, emumode, count_per_op, count_per_op_denom_pot, no_compiled_jump, randomize_interrupt, g_start_address, &g_dev.ai, &g_iaudio_out_backend_plugin_compat, ((float)ROM_SETTINGS.aidmamodifier / 100.0), si_dma_duration, rdram_size, joybus_devices, ijoybus_devices, vi_clock_from_tv_standard(ROM_PARAMS.systemtype), vi_expected_refresh_rate_from_tv_standard(ROM_PARAMS.systemtype), NULL, &g_iclock_ctime_plus_delta, g_rom_size, eeprom_type, &eep, &g_ifile_storage, flashram_type, &fla, &g_ifile_storage, &sra, &g_ifile_storage, NULL, dd_rtc_iclock, dd_rom_size, &dd_disk, dd_idisk); // Attach rom to plugins failure_rval = M64ERR_PLUGIN_FAIL; if (!gfx.romOpen()) { goto on_gfx_open_failure; } if (!audio.romOpen()) { goto on_audio_open_failure; } if (!input.romOpen()) { goto on_input_open_failure; } /* set up the SDL key repeat and event filter to catch keyboard/joystick commands for the core */ event_initialize(); /* initialize frame counter */ l_CurrentFrame = 0; /* initialize the on-screen display */ if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay")) { // init on-screen display int width = 640, height = 480; gfx.readScreen(NULL, &width, &height, 0); // read screen to get width and height osd_init(width, height); } // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display gfx.setRenderingCallback(video_plugin_render_callback); #ifdef WITH_LIRC lircStart(); #endif // WITH_LIRC #ifdef DBG if (ConfigGetParamBool(g_CoreConfig, "EnableDebugger")) init_debugger(); #endif /* Startup message on the OSD */ osd_new_message(OSD_MIDDLE_CENTER, "Mupen64Plus Started..."); g_EmulatorRunning = 1; StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING); poweron_device(&g_dev); pif_bootrom_hle_execute(&g_dev.r4300); run_device(&g_dev); /* now begin to shut down */ #ifdef WITH_LIRC lircStop(); #endif // WITH_LIRC #ifdef DBG if (g_DebuggerActive) destroy_debugger(); #endif /* release gb_carts */ for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { if (!Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD) && g_dev.gb_carts[i].read_gb_cart != NULL) { release_gb_rom(&l_gb_carts_data[i]); release_gb_ram(&l_gb_carts_data[i]); } } igbcam_backend->close(gbcam_backend); igbcam_backend->release(gbcam_backend); close_file_storage(&sra); close_file_storage(&fla); close_file_storage(&eep); close_file_storage(&mpk); close_dd_disk(&dd_disk); /* reset pif */ close_pif(); if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay")) { osd_exit(); } rsp.romClosed(); input.romClosed(); audio.romClosed(); gfx.romClosed(); // clean up g_EmulatorRunning = 0; StateChanged(M64CORE_EMU_STATE, M64EMU_STOPPED); return M64ERR_SUCCESS; on_disk_failure: failure_rval = M64ERR_INVALID_STATE; rsp.romClosed(); input.romClosed(); on_input_open_failure: audio.romClosed(); on_audio_open_failure: gfx.romClosed(); on_gfx_open_failure: /* release gb_carts */ for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { if (!Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD) && g_dev.gb_carts[i].read_gb_cart != NULL) { release_gb_rom(&l_gb_carts_data[i]); release_gb_ram(&l_gb_carts_data[i]); } } igbcam_backend->close(gbcam_backend); igbcam_backend->release(gbcam_backend); /* release storage files */ close_file_storage(&sra); close_file_storage(&fla); close_file_storage(&eep); close_file_storage(&mpk); close_dd_disk(&dd_disk); /* reset pif */ close_pif(); return failure_rval; } void main_stop(void) { /* note: this operation is asynchronous. It may be called from a thread other than the main emulator thread, and may return before the emulator is completely stopped */ if (!g_EmulatorRunning) return; DebugMessage(M64MSG_STATUS, "Stopping emulation."); if(l_msgPause) { osd_delete_message(l_msgPause); l_msgPause = NULL; } if(l_msgFF) { osd_delete_message(l_msgFF); l_msgFF = NULL; } if(l_msgVol) { osd_delete_message(l_msgVol); l_msgVol = NULL; } if (g_rom_pause) { g_rom_pause = 0; StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING); } stop_device(&g_dev); #ifdef DBG if(g_DebuggerActive) { debugger_step(); } #endif } m64p_error open_pif(const unsigned char* pifimage, unsigned int size) { md5_byte_t old_pif_ntsc_md5[] = {0x49, 0x21, 0xD5, 0xF2, 0x16, 0x5D, 0xEE, 0x6E, 0x24, 0x96, 0xF4, 0x38, 0x8C, 0x4C, 0x81, 0xDA}; md5_byte_t old_pif_pal_md5[] = {0x2B, 0x6E, 0xEC, 0x58, 0x6F, 0xAA, 0x43, 0xF3, 0x46, 0x23, 0x33, 0xB8, 0x44, 0x83, 0x45, 0x54}; md5_byte_t pif_ntsc_md5[] = {0x5C, 0x12, 0x4E, 0x79, 0x48, 0xAD, 0xA8, 0x5D, 0xA6, 0x03, 0xA5, 0x22, 0x78, 0x29, 0x40, 0xD0}; md5_byte_t pif_pal_md5[] = {0xD4, 0x23, 0x2D, 0xC9, 0x35, 0xCA, 0xD0, 0x65, 0x0A, 0xC2, 0x66, 0x4D, 0x52, 0x28, 0x1F, 0x3A}; uint32_t *dst32 = mem_base_u32(g_mem_base, MM_PIF_MEM); uint32_t *src32 = (uint32_t*) pifimage; md5_state_t state; md5_byte_t digest[16]; md5_init(&state); md5_append(&state, (const md5_byte_t*)pifimage, size); md5_finish(&state, digest); if (memcmp(digest, old_pif_ntsc_md5, 16) == 0 || memcmp(digest, pif_ntsc_md5, 16) == 0) { DebugMessage(M64MSG_INFO, "Using NTSC PIF ROM"); } else if (memcmp(digest, old_pif_pal_md5, 16) == 0 || memcmp(digest, pif_pal_md5, 16) == 0) { DebugMessage(M64MSG_INFO, "Using PAL PIF ROM"); } else { DebugMessage(M64MSG_ERROR, "Invalid PIF ROM"); return M64ERR_INPUT_INVALID; } for (unsigned int i = 0; i < size; i += 4) *dst32++ = big32(*src32++); g_start_address = UINT32_C(0xbfc00000); return M64ERR_SUCCESS; } m64p_error close_pif(void) { g_start_address = UINT32_C(0xa4000040); return M64ERR_SUCCESS; } mupen64plus-core-src-2.6.0/src/main/main.h000066400000000000000000000073631464506436200202670ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - main.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 CasualJames * * Copyright (C) 2002 Blight * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __MAIN_H__ #define __MAIN_H__ #include #include "api/m64p_types.h" #include "main/cheat.h" #include "device/device.h" #include "osal/preproc.h" #if defined(__GNUC__) #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) #else #define ATTR_FMT(fmtpos, attrpos) #endif /* globals */ extern m64p_handle g_CoreConfig; extern int g_RomWordsLittleEndian; extern int g_EmulatorRunning; extern int g_rom_pause; extern struct cheat_ctx g_cheat_ctx; extern void* g_mem_base; extern struct device g_dev; extern m64p_media_loader g_media_loader; extern m64p_frame_callback g_FrameCallback; extern int g_gs_vi_counter; const char* get_savestatepath(void); const char* get_savesrampath(void); const char* get_savestatefilename(void); void new_frame(void); void new_vi(void); void main_switch_next_pak(int control_id); void main_switch_plugin_pak(int control_id); void main_change_gb_cart(int control_id); int main_set_core_defaults(void); void main_message(m64p_msg_level level, unsigned int osd_corner, const char *format, ...) ATTR_FMT(3, 4); m64p_error main_run(void); void main_stop(void); void main_toggle_pause(void); void main_advance_one(void); void main_speedup(int percent); void main_speeddown(int percent); void main_set_fastforward(int enable); void main_speedlimiter_toggle(void); void main_take_next_screenshot(void); void main_state_set_slot(int slot); void main_state_inc_slot(void); void main_state_load(const char *filename); void main_state_save(int format, const char *filename); m64p_error main_core_state_query(m64p_core_param param, int *rval); m64p_error main_core_state_set(m64p_core_param param, int val); m64p_error main_get_screen_size(int *width, int *height); m64p_error main_read_screen(void *pixels, int bFront); m64p_error main_volume_up(void); m64p_error main_volume_down(void); m64p_error main_volume_get_level(int *level); m64p_error main_volume_set_level(int level); m64p_error main_volume_mute(void); int main_volume_get_muted(void); m64p_error main_reset(int do_hard_reset); m64p_error open_pif(const unsigned char* pifimage, unsigned int size); m64p_error close_pif(void); #endif /* __MAIN_H__ */ mupen64plus-core-src-2.6.0/src/main/netplay.c000066400000000000000000000565611464506436200210160ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - netplay.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2020 loganmc10 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define SETTINGS_SIZE 24 #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "main.h" #include "util.h" #include "plugin/plugin.h" #include "backends/plugins_compat/plugins_compat.h" #include "netplay.h" #include #if !defined(WIN32) #include #endif static int l_canFF; static int l_netplay_controller; static int l_netplay_control[4]; static UDPsocket l_udpSocket; static TCPsocket l_tcpSocket; static int l_udpChannel; static int l_spectator; static int l_netplay_is_init = 0; static uint32_t l_vi_counter; static uint8_t l_status; static uint32_t l_reg_id; static struct controller_input_compat *l_cin_compats; static uint8_t l_plugin[4]; static uint8_t l_buffer_target; static uint8_t l_player_lag[4]; //UDP packet formats #define UDP_SEND_KEY_INFO 0 #define UDP_RECEIVE_KEY_INFO 1 #define UDP_REQUEST_KEY_INFO 2 #define UDP_RECEIVE_KEY_INFO_GRATUITOUS 3 #define UDP_SYNC_DATA 4 //TCP packet formats #define TCP_SEND_SAVE 1 #define TCP_RECEIVE_SAVE 2 #define TCP_SEND_SETTINGS 3 #define TCP_RECEIVE_SETTINGS 4 #define TCP_REGISTER_PLAYER 5 #define TCP_GET_REGISTRATION 6 #define TCP_DISCONNECT_NOTICE 7 struct __UDPSocket { int ready; int channel; }; #define CS4 32 m64p_error netplay_start(const char* host, int port) { if (SDLNet_Init() < 0) { DebugMessage(M64MSG_ERROR, "Netplay: Could not initialize SDL Net library"); return M64ERR_SYSTEM_FAIL; } l_udpSocket = SDLNet_UDP_Open(0); if (l_udpSocket == NULL) { DebugMessage(M64MSG_ERROR, "Netplay: UDP socket creation failed"); return M64ERR_SYSTEM_FAIL; } #if !defined(WIN32) const char tos_local = CS4 << 2; struct __UDPSocket* socket = (struct __UDPSocket*) l_udpSocket; setsockopt(socket->channel, IPPROTO_IP, IP_TOS, &tos_local, sizeof(tos_local)); #endif IPaddress dest; SDLNet_ResolveHost(&dest, host, port); l_udpChannel = SDLNet_UDP_Bind(l_udpSocket, -1, &dest); if (l_udpChannel < 0) { DebugMessage(M64MSG_ERROR, "Netplay: could not bind to UDP socket"); SDLNet_UDP_Close(l_udpSocket); l_udpSocket = NULL; return M64ERR_SYSTEM_FAIL; } l_tcpSocket = SDLNet_TCP_Open(&dest); if (l_tcpSocket == NULL) { DebugMessage(M64MSG_ERROR, "Netplay: could not bind to TCP socket"); SDLNet_UDP_Close(l_udpSocket); l_udpSocket = NULL; return M64ERR_SYSTEM_FAIL; } for (int i = 0; i < 4; ++i) { l_netplay_control[i] = -1; l_plugin[i] = 0; l_player_lag[i] = 0; } l_canFF = 0; l_netplay_controller = 0; l_netplay_is_init = 1; l_spectator = 1; l_vi_counter = 0; l_status = 0; l_reg_id = 0; return M64ERR_SUCCESS; } m64p_error netplay_stop() { if (l_udpSocket == NULL) return M64ERR_INVALID_STATE; else { if (l_cin_compats != NULL) { for (int i = 0; i < 4; ++i) { struct netplay_event* current = l_cin_compats[i].event_first; struct netplay_event* next; while (current != NULL) { next = current->next; free(current); current = next; } } } char output_data[5]; output_data[0] = TCP_DISCONNECT_NOTICE; SDLNet_Write32(l_reg_id, &output_data[1]); SDLNet_TCP_Send(l_tcpSocket, &output_data[0], 5); SDLNet_UDP_Unbind(l_udpSocket, l_udpChannel); SDLNet_UDP_Close(l_udpSocket); SDLNet_TCP_Close(l_tcpSocket); l_tcpSocket = NULL; l_udpSocket = NULL; l_udpChannel = -1; l_netplay_is_init = 0; SDLNet_Quit(); return M64ERR_SUCCESS; } } int netplay_is_init() { return l_netplay_is_init; } static uint8_t buffer_size(uint8_t control_id) { //This function returns the size of the local input buffer uint8_t counter = 0; struct netplay_event* current = l_cin_compats[control_id].event_first; while (current != NULL) { current = current->next; ++counter; } return counter; } static void netplay_request_input(uint8_t control_id) { UDPpacket *packet = SDLNet_AllocPacket(12); packet->data[0] = UDP_REQUEST_KEY_INFO; packet->data[1] = control_id; //The player we need input for SDLNet_Write32(l_reg_id, &packet->data[2]); //our registration ID SDLNet_Write32(l_cin_compats[control_id].netplay_count, &packet->data[6]); //the current event count packet->data[10] = l_spectator; //whether we are a spectator packet->data[11] = buffer_size(control_id); //our local buffer size packet->len = 12; SDLNet_UDP_Send(l_udpSocket, l_udpChannel, packet); SDLNet_FreePacket(packet); } static int check_valid(uint8_t control_id, uint32_t count) { //Check if we already have this event recorded locally, returns 1 if we do struct netplay_event* current = l_cin_compats[control_id].event_first; while (current != NULL) { if (current->count == count) //event already recorded return 1; current = current->next; } return 0; } static int netplay_require_response(void* opaque) { //This function runs inside a thread. //It runs if our local buffer size is 0 (we need to execute a key event, but we don't have the data we need). //We basically beg the server for input data. //After 10 seconds a timeout occurs, we assume we have lost connection to the server. uint8_t control_id = *(uint8_t*)opaque; uint32_t timeout = SDL_GetTicks() + 10000; while (!check_valid(control_id, l_cin_compats[control_id].netplay_count)) { if (SDL_GetTicks() > timeout) { l_udpChannel = -1; return 0; } netplay_request_input(control_id); SDL_Delay(5); } return 1; } static void netplay_process() { //In this function we process data we have received from the server UDPpacket *packet = SDLNet_AllocPacket(512); uint32_t curr, count, keys; uint8_t plugin, player, current_status; while (SDLNet_UDP_Recv(l_udpSocket, packet) == 1) { switch (packet->data[0]) { case UDP_RECEIVE_KEY_INFO: case UDP_RECEIVE_KEY_INFO_GRATUITOUS: player = packet->data[1]; //current_status is a status update from the server //it will let us know if another player has disconnected, or the games have desynced current_status = packet->data[2]; if (packet->data[0] == UDP_RECEIVE_KEY_INFO) l_player_lag[player] = packet->data[3]; if (current_status != l_status) { if (((current_status & 0x1) ^ (l_status & 0x1)) != 0) DebugMessage(M64MSG_ERROR, "Netplay: players have de-synced at VI %u", l_vi_counter); for (int dis = 1; dis < 5; ++dis) { if (((current_status & (0x1 << dis)) ^ (l_status & (0x1 << dis))) != 0) DebugMessage(M64MSG_ERROR, "Netplay: player %u has disconnected", dis); } l_status = current_status; } curr = 5; //this loop processes input data from the server, inserting new events into the linked list for each player //it skips events that we have already recorded, or if we receive data for an event that has already happened for (uint8_t i = 0; i < packet->data[4]; ++i) { count = SDLNet_Read32(&packet->data[curr]); curr += 4; if (((count - l_cin_compats[player].netplay_count) > (UINT32_MAX / 2)) || (check_valid(player, count))) //event doesn't need to be recorded { curr += 5; continue; } keys = SDLNet_Read32(&packet->data[curr]); curr += 4; plugin = packet->data[curr]; curr += 1; //insert new event at beginning of linked list struct netplay_event* new_event = (struct netplay_event*)malloc(sizeof(struct netplay_event)); new_event->count = count; new_event->buttons = keys; new_event->plugin = plugin; new_event->next = l_cin_compats[player].event_first; l_cin_compats[player].event_first = new_event; } break; default: DebugMessage(M64MSG_ERROR, "Netplay: received unknown message from server"); break; } } SDLNet_FreePacket(packet); } static int netplay_ensure_valid(uint8_t control_id) { //This function makes sure we have data for a certain event //If we don't have the data, it will create a new thread that will request the data if (check_valid(control_id, l_cin_compats[control_id].netplay_count)) return 1; if (l_udpChannel == -1) return 0; #if SDL_VERSION_ATLEAST(2,0,0) SDL_Thread* thread = SDL_CreateThread(netplay_require_response, "Netplay key request", &control_id); #else SDL_Thread* thread = SDL_CreateThread(netplay_require_response, &control_id); #endif while (!check_valid(control_id, l_cin_compats[control_id].netplay_count) && l_udpChannel != -1) netplay_process(); int success; SDL_WaitThread(thread, &success); return success; } static void netplay_delete_event(struct netplay_event* current, uint8_t control_id) { //This function deletes an event from the linked list struct netplay_event* find = l_cin_compats[control_id].event_first; while (find != NULL) { if (find->next == current) { find->next = current->next; break; } find = find->next; } if (current == l_cin_compats[control_id].event_first) l_cin_compats[control_id].event_first = l_cin_compats[control_id].event_first->next; free(current); } static uint32_t netplay_get_input(uint8_t control_id) { uint32_t keys; netplay_process(); netplay_request_input(control_id); //l_buffer_target is set by the server upon registration //l_player_lag is how far behind we are from the lead player //buffer_size is the local buffer size if (l_player_lag[control_id] > 0 && buffer_size(control_id) > l_buffer_target) { l_canFF = 1; main_core_state_set(M64CORE_SPEED_LIMITER, 0); } else { main_core_state_set(M64CORE_SPEED_LIMITER, 1); l_canFF = 0; } if (netplay_ensure_valid(control_id)) { //We grab the event from the linked list, the delete it once it has been used //Finally we increment the event counter struct netplay_event* current = l_cin_compats[control_id].event_first; while (current->count != l_cin_compats[control_id].netplay_count) current = current->next; keys = current->buttons; Controls[control_id].Plugin = current->plugin; netplay_delete_event(current, control_id); ++l_cin_compats[control_id].netplay_count; } else { DebugMessage(M64MSG_ERROR, "Netplay: lost connection to server"); main_core_state_set(M64CORE_EMU_STATE, M64EMU_STOPPED); keys = 0; } return keys; } static void netplay_send_input(uint8_t control_id, uint32_t keys) { UDPpacket *packet = SDLNet_AllocPacket(11); packet->data[0] = UDP_SEND_KEY_INFO; packet->data[1] = control_id; //player number SDLNet_Write32(l_cin_compats[control_id].netplay_count, &packet->data[2]); // current event count SDLNet_Write32(keys, &packet->data[6]); //key data packet->data[10] = l_plugin[control_id]; //current plugin packet->len = 11; SDLNet_UDP_Send(l_udpSocket, l_udpChannel, packet); SDLNet_FreePacket(packet); } uint8_t netplay_register_player(uint8_t player, uint8_t plugin, uint8_t rawdata, uint32_t reg_id) { l_reg_id = reg_id; char output_data[8]; output_data[0] = TCP_REGISTER_PLAYER; output_data[1] = player; //player number we'd like to register output_data[2] = plugin; //current plugin output_data[3] = rawdata; //whether we are using a RawData input plugin SDLNet_Write32(l_reg_id, &output_data[4]); SDLNet_TCP_Send(l_tcpSocket, &output_data[0], 8); uint8_t response[2]; size_t recv = 0; while (recv < 2) recv += SDLNet_TCP_Recv(l_tcpSocket, &response[recv], 2 - recv); l_buffer_target = response[1]; //local buffer size target return response[0]; } int netplay_lag() { return l_canFF; } int netplay_next_controller() { return l_netplay_controller; } void netplay_set_controller(uint8_t player) { l_netplay_control[player] = l_netplay_controller++; l_spectator = 0; } int netplay_get_controller(uint8_t player) { return l_netplay_control[player]; } file_status_t netplay_read_storage(const char *filename, void *data, size_t size) { //This function syncs save games. //If the client is controlling player 1, it sends its save game to the server //All other players receive save files from the server const char *file_extension = strrchr(filename, '.'); file_extension += 1; uint32_t buffer_pos = 0; char *output_data = malloc(size + strlen(file_extension) + 6); file_status_t ret; uint8_t request; if (l_netplay_control[0] != -1) { request = TCP_SEND_SAVE; memcpy(&output_data[buffer_pos], &request, 1); ++buffer_pos; //send file extension memcpy(&output_data[buffer_pos], file_extension, strlen(file_extension) + 1); buffer_pos += strlen(file_extension) + 1; ret = read_from_file(filename, data, size); if (ret == file_open_error) memset(data, 0, size); //all zeros means there is no save file SDLNet_Write32((int32_t)size, &output_data[buffer_pos]); //file data size buffer_pos += 4; memcpy(&output_data[buffer_pos], data, size); //file data buffer_pos += size; SDLNet_TCP_Send(l_tcpSocket, &output_data[0], buffer_pos); } else { request = TCP_RECEIVE_SAVE; memcpy(&output_data[buffer_pos], &request, 1); ++buffer_pos; //extension of the file we are requesting memcpy(&output_data[buffer_pos], file_extension, strlen(file_extension) + 1); buffer_pos += strlen(file_extension) + 1; SDLNet_TCP_Send(l_tcpSocket, &output_data[0], buffer_pos); size_t recv = 0; char *data_array = data; while (recv < size) recv += SDLNet_TCP_Recv(l_tcpSocket, data_array + recv, size - recv); int sum = 0; for (int i = 0; i < size; ++i) sum |= data_array[i]; if (sum == 0) //all zeros means there is no save file ret = file_open_error; else ret = file_ok; } free(output_data); return ret; } void netplay_sync_settings(uint32_t *count_per_op, uint32_t *count_per_op_denom_pot, uint32_t *disable_extra_mem, int32_t *si_dma_duration, uint32_t *emumode, int32_t *no_compiled_jump) { if (!netplay_is_init()) return; char output_data[SETTINGS_SIZE + 1]; uint8_t request; if (l_netplay_control[0] != -1) //player 1 is the source of truth for settings { request = TCP_SEND_SETTINGS; memcpy(&output_data[0], &request, 1); SDLNet_Write32(*count_per_op, &output_data[1]); SDLNet_Write32(*count_per_op_denom_pot, &output_data[5]); SDLNet_Write32(*disable_extra_mem, &output_data[9]); SDLNet_Write32(*si_dma_duration, &output_data[13]); SDLNet_Write32(*emumode, &output_data[17]); SDLNet_Write32(*no_compiled_jump, &output_data[21]); SDLNet_TCP_Send(l_tcpSocket, &output_data[0], SETTINGS_SIZE + 1); } else { request = TCP_RECEIVE_SETTINGS; memcpy(&output_data[0], &request, 1); SDLNet_TCP_Send(l_tcpSocket, &output_data[0], 1); int32_t recv = 0; while (recv < SETTINGS_SIZE) recv += SDLNet_TCP_Recv(l_tcpSocket, &output_data[recv], SETTINGS_SIZE - recv); *count_per_op = SDLNet_Read32(&output_data[0]); *count_per_op_denom_pot = SDLNet_Read32(&output_data[4]); *disable_extra_mem = SDLNet_Read32(&output_data[8]); *si_dma_duration = SDLNet_Read32(&output_data[12]); *emumode = SDLNet_Read32(&output_data[16]); *no_compiled_jump = SDLNet_Read32(&output_data[20]); } } void netplay_check_sync(struct cp0* cp0) { //This function is used to check if games have desynced //Every 600 VIs, it sends the value of the CP0 registers to the server //The server will compare the values, and update the status byte if it detects a desync if (!netplay_is_init()) return; const uint32_t* cp0_regs = r4300_cp0_regs(cp0); if (l_vi_counter % 600 == 0) { uint32_t packet_len = (CP0_REGS_COUNT * 4) + 5; UDPpacket *packet = SDLNet_AllocPacket(packet_len); packet->data[0] = UDP_SYNC_DATA; SDLNet_Write32(l_vi_counter, &packet->data[1]); //current VI count for (int i = 0; i < CP0_REGS_COUNT; ++i) { SDLNet_Write32(cp0_regs[i], &packet->data[(i * 4) + 5]); } packet->len = packet_len; SDLNet_UDP_Send(l_udpSocket, l_udpChannel, packet); SDLNet_FreePacket(packet); } ++l_vi_counter; } void netplay_read_registration(struct controller_input_compat* cin_compats) { //This function runs right before the game starts //The server shares the registration details about each player if (!netplay_is_init()) return; l_cin_compats = cin_compats; uint32_t reg_id; char output_data = TCP_GET_REGISTRATION; char input_data[24]; SDLNet_TCP_Send(l_tcpSocket, &output_data, 1); size_t recv = 0; while (recv < 24) recv += SDLNet_TCP_Recv(l_tcpSocket, &input_data[recv], 24 - recv); uint32_t curr = 0; for (int i = 0; i < 4; ++i) { reg_id = SDLNet_Read32(&input_data[curr]); curr += 4; if (reg_id == 0) //No one registered to control this player { Controls[i].Present = 0; Controls[i].Plugin = PLUGIN_NONE; Controls[i].RawData = 0; curr += 2; } else { Controls[i].Present = 1; if (i > 0 && input_data[curr] == PLUGIN_MEMPAK) // only P1 can use mempak Controls[i].Plugin = PLUGIN_NONE; else if (input_data[curr] == PLUGIN_TRANSFER_PAK) // Transferpak not supported during netplay Controls[i].Plugin = PLUGIN_NONE; else Controls[i].Plugin = input_data[curr]; l_plugin[i] = Controls[i].Plugin; ++curr; Controls[i].RawData = input_data[curr]; ++curr; } } } static void netplay_send_raw_input(struct pif* pif) { for (int i = 0; i < 4; ++i) { if (l_netplay_control[i] != -1) { if (pif->channels[i].tx && pif->channels[i].tx_buf[0] == JCMD_CONTROLLER_READ) netplay_send_input(i, *(uint32_t*)pif->channels[i].rx_buf); } } } static void netplay_get_raw_input(struct pif* pif) { for (int i = 0; i < 4; ++i) { if (Controls[i].Present == 1) { if (pif->channels[i].tx) { *pif->channels[i].rx &= ~0xC0; //Always show the controller as connected if(pif->channels[i].tx_buf[0] == JCMD_CONTROLLER_READ) { *(uint32_t*)pif->channels[i].rx_buf = netplay_get_input(i); } else if ((pif->channels[i].tx_buf[0] == JCMD_STATUS || pif->channels[i].tx_buf[0] == JCMD_RESET) && Controls[i].RawData) { //a bit of a hack for raw input controllers, force the status uint16_t type = JDT_JOY_ABS_COUNTERS | JDT_JOY_PORT; pif->channels[i].rx_buf[0] = (uint8_t)(type >> 0); pif->channels[i].rx_buf[1] = (uint8_t)(type >> 8); pif->channels[i].rx_buf[2] = 0; } else if (pif->channels[i].tx_buf[0] == JCMD_PAK_READ && Controls[i].RawData) { //also a hack for raw input, we return "mempak not present" if the game tries to read the mempak pif->channels[i].rx_buf[32] = 255; } else if (pif->channels[i].tx_buf[0] == JCMD_PAK_WRITE && Controls[i].RawData) { //also a hack for raw input, we return "mempak not present" if the game tries to write to mempak pif->channels[i].rx_buf[0] = 255; } } } } } void netplay_update_input(struct pif* pif) { if (netplay_is_init()) { netplay_send_raw_input(pif); netplay_get_raw_input(pif); } } m64p_error netplay_send_config(char* data, int size) { if (!netplay_is_init()) return M64ERR_NOT_INIT; if (l_netplay_control[0] != -1 || size == 1) //Only P1 sends settings, we allow all players to send if the size is 1, this may be a request packet { int result = SDLNet_TCP_Send(l_tcpSocket, data, size); if (result < size) return M64ERR_SYSTEM_FAIL; return M64ERR_SUCCESS; } else return M64ERR_INVALID_STATE; } m64p_error netplay_receive_config(char* data, int size) { if (!netplay_is_init()) return M64ERR_NOT_INIT; if (l_netplay_control[0] == -1) //Only P2-4 receive settings { int recv = 0; while (recv < size) { recv += SDLNet_TCP_Recv(l_tcpSocket, &data[recv], size - recv); if (recv < 1) return M64ERR_SYSTEM_FAIL; } return M64ERR_SUCCESS; } else return M64ERR_INVALID_STATE; } mupen64plus-core-src-2.6.0/src/main/netplay.h000066400000000000000000000103301464506436200210030ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - netplay.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2020 loganmc10 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __NETPLAY_H__ #define __NETPLAY_H__ #include "device/r4300/cp0.h" #include "device/pif/pif.h" #include "main/util.h" #define NETPLAY_CORE_VERSION 1 struct netplay_event { uint32_t buttons; uint8_t plugin; uint32_t count; struct netplay_event* next; }; struct controller_input_compat; #ifdef M64P_NETPLAY m64p_error netplay_start(const char* host, int port); m64p_error netplay_stop(); uint8_t netplay_register_player(uint8_t player, uint8_t plugin, uint8_t rawdata, uint32_t reg_id); int netplay_lag(); void netplay_set_controller(uint8_t player); int netplay_is_init(); int netplay_get_controller(uint8_t player); file_status_t netplay_read_storage(const char *filename, void *data, size_t size); void netplay_sync_settings(uint32_t *count_per_op, uint32_t *count_per_op_denom_pot, uint32_t *disable_extra_mem, int32_t *si_dma_duration, uint32_t *emumode, int32_t *no_compiled_jump); void netplay_check_sync(struct cp0* cp0); int netplay_next_controller(); void netplay_read_registration(struct controller_input_compat* cin_compats); void netplay_update_input(struct pif* pif); m64p_error netplay_send_config(char* data, int size); m64p_error netplay_receive_config(char* data, int size); #else static osal_inline m64p_error netplay_start(const char* host, int port) { return M64ERR_INCOMPATIBLE; } static osal_inline m64p_error netplay_stop() { return M64ERR_INCOMPATIBLE; } static osal_inline uint8_t netplay_register_player(uint8_t player, uint8_t plugin, uint8_t rawdata, uint32_t reg_id) { return 0; } static osal_inline int netplay_lag() { return 0; } static osal_inline void netplay_set_controller(uint8_t player) { } static osal_inline int netplay_is_init() { return 0; } static osal_inline int netplay_get_controller(uint8_t player) { return 0; } static osal_inline file_status_t netplay_read_storage(const char *filename, void *data, size_t size) { return 0; } static osal_inline void netplay_sync_settings(uint32_t *count_per_op, uint32_t *count_per_op_denom_pot, uint32_t *disable_extra_mem, int32_t *si_dma_duration, uint32_t *emumode, int32_t *no_compiled_jump) { } static osal_inline void netplay_check_sync(struct cp0* cp0) { } static osal_inline int netplay_next_controller() { return 0; } static osal_inline void netplay_read_registration(struct controller_input_compat* cin_compats) { } static osal_inline void netplay_update_input(struct pif* pif) { } static osal_inline void netplay_set_plugin(uint8_t control_id, uint8_t plugin) { } static osal_inline m64p_error netplay_send_config(char* data, int size) { return M64ERR_INCOMPATIBLE; } static osal_inline m64p_error netplay_receive_config(char* data, int size) { return M64ERR_INCOMPATIBLE; } #endif #endif mupen64plus-core-src-2.6.0/src/main/profile.c000066400000000000000000000101751464506436200207710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - profile.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2012 CasualJames * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "profile.h" #include "api/callbacks.h" #include "api/m64p_types.h" static long long int time_in_section[NUM_TIMED_SECTIONS]; static long long int last_start[NUM_TIMED_SECTIONS]; #if defined(WIN32) && !defined(__MINGW32__) // timing #include static long long int get_time(void) { LARGE_INTEGER counter; QueryPerformanceCounter(&counter); return counter.QuadPart; } static long long int time_to_nsec(long long int time) { static LARGE_INTEGER freq = { 0 }; if (freq.QuadPart == 0) QueryPerformanceFrequency(&freq); return time * 1000000000 / freq.QuadPart; } #else /* Not WIN32 */ // timing #include static long long int get_time(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (long long int)ts.tv_sec * 1000000000 + ts.tv_nsec; } static long long int time_to_nsec(long long int time) { return time; } #endif void timed_section_start(enum timed_section section) { last_start[section] = get_time(); } void timed_section_end(enum timed_section section) { long long int end = get_time(); time_in_section[section] += end - last_start[section]; } void timed_sections_refresh() { long long int curr_time = get_time(); if(time_to_nsec(curr_time - last_start[TIMED_SECTION_ALL]) >= 2000000000) { time_in_section[TIMED_SECTION_ALL] = curr_time - last_start[TIMED_SECTION_ALL]; DebugMessage(M64MSG_INFO, "gfx=%f%% - audio=%f%% - compiler=%f%%, idle=%f%%", 100.0 * (double)time_in_section[TIMED_SECTION_GFX] / time_in_section[TIMED_SECTION_ALL], 100.0 * (double)time_in_section[TIMED_SECTION_AUDIO] / time_in_section[TIMED_SECTION_ALL], 100.0 * (double)time_in_section[TIMED_SECTION_COMPILER] / time_in_section[TIMED_SECTION_ALL], 100.0 * (double)time_in_section[TIMED_SECTION_IDLE] / time_in_section[TIMED_SECTION_ALL]); DebugMessage(M64MSG_INFO, "gfx=%llins - audio=%llins - compiler %llins - idle=%llins", time_to_nsec(time_in_section[TIMED_SECTION_GFX]), time_to_nsec(time_in_section[TIMED_SECTION_AUDIO]), time_to_nsec(time_in_section[TIMED_SECTION_COMPILER]), time_to_nsec(time_in_section[TIMED_SECTION_IDLE])); time_in_section[TIMED_SECTION_GFX] = 0; time_in_section[TIMED_SECTION_AUDIO] = 0; time_in_section[TIMED_SECTION_COMPILER] = 0; time_in_section[TIMED_SECTION_IDLE] = 0; last_start[TIMED_SECTION_ALL] = curr_time; } } mupen64plus-core-src-2.6.0/src/main/profile.h000066400000000000000000000040051464506436200207710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - profile.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2014 Bobby Smiles * * Copyright (C) 2012 CasualJames * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef PROFILE_H #define PROFILE_H enum timed_section { TIMED_SECTION_ALL, TIMED_SECTION_GFX, TIMED_SECTION_AUDIO, TIMED_SECTION_COMPILER, TIMED_SECTION_IDLE, NUM_TIMED_SECTIONS }; void timed_section_start(enum timed_section section); void timed_section_end(enum timed_section section); void timed_sections_refresh(void); #endif mupen64plus-core-src-2.6.0/src/main/rom.c000066400000000000000000001051311464506436200201230ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rom.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Tillin9 * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS #include #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "api/config.h" #include "api/m64p_config.h" #include "api/m64p_types.h" #include "device/dd/disk.h" #include "backends/file_storage.h" #include "device/device.h" #include "main.h" #include "md5.h" #include "osal/files.h" #include "osal/preproc.h" #include "osd/osd.h" #include "rom.h" #include "util.h" #define CHUNKSIZE 1024*128 /* Read files 128KB at a time. */ /* Number of cpu cycles per instruction */ enum { DEFAULT_COUNT_PER_OP = 2 }; /* by default, extra mem is enabled */ enum { DEFAULT_DISABLE_EXTRA_MEM = 0 }; /* Default SI DMA duration */ enum { DEFAULT_SI_DMA_DURATION = 0x900 }; /* Default AI DMA modifier */ enum { DEFAULT_AI_DMA_MODIFIER = 100 }; static romdatabase_entry* ini_search_by_md5(md5_byte_t* md5); static _romdatabase g_romdatabase; /* Global loaded rom size. */ int g_rom_size = 0; m64p_rom_header ROM_HEADER; rom_params ROM_PARAMS; m64p_rom_settings ROM_SETTINGS; static m64p_system_type rom_country_code_to_system_type(uint16_t country_code); static unsigned char rom_homebrew_savetype_to_savetype(uint8_t save_type); static const uint8_t Z64_SIGNATURE[4] = { 0x80, 0x37, 0x12, 0x40 }; static const uint8_t V64_SIGNATURE[4] = { 0x37, 0x80, 0x40, 0x12 }; static const uint8_t N64_SIGNATURE[4] = { 0x40, 0x12, 0x37, 0x80 }; /* Tests if a file is a valid N64 rom by checking the first 4 bytes and size */ static int is_valid_rom(const unsigned char *buffer, unsigned int size) { if ((memcmp(buffer, Z64_SIGNATURE, sizeof(Z64_SIGNATURE)) == 0) || (memcmp(buffer, V64_SIGNATURE, sizeof(V64_SIGNATURE)) == 0 && size % 2 == 0) || (memcmp(buffer, N64_SIGNATURE, sizeof(N64_SIGNATURE)) == 0 && size % 4 == 0)) return 1; else return 0; } /* Copies the source block of memory to the destination block of memory while * switching the endianness of .v64 and .n64 images to the .z64 format, which * is native to the Nintendo 64. The data extraction routines and MD5 hashing * function may only act on the .z64 big-endian format. * * IN: src: The source block of memory. This must be a valid Nintendo 64 ROM * image of 'len' bytes. * len: The length of the source and destination, in bytes. * OUT: dst: The destination block of memory. This must be a valid buffer for * at least 'len' bytes. * imagetype: A pointer to a byte that gets updated with the value of * V64IMAGE, N64IMAGE or Z64IMAGE according to the format of * the source block. The value is undefined if 'src' does not * represent a valid Nintendo 64 ROM image. */ static void swap_copy_rom(void* dst, const void* src, size_t len, unsigned char* imagetype) { if (memcmp(src, V64_SIGNATURE, sizeof(V64_SIGNATURE)) == 0) { size_t i; const uint16_t* src16 = (const uint16_t*) src; uint16_t* dst16 = (uint16_t*) dst; *imagetype = V64IMAGE; /* .v64 images have byte-swapped half-words (16-bit). */ for (i = 0; i < len; i += 2) { *dst16++ = m64p_swap16(*src16++); } } else if (memcmp(src, N64_SIGNATURE, sizeof(N64_SIGNATURE)) == 0) { size_t i; const uint32_t* src32 = (const uint32_t*) src; uint32_t* dst32 = (uint32_t*) dst; *imagetype = N64IMAGE; /* .n64 images have byte-swapped words (32-bit). */ for (i = 0; i < len; i += 4) { *dst32++ = m64p_swap32(*src32++); } } else { *imagetype = Z64IMAGE; memcpy(dst, src, len); } } m64p_error open_rom(const unsigned char* romimage, unsigned int size) { md5_state_t state; md5_byte_t digest[16]; romdatabase_entry* entry; char buffer[256]; unsigned char imagetype; int i; /* check input requirements */ if (romimage == NULL || !is_valid_rom(romimage, size)) { DebugMessage(M64MSG_ERROR, "open_rom(): not a valid ROM image"); return M64ERR_INPUT_INVALID; } /* Clear Byte-swapped flag, since ROM is now deleted. */ g_RomWordsLittleEndian = 0; /* allocate new buffer for ROM and copy into this buffer */ g_rom_size = size; swap_copy_rom((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM), romimage, size, &imagetype); /* ROM is now in N64 native (big endian) byte order */ memcpy(&ROM_HEADER, (uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM), sizeof(m64p_rom_header)); /* Calculate MD5 hash */ md5_init(&state); md5_append(&state, (const md5_byte_t*)((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM)), g_rom_size); md5_finish(&state, digest); for ( i = 0; i < 16; ++i ) sprintf(buffer+i*2, "%02X", digest[i]); buffer[32] = '\0'; strcpy(ROM_SETTINGS.MD5, buffer); /* add some useful properties to ROM_PARAMS */ ROM_PARAMS.systemtype = rom_country_code_to_system_type(ROM_HEADER.Country_code); ROM_PARAMS.cheats = NULL; memcpy(ROM_PARAMS.headername, ROM_HEADER.Name, 20); ROM_PARAMS.headername[20] = '\0'; trim(ROM_PARAMS.headername); /* Remove trailing whitespace from ROM name. */ /* Look up this ROM in the .ini file and fill in goodname, etc */ if ((entry=ini_search_by_md5(digest)) != NULL || (entry=ini_search_by_crc(tohl(ROM_HEADER.CRC1),tohl(ROM_HEADER.CRC2))) != NULL) { strncpy(ROM_SETTINGS.goodname, entry->goodname, 255); ROM_SETTINGS.goodname[255] = '\0'; ROM_SETTINGS.savetype = entry->savetype; ROM_SETTINGS.status = entry->status; ROM_SETTINGS.players = entry->players; ROM_SETTINGS.rumble = entry->rumble; ROM_SETTINGS.transferpak = entry->transferpak; ROM_SETTINGS.mempak = entry->mempak; ROM_SETTINGS.biopak = entry->biopak; ROM_SETTINGS.countperop = entry->countperop; ROM_SETTINGS.disableextramem = entry->disableextramem; ROM_SETTINGS.sidmaduration = entry->sidmaduration; ROM_SETTINGS.aidmamodifier = entry->aidmamodifier; ROM_PARAMS.cheats = entry->cheats; } else { strcpy(ROM_SETTINGS.goodname, ROM_PARAMS.headername); strcat(ROM_SETTINGS.goodname, " (unknown rom)"); ROM_SETTINGS.status = 0; ROM_SETTINGS.players = 4; ROM_SETTINGS.rumble = 1; ROM_SETTINGS.transferpak = 0; ROM_SETTINGS.mempak = 1; ROM_SETTINGS.biopak = 0; ROM_SETTINGS.countperop = DEFAULT_COUNT_PER_OP; ROM_SETTINGS.disableextramem = DEFAULT_DISABLE_EXTRA_MEM; ROM_SETTINGS.sidmaduration = DEFAULT_SI_DMA_DURATION; ROM_SETTINGS.aidmamodifier = DEFAULT_AI_DMA_MODIFIER; ROM_PARAMS.cheats = NULL; /* check if ROM has the Advanced Homebrew ROM Header (see https://n64brew.dev/wiki/ROM_Header) */ if (ROM_HEADER.Cartridge_ID == 0x4445) { /* When current ROM has the Advanced Homebrew ROM Header, use the save type */ ROM_SETTINGS.savetype = rom_homebrew_savetype_to_savetype(ROM_HEADER.Version >> 4); } else { /* There's no way to guess the save type, but 4K EEPROM is better than nothing */ ROM_SETTINGS.savetype = SAVETYPE_EEPROM_4K; } } /* print out a bunch of info about the ROM */ DebugMessage(M64MSG_INFO, "Goodname: %s", ROM_SETTINGS.goodname); DebugMessage(M64MSG_INFO, "Name: %s", ROM_HEADER.Name); imagestring(imagetype, buffer); DebugMessage(M64MSG_INFO, "MD5: %s", ROM_SETTINGS.MD5); DebugMessage(M64MSG_INFO, "CRC: %08" PRIX32 " %08" PRIX32, tohl(ROM_HEADER.CRC1), tohl(ROM_HEADER.CRC2)); DebugMessage(M64MSG_INFO, "Imagetype: %s", buffer); DebugMessage(M64MSG_INFO, "Rom size: %d bytes (or %d Mb or %d Megabits)", g_rom_size, g_rom_size/1024/1024, g_rom_size/1024/1024*8); DebugMessage(M64MSG_VERBOSE, "ClockRate = %" PRIX32, tohl(ROM_HEADER.ClockRate)); DebugMessage(M64MSG_INFO, "Version: %" PRIX32, tohl(ROM_HEADER.Release)); if(tohl(ROM_HEADER.Manufacturer_ID) == 'N') DebugMessage(M64MSG_INFO, "Manufacturer: Nintendo"); else DebugMessage(M64MSG_INFO, "Manufacturer: %" PRIX32, tohl(ROM_HEADER.Manufacturer_ID)); DebugMessage(M64MSG_VERBOSE, "Cartridge_ID: %" PRIX16, ROM_HEADER.Cartridge_ID); countrycodestring(ROM_HEADER.Country_code, buffer); DebugMessage(M64MSG_INFO, "Country: %s", buffer); DebugMessage(M64MSG_VERBOSE, "PC = %" PRIX32, tohl(ROM_HEADER.PC)); DebugMessage(M64MSG_VERBOSE, "Save type: %d", ROM_SETTINGS.savetype); return M64ERR_SUCCESS; } m64p_error close_rom(void) { /* Clear Byte-swapped flag, since ROM is now deleted. */ g_RomWordsLittleEndian = 0; DebugMessage(M64MSG_STATUS, "Rom closed."); return M64ERR_SUCCESS; } m64p_error open_disk(void) { md5_state_t state; md5_byte_t digest[16]; romdatabase_entry* entry; char buffer[256]; int i; /* ask the core loader for DD disk filename */ char* dd_disk_filename = (g_media_loader.get_dd_disk == NULL) ? NULL : g_media_loader.get_dd_disk(g_media_loader.cb_data); /* handle the no disk case */ if (dd_disk_filename == NULL || strlen(dd_disk_filename) == 0) { goto no_disk; } /* Get DD Disk size */ size_t dd_size = 0; if (get_file_size(dd_disk_filename, &dd_size) != file_ok) { goto no_disk; } struct file_storage* fstorage = malloc(sizeof(struct file_storage)); if (fstorage == NULL) { goto no_disk; } /* Try loading regular disk file */ if (open_rom_file_storage(fstorage, dd_disk_filename) != file_ok) { goto free_fstorage; } /* Scan disk to deduce disk format and other parameters and expand its size for D64 */ unsigned int format = 0; unsigned int development = 0; size_t offset_sys = 0; size_t offset_id = 0; size_t offset_ram = 0; size_t size_ram = 0; uint8_t* new_data = scan_and_expand_disk_format(fstorage->data, fstorage->size, &format, &development, &offset_sys, &offset_id, &offset_ram, &size_ram); if (new_data == NULL) { goto wrong_disk_format; } else { fstorage->data = new_data; } /* Calculate MD5 hash */ md5_init(&state); md5_append(&state, (const md5_byte_t*)(fstorage->data), fstorage->size); md5_finish(&state, digest); for ( i = 0; i < 16; ++i ) sprintf(buffer+i*2, "%02X", digest[i]); buffer[32] = '\0'; strcpy(ROM_SETTINGS.MD5, buffer); /* Look up this disk in the .ini file and fill in goodname, etc */ if ((entry=ini_search_by_md5(digest)) != NULL) { strncpy(ROM_SETTINGS.goodname, entry->goodname, 255); ROM_SETTINGS.goodname[255] = '\0'; ROM_SETTINGS.savetype = entry->savetype; ROM_SETTINGS.status = entry->status; ROM_SETTINGS.players = entry->players; ROM_SETTINGS.rumble = entry->rumble; ROM_SETTINGS.transferpak = entry->transferpak; ROM_SETTINGS.mempak = entry->mempak; ROM_SETTINGS.biopak = entry->biopak; ROM_SETTINGS.countperop = entry->countperop; ROM_SETTINGS.disableextramem = entry->disableextramem; ROM_SETTINGS.sidmaduration = entry->sidmaduration; ROM_SETTINGS.aidmamodifier = entry->aidmamodifier; ROM_PARAMS.cheats = entry->cheats; } else { strcpy(ROM_SETTINGS.goodname, "(unknown disk)"); /* There's no way to guess the save type, but 4K EEPROM is better than nothing */ ROM_SETTINGS.savetype = SAVETYPE_EEPROM_4K; ROM_SETTINGS.status = 0; ROM_SETTINGS.players = 4; ROM_SETTINGS.rumble = 1; ROM_SETTINGS.transferpak = 0; ROM_SETTINGS.mempak = 1; ROM_SETTINGS.biopak = 0; ROM_SETTINGS.countperop = DEFAULT_COUNT_PER_OP; ROM_SETTINGS.disableextramem = DEFAULT_DISABLE_EXTRA_MEM; ROM_SETTINGS.sidmaduration = DEFAULT_SI_DMA_DURATION; ROM_SETTINGS.aidmamodifier = DEFAULT_AI_DMA_MODIFIER; ROM_PARAMS.cheats = NULL; } /* set system type */ ROM_PARAMS.systemtype = SYSTEM_NTSC; /* clear rom header & size */ memset(&ROM_HEADER, 0, sizeof(m64p_rom_header)); memset(ROM_PARAMS.headername, 0, 20); g_rom_size = 0; close_file_storage(fstorage); free(fstorage); return M64ERR_SUCCESS; wrong_disk_format: close_file_storage(fstorage); dd_disk_filename = NULL; /* already freed in close_file_storage */ free_fstorage: free(fstorage); no_disk: if (dd_disk_filename != NULL) { free(dd_disk_filename); } DebugMessage(M64MSG_ERROR, "open_disk(): not a valid disk image"); return M64ERR_INPUT_INVALID; } m64p_error close_disk(void) { DebugMessage(M64MSG_STATUS, "Disk closed."); return M64ERR_SUCCESS; } /********************************************************************************************/ /* ROM utility functions */ // Get the system type associated to a ROM country code. static m64p_system_type rom_country_code_to_system_type(uint16_t country_code) { switch (country_code) { // PAL codes case 0x44: case 0x46: case 0x49: case 0x50: case 0x53: case 0x55: case 0x58: case 0x59: return SYSTEM_PAL; // NTSC codes case 0x37: case 0x41: case 0x45: case 0x4a: default: // Fallback for unknown codes return SYSTEM_NTSC; } } // Converts the homebrew advanced rom header savetype to a m64p_rom_save_type static unsigned char rom_homebrew_savetype_to_savetype(uint8_t save_type) { unsigned char m64p_save_type; switch (save_type) { default: case 0: /* None */ m64p_save_type = SAVETYPE_NONE; break; case 1: /* 4K EEPROM */ m64p_save_type = SAVETYPE_EEPROM_4K; break; case 2: /* 16K EEPROM */ m64p_save_type = SAVETYPE_EEPROM_16KB; break; case 3: /* 256K SRAM */ case 4: /* 768K SRAM (banked) */ case 6: /* 1M SRAM */ m64p_save_type = SAVETYPE_SRAM; break; case 5: /* Flash RAM */ m64p_save_type = SAVETYPE_FLASH_RAM; break; } return m64p_save_type; } static size_t romdatabase_resolve_round(void) { romdatabase_search *entry; romdatabase_entry *ref; size_t skipped = 0; /* Resolve RefMD5 references */ for (entry = g_romdatabase.list; entry; entry = entry->next_entry) { if (!entry->entry.refmd5) continue; ref = ini_search_by_md5(entry->entry.refmd5); if (!ref) { DebugMessage(M64MSG_WARNING, "ROM Database: Error solving RefMD5s"); continue; } /* entry is not yet resolved, skip for now */ if (ref->refmd5) { skipped++; continue; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_GOODNAME) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_GOODNAME)) { entry->entry.goodname = strdup(ref->goodname); if (entry->entry.goodname) entry->entry.set_flags |= ROMDATABASE_ENTRY_GOODNAME; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_CRC) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_CRC)) { entry->entry.crc1 = ref->crc1; entry->entry.crc2 = ref->crc2; entry->entry.set_flags |= ROMDATABASE_ENTRY_CRC; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_STATUS) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_STATUS)) { entry->entry.status = ref->status; entry->entry.set_flags |= ROMDATABASE_ENTRY_STATUS; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_SAVETYPE) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_SAVETYPE)) { entry->entry.savetype = ref->savetype; entry->entry.set_flags |= ROMDATABASE_ENTRY_SAVETYPE; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_PLAYERS) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_PLAYERS)) { entry->entry.players = ref->players; entry->entry.set_flags |= ROMDATABASE_ENTRY_PLAYERS; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_RUMBLE) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_RUMBLE)) { entry->entry.rumble = ref->rumble; entry->entry.set_flags |= ROMDATABASE_ENTRY_RUMBLE; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_COUNTEROP) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_COUNTEROP)) { entry->entry.countperop = ref->countperop; entry->entry.set_flags |= ROMDATABASE_ENTRY_COUNTEROP; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_CHEATS) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_CHEATS)) { if (ref->cheats) entry->entry.cheats = strdup(ref->cheats); entry->entry.set_flags |= ROMDATABASE_ENTRY_CHEATS; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_EXTRAMEM) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_EXTRAMEM)) { entry->entry.disableextramem = ref->disableextramem; entry->entry.set_flags |= ROMDATABASE_ENTRY_EXTRAMEM; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_TRANSFERPAK) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_TRANSFERPAK)) { entry->entry.transferpak = ref->transferpak; entry->entry.set_flags |= ROMDATABASE_ENTRY_TRANSFERPAK; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_MEMPAK) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_MEMPAK)) { entry->entry.mempak = ref->mempak; entry->entry.set_flags |= ROMDATABASE_ENTRY_MEMPAK; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_BIOPAK) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_BIOPAK)) { entry->entry.biopak = ref->biopak; entry->entry.set_flags |= ROMDATABASE_ENTRY_BIOPAK; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_SIDMADURATION) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_SIDMADURATION)) { entry->entry.sidmaduration = ref->sidmaduration; entry->entry.set_flags |= ROMDATABASE_ENTRY_SIDMADURATION; } if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_AIDMAMODIFIER) && isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_AIDMAMODIFIER)) { entry->entry.aidmamodifier = ref->aidmamodifier; entry->entry.set_flags |= ROMDATABASE_ENTRY_AIDMAMODIFIER; } free(entry->entry.refmd5); entry->entry.refmd5 = NULL; } return skipped; } static void romdatabase_resolve(void) { size_t last_skipped = (size_t)~0ULL; size_t skipped; do { skipped = romdatabase_resolve_round(); if (skipped == last_skipped) { DebugMessage(M64MSG_ERROR, "Unable to resolve rom database entries (loop)"); break; } last_skipped = skipped; } while (skipped > 0); } /********************************************************************************************/ /* INI Rom database functions */ void romdatabase_open(void) { FILE *fPtr; char buffer[256]; romdatabase_search* search = NULL; romdatabase_search** next_search; int counter, value, lineno; unsigned char index; const char *pathname = ConfigGetSharedDataFilepath("mupen64plus.ini"); if(g_romdatabase.have_database) return; /* Open romdatabase. */ if (pathname == NULL || (fPtr = osal_file_open(pathname, "rb")) == NULL) { DebugMessage(M64MSG_ERROR, "Unable to open rom database file '%s'.", pathname); return; } g_romdatabase.have_database = 1; /* Clear premade indices. */ for(counter = 0; counter < 255; ++counter) g_romdatabase.crc_lists[counter] = NULL; for(counter = 0; counter < 255; ++counter) g_romdatabase.md5_lists[counter] = NULL; g_romdatabase.list = NULL; next_search = &g_romdatabase.list; /* Parse ROM database file */ for (lineno = 1; fgets(buffer, 255, fPtr) != NULL; lineno++) { char *line = buffer; ini_line l = ini_parse_line(&line); switch (l.type) { case INI_SECTION: { md5_byte_t md5[16]; if (!parse_hex(l.name, md5, 16)) { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid MD5 on line %i", lineno); search = NULL; continue; } *next_search = (romdatabase_search*) malloc(sizeof(romdatabase_search)); search = *next_search; next_search = &search->next_entry; memset(search, 0, sizeof(romdatabase_search)); search->entry.goodname = NULL; memcpy(search->entry.md5, md5, 16); search->entry.refmd5 = NULL; search->entry.crc1 = 0; search->entry.crc2 = 0; search->entry.status = 0; /* Set default to 0 stars. */ search->entry.savetype = SAVETYPE_EEPROM_4K; search->entry.players = 4; search->entry.rumble = 1; search->entry.countperop = DEFAULT_COUNT_PER_OP; search->entry.disableextramem = DEFAULT_DISABLE_EXTRA_MEM; search->entry.cheats = NULL; search->entry.transferpak = 0; search->entry.mempak = 1; search->entry.biopak = 0; search->entry.sidmaduration = DEFAULT_SI_DMA_DURATION; search->entry.aidmamodifier = DEFAULT_AI_DMA_MODIFIER; search->entry.set_flags = ROMDATABASE_ENTRY_NONE; search->next_entry = NULL; search->next_crc = NULL; /* Index MD5s by first 8 bits. */ index = search->entry.md5[0]; search->next_md5 = g_romdatabase.md5_lists[index]; g_romdatabase.md5_lists[index] = search; break; } case INI_PROPERTY: // This happens if there's stray properties before any section, // or if some error happened on INI_SECTION (e.g. parsing). if (search == NULL) { DebugMessage(M64MSG_WARNING, "ROM Database: Ignoring property on line %i", lineno); continue; } if(!strcmp(l.name, "GoodName")) { search->entry.goodname = strdup(l.value); search->entry.set_flags |= ROMDATABASE_ENTRY_GOODNAME; } else if(!strcmp(l.name, "CRC")) { char garbage_sweeper; if (sscanf(l.value, "%X %X%c", &search->entry.crc1, &search->entry.crc2, &garbage_sweeper) == 2) { /* Index CRCs by first 8 bits. */ index = search->entry.crc1 >> 24; search->next_crc = g_romdatabase.crc_lists[index]; g_romdatabase.crc_lists[index] = search; search->entry.set_flags |= ROMDATABASE_ENTRY_CRC; } else { search->entry.crc1 = search->entry.crc2 = 0; DebugMessage(M64MSG_WARNING, "ROM Database: Invalid CRC on line %i", lineno); } } else if(!strcmp(l.name, "RefMD5")) { md5_byte_t md5[16]; if (parse_hex(l.value, md5, 16)) { search->entry.refmd5 = (md5_byte_t*)malloc(16*sizeof(md5_byte_t)); memcpy(search->entry.refmd5, md5, 16); } else DebugMessage(M64MSG_WARNING, "ROM Database: Invalid RefMD5 on line %i", lineno); } else if(!strcmp(l.name, "SaveType")) { if(!strcmp(l.value, "Eeprom 4KB")) { search->entry.savetype = SAVETYPE_EEPROM_4K; search->entry.set_flags |= ROMDATABASE_ENTRY_SAVETYPE; } else if(!strcmp(l.value, "Eeprom 16KB")) { search->entry.savetype = SAVETYPE_EEPROM_16K; search->entry.set_flags |= ROMDATABASE_ENTRY_SAVETYPE; } else if(!strcmp(l.value, "SRAM")) { search->entry.savetype = SAVETYPE_SRAM; search->entry.set_flags |= ROMDATABASE_ENTRY_SAVETYPE; } else if(!strcmp(l.value, "Flash RAM")) { search->entry.savetype = SAVETYPE_FLASH_RAM; search->entry.set_flags |= ROMDATABASE_ENTRY_SAVETYPE; } else if(!strcmp(l.value, "Controller Pack")) { search->entry.savetype = SAVETYPE_CONTROLLER_PAK; search->entry.set_flags |= ROMDATABASE_ENTRY_SAVETYPE; } else if(!strcmp(l.value, "None")) { search->entry.savetype = SAVETYPE_NONE; search->entry.set_flags |= ROMDATABASE_ENTRY_SAVETYPE; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid save type on line %i", lineno); } } else if(!strcmp(l.name, "Status")) { if (string_to_int(l.value, &value) && value >= 0 && value < 6) { search->entry.status = value; search->entry.set_flags |= ROMDATABASE_ENTRY_STATUS; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid status on line %i", lineno); } } else if(!strcmp(l.name, "Players")) { if (string_to_int(l.value, &value) && value >= 0 && value < 8) { search->entry.players = value; search->entry.set_flags |= ROMDATABASE_ENTRY_PLAYERS; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid player count on line %i", lineno); } } else if(!strcmp(l.name, "Rumble")) { if(!strcmp(l.value, "Yes")) { search->entry.rumble = 1; search->entry.set_flags |= ROMDATABASE_ENTRY_RUMBLE; } else if(!strcmp(l.value, "No")) { search->entry.rumble = 0; search->entry.set_flags |= ROMDATABASE_ENTRY_RUMBLE; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid rumble string on line %i", lineno); } } else if(!strcmp(l.name, "CountPerOp")) { if (string_to_int(l.value, &value) && value > 0 && value <= 4) { search->entry.countperop = value; search->entry.set_flags |= ROMDATABASE_ENTRY_COUNTEROP; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid CountPerOp on line %i", lineno); } } else if (!strcmp(l.name, "DisableExtraMem")) { search->entry.disableextramem = atoi(l.value); search->entry.set_flags |= ROMDATABASE_ENTRY_EXTRAMEM; } else if(!strncmp(l.name, "Cheat", 5)) { size_t len1 = 0, len2 = 0; char *newcheat; if (search->entry.cheats) len1 = strlen(search->entry.cheats); if (l.value) len2 = strlen(l.value); /* initial cheat */ if (len1 == 0 && len2 > 0) search->entry.cheats = strdup(l.value); /* append cheat */ if (len1 != 0 && len2 > 0) { newcheat = malloc(len1 + 1 + len2 + 1); if (!newcheat) { DebugMessage(M64MSG_WARNING, "ROM Database: Failed to append cheat"); } else { strcpy(newcheat, search->entry.cheats); strcat(newcheat, ";"); strcat(newcheat, l.value); free(search->entry.cheats); search->entry.cheats = newcheat; } } search->entry.set_flags |= ROMDATABASE_ENTRY_CHEATS; } else if(!strcmp(l.name, "Transferpak")) { if(!strcmp(l.value, "Yes")) { search->entry.transferpak = 1; search->entry.set_flags |= ROMDATABASE_ENTRY_TRANSFERPAK; } else if(!strcmp(l.value, "No")) { search->entry.transferpak = 0; search->entry.set_flags |= ROMDATABASE_ENTRY_TRANSFERPAK; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid transferpak string on line %i", lineno); } } else if(!strcmp(l.name, "Mempak")) { if(!strcmp(l.value, "Yes")) { search->entry.mempak = 1; search->entry.set_flags |= ROMDATABASE_ENTRY_MEMPAK; } else if(!strcmp(l.value, "No")) { search->entry.mempak = 0; search->entry.set_flags |= ROMDATABASE_ENTRY_MEMPAK; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid mempak string on line %i", lineno); } } else if(!strcmp(l.name, "Biopak")) { if(!strcmp(l.value, "Yes")) { search->entry.biopak = 1; search->entry.set_flags |= ROMDATABASE_ENTRY_BIOPAK; } else if(!strcmp(l.value, "No")) { search->entry.biopak = 0; search->entry.set_flags |= ROMDATABASE_ENTRY_BIOPAK; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid biopak string on line %i", lineno); } } else if(!strcmp(l.name, "SiDmaDuration")) { if (string_to_int(l.value, &value) && value >= 0 && value <= 0x10000) { search->entry.sidmaduration = value; search->entry.set_flags |= ROMDATABASE_ENTRY_SIDMADURATION; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid SiDmaDuration on line %i", lineno); } } else if(!strcmp(l.name, "AiDmaModifier")) { if (string_to_int(l.value, &value) && value >= 0 && value <= 200) { search->entry.aidmamodifier = value; search->entry.set_flags |= ROMDATABASE_ENTRY_AIDMAMODIFIER; } else { DebugMessage(M64MSG_WARNING, "ROM Database: Invalid AiDmaModifier on line %i", lineno); } } else { DebugMessage(M64MSG_WARNING, "ROM Database: Unknown property on line %i", lineno); } break; default: break; } } fclose(fPtr); romdatabase_resolve(); } void romdatabase_close(void) { if (!g_romdatabase.have_database) return; while (g_romdatabase.list != NULL) { romdatabase_search* search = g_romdatabase.list->next_entry; if(g_romdatabase.list->entry.goodname) free(g_romdatabase.list->entry.goodname); if(g_romdatabase.list->entry.refmd5) free(g_romdatabase.list->entry.refmd5); free(g_romdatabase.list->entry.cheats); free(g_romdatabase.list); g_romdatabase.list = search; } g_romdatabase.have_database = 0; } static romdatabase_entry* ini_search_by_md5(md5_byte_t* md5) { romdatabase_search* search; if(!g_romdatabase.have_database) return NULL; search = g_romdatabase.md5_lists[md5[0]]; while (search != NULL && memcmp(search->entry.md5, md5, 16) != 0) search = search->next_md5; if(search==NULL) return NULL; return &(search->entry); } romdatabase_entry* ini_search_by_crc(unsigned int crc1, unsigned int crc2) { romdatabase_search* search; romdatabase_entry* found_entry = NULL; if(!g_romdatabase.have_database) return NULL; search = g_romdatabase.crc_lists[((crc1 >> 24) & 0xff)]; // because CRCs can be ambiguous (there can be multiple database entries with the same CRC), // we will prefer MD5 hashes instead. If the given CRC matches more than one entry in the // database, we will return no match. while (search != NULL) { if (search->entry.crc1 == crc1 && search->entry.crc2 == crc2) { if (found_entry != NULL) return NULL; found_entry = &search->entry; } search = search->next_crc; } return found_entry; } mupen64plus-core-src-2.6.0/src/main/rom.h000066400000000000000000000133571464506436200201400ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - rom.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Tillin9 * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __ROM_H__ #define __ROM_H__ #include #include #include "api/m64p_types.h" #define BIT(bitnr) (1ULL << (bitnr)) #ifdef __GNUC__ #define isset_bitmask(x, bitmask) __extension__ ({ __typeof__(bitmask) _bitmask = (bitmask); \ (_bitmask & (x)) == _bitmask; }) #else #define isset_bitmask(x, bitmask) ((bitmask & (x)) == bitmask) #endif /* ROM Loading and Saving functions */ m64p_error open_rom(const unsigned char* romimage, unsigned int size); m64p_error close_rom(void); m64p_error open_disk(void); m64p_error close_disk(void); extern int g_rom_size; typedef struct _rom_params { char *cheats; m64p_system_type systemtype; char headername[21]; /* ROM Name as in the header, removing trailing whitespace */ } rom_params; extern m64p_rom_header ROM_HEADER; extern rom_params ROM_PARAMS; extern m64p_rom_settings ROM_SETTINGS; /* Supported rom compressiontypes. */ enum { UNCOMPRESSED, ZIP_COMPRESSION, GZIP_COMPRESSION, BZIP2_COMPRESSION, LZMA_COMPRESSION, SZIP_COMPRESSION }; /* Supported rom image types. */ enum { Z64IMAGE, V64IMAGE, N64IMAGE }; /* Supported CIC chips. */ enum { CIC_NUS_6101, CIC_NUS_6102, CIC_NUS_6103, CIC_NUS_6105, CIC_NUS_6106 }; /* Rom INI database structures and functions */ /* The romdatabase contains the items mupen64plus indexes for each rom. These * include the goodname (from the GoodN64 project), the current status of the rom * in mupen, the N64 savetype used in the original cartridge (often necessary for * booting the rom in mupen), the number of players (including netplay options), * and whether the rom can make use of the N64's rumble feature. Md5, crc1, and * crc2 used for rom lookup. Md5s are unique hashes of the ENTIRE rom. Crcs are not * unique and read from the rom header, meaning corrupt crcs are also a problem. * Crcs were widely used (mainly in the cheat system). Refmd5s allows for a smaller * database file and need not be used outside database loading. */ typedef struct { char* goodname; md5_byte_t md5[16]; md5_byte_t* refmd5; char *cheats; unsigned int crc1; unsigned int crc2; unsigned char status; /* Rom status on a scale from 0-5. */ unsigned char savetype; unsigned char players; /* Local players 0-4, 2/3/4 way Netplay indicated by 5/6/7. */ unsigned char rumble; /* 0 - No, 1 - Yes boolean for rumble support. */ unsigned char countperop; unsigned char disableextramem; unsigned char transferpak; /* 0 - No, 1 - Yes boolean for transferpak support. */ unsigned char mempak; /* 0 - No, 1 - Yes boolean for mempak support. */ unsigned char biopak; /* 0 - No, 1 - Yes boolean for biopak support. */ unsigned int sidmaduration; unsigned int aidmamodifier; uint32_t set_flags; } romdatabase_entry; #define ROMDATABASE_ENTRY_NONE 0ULL #define ROMDATABASE_ENTRY_GOODNAME BIT(0) #define ROMDATABASE_ENTRY_CRC BIT(1) #define ROMDATABASE_ENTRY_STATUS BIT(2) #define ROMDATABASE_ENTRY_SAVETYPE BIT(3) #define ROMDATABASE_ENTRY_PLAYERS BIT(4) #define ROMDATABASE_ENTRY_RUMBLE BIT(5) #define ROMDATABASE_ENTRY_COUNTEROP BIT(6) #define ROMDATABASE_ENTRY_CHEATS BIT(7) #define ROMDATABASE_ENTRY_EXTRAMEM BIT(8) #define ROMDATABASE_ENTRY_TRANSFERPAK BIT(9) #define ROMDATABASE_ENTRY_MEMPAK BIT(10) #define ROMDATABASE_ENTRY_BIOPAK BIT(11) #define ROMDATABASE_ENTRY_SIDMADURATION BIT(12) #define ROMDATABASE_ENTRY_AIDMAMODIFIER BIT(13) typedef struct _romdatabase_search { romdatabase_entry entry; struct _romdatabase_search* next_entry; struct _romdatabase_search* next_crc; struct _romdatabase_search* next_md5; } romdatabase_search; typedef struct { int have_database; romdatabase_search* crc_lists[256]; romdatabase_search* md5_lists[256]; romdatabase_search* list; } _romdatabase; void romdatabase_open(void); void romdatabase_close(void); /* Should be used by current cheat system (isn't), when cheat system is * migrated to md5s, will be fully depreciated. */ romdatabase_entry* ini_search_by_crc(unsigned int crc1, unsigned int crc2); #endif /* __ROM_H__ */ mupen64plus-core-src-2.6.0/src/main/savestates.c000066400000000000000000002700041464506436200215120ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - savestates.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 CasualJames * * Copyright (C) 2009 Olejl Tillin9 * * Copyright (C) 2008 Richard42 Tillin9 * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include #include #include #include #include #include #include #include #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "api/config.h" #include "api/m64p_config.h" #include "api/m64p_types.h" #include "backends/api/storage_backend.h" #include "device/device.h" #include "main/list.h" #include "main/main.h" #include "osal/files.h" #include "osal/preproc.h" #include "osd/osd.h" #include "plugin/plugin.h" #include "rom.h" #include "savestates.h" #include "util.h" #include "workqueue.h" enum { GB_CART_FINGERPRINT_SIZE = 0x1c }; enum { GB_CART_FINGERPRINT_OFFSET = 0x134 }; enum { DD_DISK_ID_OFFSET = 0x43670 }; static const char* savestate_magic = "M64+SAVE"; static const int savestate_latest_version = 0x00010900; /* 1.9 */ static const unsigned char pj64_magic[4] = { 0xC8, 0xA6, 0xD8, 0x23 }; static savestates_job job = savestates_job_nothing; static savestates_type type = savestates_type_unknown; static char *fname = NULL; static unsigned int slot = 0; static int autoinc_save_slot = 0; static SDL_mutex *savestates_lock; struct savestate_work { char *filepath; char *data; size_t size; struct work_struct work; }; /* Returns the malloc'd full path of the currently selected savestate. */ static char *savestates_generate_path(savestates_type type) { if(fname != NULL) /* A specific path was given. */ { return strdup(fname); } else /* Use the selected savestate slot */ { char *filepath; size_t size = 0; switch (type) { case savestates_type_m64p: /* check if old file path exists, if it does then use that */ filepath = formatstr("%s%s.st%d", get_savestatepath(), ROM_SETTINGS.goodname, slot); if (get_file_size(filepath, &size) != file_ok || size == 0) { /* else use new path */ filepath = formatstr("%s%s.st%d", get_savestatepath(), get_savestatefilename(), slot); } break; case savestates_type_pj64_zip: filepath = formatstr("%s%s.pj%d.zip", get_savestatepath(), ROM_PARAMS.headername, slot); break; case savestates_type_pj64_unc: filepath = formatstr("%s%s.pj%d", get_savestatepath(), ROM_PARAMS.headername, slot); break; default: filepath = NULL; break; } return filepath; } } void savestates_select_slot(unsigned int s) { if(s>9||s==slot) return; slot = s; ConfigSetParameter(g_CoreConfig, "CurrentStateSlot", M64TYPE_INT, &s); StateChanged(M64CORE_SAVESTATE_SLOT, slot); main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Selected state slot: %d", slot); } /* Returns the currently selected save slot. */ unsigned int savestates_get_slot(void) { return slot; } /* Sets save state slot autoincrement on or off. */ void savestates_set_autoinc_slot(int b) { autoinc_save_slot = b; } void savestates_inc_slot(void) { if(++slot>9) slot = 0; ConfigSetParameter(g_CoreConfig, "CurrentStateSlot", M64TYPE_INT, &slot); StateChanged(M64CORE_SAVESTATE_SLOT, slot); } savestates_job savestates_get_job(void) { return job; } void savestates_set_job(savestates_job j, savestates_type t, const char *fn) { if (fname != NULL) { free(fname); fname = NULL; } job = j; type = t; if (fn != NULL) fname = strdup(fn); } static void savestates_clear_job(void) { savestates_set_job(savestates_job_nothing, savestates_type_unknown, NULL); } #define GETARRAY(buff, type, count) \ (to_little_endian_buffer(buff, sizeof(type),count), \ buff += count*sizeof(type), \ (type *)(buff-count*sizeof(type))) #define COPYARRAY(dst, buff, type, count) \ memcpy(dst, GETARRAY(buff, type, count), sizeof(type)*count) #define GETDATA(buff, type) *GETARRAY(buff, type, 1) #define PUTARRAY(src, buff, type, count) \ memcpy(buff, src, sizeof(type)*count); \ to_little_endian_buffer(buff, sizeof(type), count); \ buff += count*sizeof(type); #define PUTDATA(buff, type, value) \ do { type x = value; PUTARRAY(&x, buff, type, 1); } while(0) static int savestates_load_m64p(struct device* dev, char *filepath) { unsigned char header[44]; gzFile f; unsigned int version; int i; uint32_t FCR31; size_t savestateSize; unsigned char *savestateData, *curr; char queue[1024]; unsigned char using_tlb_data[4]; unsigned char data_0001_0200[4096]; // 4k for extra state from v1.2 uint32_t* cp0_regs = r4300_cp0_regs(&dev->r4300.cp0); SDL_LockMutex(savestates_lock); f = osal_gzopen(filepath, "rb"); if(f==NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not open state file: %s", filepath); SDL_UnlockMutex(savestates_lock); return 0; } /* Read and check Mupen64Plus magic number. */ if (gzread(f, header, 44) != 44) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read header from state file %s", filepath); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } curr = header; if(strncmp((char *)curr, savestate_magic, 8)!=0) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State file: %s is not a valid Mupen64plus savestate.", filepath); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } curr += 8; version = *curr++; version = (version << 8) | *curr++; version = (version << 8) | *curr++; version = (version << 8) | *curr++; if((version >> 16) != (savestate_latest_version >> 16)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State version (%08x) isn't compatible. Please update Mupen64Plus.", version); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } if(memcmp((char *)curr, ROM_SETTINGS.MD5, 32)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State ROM MD5 does not match current ROM."); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } curr += 32; /* Read the rest of the savestate */ savestateSize = 16788244; savestateData = curr = (unsigned char *)malloc(savestateSize); if (savestateData == NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to load state."); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } if (version == 0x00010000) /* original savestate version */ { if (gzread(f, savestateData, savestateSize) != (int)savestateSize || (gzread(f, queue, sizeof(queue)) % 4) != 0) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read Mupen64Plus savestate 1.0 data from %s", filepath); free(savestateData); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } } else if (version == 0x00010100) // saves entire eventqueue plus 4-byte using_tlb flags { if (gzread(f, savestateData, savestateSize) != (int)savestateSize || gzread(f, queue, sizeof(queue)) != sizeof(queue) || gzread(f, using_tlb_data, sizeof(using_tlb_data)) != sizeof(using_tlb_data)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read Mupen64Plus savestate 1.1 data from %s", filepath); free(savestateData); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } } else // version >= 0x00010200 saves entire eventqueue, 4-byte using_tlb flags and extra state { if (gzread(f, savestateData, savestateSize) != (int)savestateSize || gzread(f, queue, sizeof(queue)) != sizeof(queue) || gzread(f, using_tlb_data, sizeof(using_tlb_data)) != sizeof(using_tlb_data) || gzread(f, data_0001_0200, sizeof(data_0001_0200)) != sizeof(data_0001_0200)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read Mupen64Plus savestate 1.2+ data from %s", filepath); free(savestateData); gzclose(f); SDL_UnlockMutex(savestates_lock); return 0; } } gzclose(f); SDL_UnlockMutex(savestates_lock); // Parse savestate dev->rdram.regs[0][RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_DELAY_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_MODE_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t); curr += 4; /* Padding from old implementation */ dev->mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t); curr += 4; // Duplicate MI init mode flags from old implementation dev->mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t); dev->mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t); dev->mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t); curr += 4; /* Padding from old implementation */ curr += 8; // Duplicated MI intr flags and padding from old implementation dev->pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t); curr += 4; /* Padding from old implementation */ dev->sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t); curr += 16; // Duplicated SP flags and padding from old implementation dev->sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t); dev->sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t); dev->sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t); dev->si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t); dev->si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t); dev->si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t); dev->vi.delay = GETDATA(curr, uint32_t); gfx.viStatusChanged(); gfx.viWidthChanged(); dev->ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t); dev->ai.fifo[1].duration = GETDATA(curr, uint32_t); dev->ai.fifo[1].length = GETDATA(curr, uint32_t); dev->ai.fifo[0].duration = GETDATA(curr, uint32_t); dev->ai.fifo[0].length = GETDATA(curr, uint32_t); /* best effort initialization of fifo addresses... * You might get a small sound "pop" because address might be wrong. * Proper initialization requires changes to savestate format */ dev->ai.fifo[0].address = dev->ai.regs[AI_DRAM_ADDR_REG]; dev->ai.fifo[1].address = dev->ai.regs[AI_DRAM_ADDR_REG]; dev->ai.samples_format_changed = 1; dev->dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t); curr += 4; // Padding from old implementation dev->dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t); curr += 12; // Duplicated DPC flags and padding from old implementation dev->dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t); dev->dp.dps_regs[DPS_TBIST_REG] = GETDATA(curr, uint32_t); dev->dp.dps_regs[DPS_TEST_MODE_REG] = GETDATA(curr, uint32_t); dev->dp.dps_regs[DPS_BUFTEST_ADDR_REG] = GETDATA(curr, uint32_t); dev->dp.dps_regs[DPS_BUFTEST_DATA_REG] = GETDATA(curr, uint32_t); COPYARRAY(dev->rdram.dram, curr, uint32_t, RDRAM_MAX_SIZE/4); COPYARRAY(dev->sp.mem, curr, uint32_t, SP_MEM_SIZE/4); COPYARRAY(dev->pif.ram, curr, uint8_t, PIF_RAM_SIZE); dev->cart.use_flashram = GETDATA(curr, int32_t); curr += 4+8+4+4; /* Here there used to be flashram state */ /* by default, reset flashram state here and load it later if available */ poweron_flashram(&dev->cart.flashram); COPYARRAY(dev->r4300.cp0.tlb.LUT_r, curr, uint32_t, 0x100000); COPYARRAY(dev->r4300.cp0.tlb.LUT_w, curr, uint32_t, 0x100000); *r4300_llbit(&dev->r4300) = GETDATA(curr, uint32_t); COPYARRAY(r4300_regs(&dev->r4300), curr, int64_t, 32); COPYARRAY(cp0_regs, curr, uint32_t, CP0_REGS_COUNT); *r4300_mult_lo(&dev->r4300) = GETDATA(curr, int64_t); *r4300_mult_hi(&dev->r4300) = GETDATA(curr, int64_t); cp1_reg *cp1_regs = r4300_cp1_regs(&dev->r4300.cp1); COPYARRAY(&cp1_regs->dword, curr, int64_t, 32); *r4300_cp1_fcr0(&dev->r4300.cp1) = GETDATA(curr, uint32_t); FCR31 = GETDATA(curr, uint32_t); *r4300_cp1_fcr31(&dev->r4300.cp1) = FCR31; set_fpr_pointers(&dev->r4300.cp1, cp0_regs[CP0_STATUS_REG]); update_x86_rounding_mode(&dev->r4300.cp1); for (i = 0; i < 32; i++) { dev->r4300.cp0.tlb.entries[i].mask = GETDATA(curr, int16_t); curr += 2; dev->r4300.cp0.tlb.entries[i].vpn2 = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].g = GETDATA(curr, char); dev->r4300.cp0.tlb.entries[i].asid = GETDATA(curr, unsigned char); curr += 2; dev->r4300.cp0.tlb.entries[i].pfn_even = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].c_even = GETDATA(curr, char); dev->r4300.cp0.tlb.entries[i].d_even = GETDATA(curr, char); dev->r4300.cp0.tlb.entries[i].v_even = GETDATA(curr, char); curr++; dev->r4300.cp0.tlb.entries[i].pfn_odd = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].c_odd = GETDATA(curr, char); dev->r4300.cp0.tlb.entries[i].d_odd = GETDATA(curr, char); dev->r4300.cp0.tlb.entries[i].v_odd = GETDATA(curr, char); dev->r4300.cp0.tlb.entries[i].r = GETDATA(curr, char); dev->r4300.cp0.tlb.entries[i].start_even = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].end_even = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].phys_even = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].start_odd = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].end_odd = GETDATA(curr, uint32_t); dev->r4300.cp0.tlb.entries[i].phys_odd = GETDATA(curr, uint32_t); } savestates_load_set_pc(&dev->r4300, GETDATA(curr, uint32_t)); *r4300_cp0_next_interrupt(&dev->r4300.cp0) = GETDATA(curr, uint32_t); curr += 4; /* here there used to be next_vi */ dev->vi.field = GETDATA(curr, uint32_t); // assert(savestateData+savestateSize == curr) to_little_endian_buffer(queue, 4, 256); load_eventqueue_infos(&dev->r4300.cp0, queue); #ifdef NEW_DYNAREC // Default this to 1, it will be updated by the correct save state version later stop_after_jal = 1; if (version >= 0x00010100) { curr = using_tlb_data; using_tlb = GETDATA(curr, uint32_t); } #endif if (version == 0x00010200) { union { uint8_t bytes[8]; uint64_t force_alignment; } aligned; #define ALIGNED_GETDATA(buff, type) \ (COPYARRAY(aligned.bytes, buff, uint8_t, sizeof(type)), *(type*)aligned.bytes) curr = data_0001_0200; /* extra ai state */ dev->ai.last_read = GETDATA(curr, uint32_t); dev->ai.delayed_carry = GETDATA(curr, uint32_t); /* extra cart_rom state */ dev->cart.cart_rom.last_write = GETDATA(curr, uint32_t); curr += 4; /* used to be cart_rom.rom_written */ /* extra sp state */ curr += 4; /* here there used to be rsp_task_locked */ /* extra af-rtc state */ dev->cart.af_rtc.control = GETDATA(curr, uint16_t); dev->cart.af_rtc.now = (time_t)ALIGNED_GETDATA(curr, int64_t); dev->cart.af_rtc.last_update_rtc = (time_t)ALIGNED_GETDATA(curr, int64_t); /* extra controllers state */ for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { dev->controllers[i].status = GETDATA(curr, uint8_t); } /* extra rpak state */ for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { uint8_t rpk_state = GETDATA(curr, uint8_t); /* init rumble pak state if enabled and not controlled by the input plugin */ if (ROM_SETTINGS.rumble && !Controls[i].RawData) { set_rumble_reg(&dev->rumblepaks[i], rpk_state); } } /* extra tpak state */ for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { char gb_fingerprint[GB_CART_FINGERPRINT_SIZE]; uint8_t rtc_regs[MBC3_RTC_REGS_COUNT]; uint8_t rtc_latched_regs[MBC3_RTC_REGS_COUNT]; uint8_t cam_regs[POCKET_CAM_REGS_COUNT]; unsigned int rom_bank = 0; unsigned int ram_bank = 0; unsigned int ram_enable = 0; unsigned int mbc1_mode = 0; unsigned int rtc_latch = 0; time_t rtc_last_time = 0; unsigned int enabled = ALIGNED_GETDATA(curr, uint32_t); unsigned int bank = ALIGNED_GETDATA(curr, uint32_t); unsigned int access_mode = ALIGNED_GETDATA(curr, uint32_t); unsigned int access_mode_changed = ALIGNED_GETDATA(curr, uint32_t); COPYARRAY(gb_fingerprint, curr, uint8_t, GB_CART_FINGERPRINT_SIZE); if (gb_fingerprint[0] != 0) { rom_bank = ALIGNED_GETDATA(curr, uint32_t); ram_bank = ALIGNED_GETDATA(curr, uint32_t); ram_enable = ALIGNED_GETDATA(curr, uint32_t); mbc1_mode = ALIGNED_GETDATA(curr, uint32_t); COPYARRAY(rtc_regs, curr, uint8_t, MBC3_RTC_REGS_COUNT); rtc_latch = ALIGNED_GETDATA(curr, uint32_t); COPYARRAY(rtc_latched_regs, curr, uint8_t, MBC3_RTC_REGS_COUNT); rtc_last_time = (time_t)ALIGNED_GETDATA(curr, int64_t); COPYARRAY(cam_regs, curr, uint8_t, POCKET_CAM_REGS_COUNT); } if (ROM_SETTINGS.transferpak && !Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD)) { /* init transferpak state if enabled and not controlled by input plugin */ dev->transferpaks[i].enabled = enabled; dev->transferpaks[i].bank = bank; dev->transferpaks[i].access_mode = access_mode; dev->transferpaks[i].access_mode_changed = access_mode_changed; /* if it holds a valid cartridge init gbcart */ if (dev->transferpaks[i].gb_cart != NULL && dev->transferpaks[i].gb_cart->irom_storage != NULL) { const uint8_t* rom = dev->transferpaks[i].gb_cart->irom_storage->data (dev->transferpaks[i].gb_cart->rom_storage); /* verify that gb cart saved in savestate is the same * as what is currently inserted in transferpak */ if (gb_fingerprint[0] != 0 && memcmp(gb_fingerprint, rom + GB_CART_FINGERPRINT_OFFSET, GB_CART_FINGERPRINT_SIZE) == 0) { /* init gbcart state */ dev->transferpaks[i].gb_cart->rom_bank = rom_bank; dev->transferpaks[i].gb_cart->ram_bank = ram_bank; dev->transferpaks[i].gb_cart->ram_enable = ram_enable; dev->transferpaks[i].gb_cart->mbc1_mode = mbc1_mode; dev->transferpaks[i].gb_cart->rtc.latch = rtc_latch; dev->transferpaks[i].gb_cart->rtc.last_time = rtc_last_time; memcpy(dev->transferpaks[i].gb_cart->rtc.regs, rtc_regs, MBC3_RTC_REGS_COUNT); memcpy(dev->transferpaks[i].gb_cart->rtc.latched_regs, rtc_latched_regs, MBC3_RTC_REGS_COUNT); memcpy(dev->transferpaks[i].gb_cart->cam.regs, cam_regs, POCKET_CAM_REGS_COUNT); } else { DebugMessage(M64MSG_WARNING, "Savestate GB cart mismatch. Current GB cart: %s. Expected GB cart : %s", (rom[GB_CART_FINGERPRINT_OFFSET] == 0x00) ? "(none)" : (const char*)(rom + GB_CART_FINGERPRINT_OFFSET), (gb_fingerprint[0] == 0x00) ? "(none)" : gb_fingerprint); poweron_gb_cart(dev->transferpaks[i].gb_cart); } } } } /* extra pif channels state */ for (i = 0; i < PIF_CHANNELS_COUNT; ++i) { int offset = GETDATA(curr, int8_t); if (offset >= 0) { setup_pif_channel(&dev->pif.channels[i], dev->pif.ram + offset); } else { disable_pif_channel(&dev->pif.channels[i]); } } /* extra vi state */ dev->vi.count_per_scanline = ALIGNED_GETDATA(curr, uint32_t); /* extra si state */ dev->si.dma_dir = GETDATA(curr, uint8_t); /* extra dp state */ dev->dp.do_on_unfreeze = GETDATA(curr, uint8_t); /* extra RDRAM register state */ for (i = 1; i < RDRAM_MAX_MODULES_COUNT; ++i) { dev->rdram.regs[i][RDRAM_CONFIG_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_DELAY_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_MODE_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_REF_INTERVAL_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_REF_ROW_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_RAS_INTERVAL_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_MIN_INTERVAL_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_ADDR_SELECT_REG] = ALIGNED_GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_DEVICE_MANUF_REG] = ALIGNED_GETDATA(curr, uint32_t); } } else if (version >= 0x00010300) { curr = data_0001_0200; /* extra ai state */ dev->ai.last_read = GETDATA(curr, uint32_t); dev->ai.delayed_carry = GETDATA(curr, uint32_t); /* extra cart_rom state */ dev->cart.cart_rom.last_write = GETDATA(curr, uint32_t); curr +=4; /* used to be cart_rom.rom_written */ /* extra sp state */ curr += 4; /* here there used to be rsp_task_locked */ /* extra af-rtc state */ dev->cart.af_rtc.control = GETDATA(curr, uint16_t); curr += 2; /* padding to keep things 8-byte aligned */ dev->cart.af_rtc.now = (time_t)GETDATA(curr, int64_t); dev->cart.af_rtc.last_update_rtc = (time_t)GETDATA(curr, int64_t); /* extra controllers state */ for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { dev->controllers[i].status = GETDATA(curr, uint8_t); } /* extra rpak state */ for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { uint8_t rpk_state = GETDATA(curr, uint8_t); /* init rumble pak state if enabled and not controlled by the input plugin */ if (ROM_SETTINGS.rumble && !Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD)) { set_rumble_reg(&dev->rumblepaks[i], rpk_state); } } /* extra tpak state */ for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { char gb_fingerprint[GB_CART_FINGERPRINT_SIZE]; uint8_t rtc_regs[MBC3_RTC_REGS_COUNT]; uint8_t rtc_latched_regs[MBC3_RTC_REGS_COUNT]; uint8_t cam_regs[POCKET_CAM_REGS_COUNT]; unsigned int rom_bank = 0; unsigned int ram_bank = 0; unsigned int ram_enable = 0; unsigned int mbc1_mode = 0; unsigned int rtc_latch = 0; time_t rtc_last_time = 0; unsigned int enabled = GETDATA(curr, uint32_t); unsigned int bank = GETDATA(curr, uint32_t); unsigned int access_mode = GETDATA(curr, uint32_t); unsigned int access_mode_changed = GETDATA(curr, uint32_t); COPYARRAY(gb_fingerprint, curr, uint8_t, GB_CART_FINGERPRINT_SIZE); if (gb_fingerprint[0] != 0) { rom_bank = GETDATA(curr, uint32_t); ram_bank = GETDATA(curr, uint32_t); ram_enable = GETDATA(curr, uint32_t); mbc1_mode = GETDATA(curr, uint32_t); rtc_latch = GETDATA(curr, uint32_t); rtc_last_time = (time_t)GETDATA(curr, int64_t); COPYARRAY(rtc_regs, curr, uint8_t, MBC3_RTC_REGS_COUNT); COPYARRAY(rtc_latched_regs, curr, uint8_t, MBC3_RTC_REGS_COUNT); COPYARRAY(cam_regs, curr, uint8_t, POCKET_CAM_REGS_COUNT); } if (ROM_SETTINGS.transferpak && !Controls[i].RawData && (Controls[i].Type == CONT_TYPE_STANDARD)) { /* init transferpak state if enabled and not controlled by input plugin */ dev->transferpaks[i].enabled = enabled; dev->transferpaks[i].bank = bank; dev->transferpaks[i].access_mode = access_mode; dev->transferpaks[i].access_mode_changed = access_mode_changed; /* if it holds a valid cartridge init gbcart */ if (dev->transferpaks[i].gb_cart != NULL && dev->transferpaks[i].gb_cart->irom_storage != NULL) { const uint8_t* rom = dev->transferpaks[i].gb_cart->irom_storage->data (dev->transferpaks[i].gb_cart->rom_storage); /* verify that gb cart saved in savestate is the same * as what is currently inserted in transferpak */ if (gb_fingerprint[0] != 0 && memcmp(gb_fingerprint, rom + GB_CART_FINGERPRINT_OFFSET, GB_CART_FINGERPRINT_SIZE) == 0) { /* init gbcart state */ dev->transferpaks[i].gb_cart->rom_bank = rom_bank; dev->transferpaks[i].gb_cart->ram_bank = ram_bank; dev->transferpaks[i].gb_cart->ram_enable = ram_enable; dev->transferpaks[i].gb_cart->mbc1_mode = mbc1_mode; dev->transferpaks[i].gb_cart->rtc.latch = rtc_latch; dev->transferpaks[i].gb_cart->rtc.last_time = rtc_last_time; memcpy(dev->transferpaks[i].gb_cart->rtc.regs, rtc_regs, MBC3_RTC_REGS_COUNT); memcpy(dev->transferpaks[i].gb_cart->rtc.latched_regs, rtc_latched_regs, MBC3_RTC_REGS_COUNT); memcpy(dev->transferpaks[i].gb_cart->cam.regs, cam_regs, POCKET_CAM_REGS_COUNT); } else { DebugMessage(M64MSG_WARNING, "Savestate GB cart mismatch. Current GB cart: %s. Expected GB cart : %s", (rom[GB_CART_FINGERPRINT_OFFSET] == 0x00) ? "(none)" : (const char*)(rom + GB_CART_FINGERPRINT_OFFSET), (gb_fingerprint[0] == 0x00) ? "(none)" : gb_fingerprint); poweron_gb_cart(dev->transferpaks[i].gb_cart); } } } } /* extra pif channels state */ for (i = 0; i < PIF_CHANNELS_COUNT; ++i) { int offset = GETDATA(curr, int8_t); if (offset >= 0) { setup_pif_channel(&dev->pif.channels[i], dev->pif.ram + offset); } else { disable_pif_channel(&dev->pif.channels[i]); } } /* extra si state */ dev->si.dma_dir = GETDATA(curr, uint8_t); /* extra dp state */ dev->dp.do_on_unfreeze = GETDATA(curr, uint8_t); /* extra vi state */ dev->vi.count_per_scanline = GETDATA(curr, uint32_t); /* extra RDRAM register state */ for (i = 1; i < RDRAM_MAX_MODULES_COUNT; ++i) { dev->rdram.regs[i][RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_DELAY_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_MODE_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[i][RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t); } if (version >= 0x00010400) { /* verify if DD data is present (and matches what's currently loaded) */ uint32_t disk_id = GETDATA(curr, uint32_t); uint32_t* current_disk_id = ((dev->dd.rom_size > 0) && dev->dd.idisk != NULL) ? (uint32_t*)(dev->dd.idisk->data(dev->dd.disk) + DD_DISK_ID_OFFSET) : NULL; if (current_disk_id != NULL && *current_disk_id == disk_id) { dev->dd.regs[DD_ASIC_DATA] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_MISC_REG] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_CMD_STATUS] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_CUR_TK] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_BM_STATUS_CTL] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_ERR_SECTOR] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_SEQ_STATUS_CTL] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_CUR_SECTOR] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_HARD_RESET] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_C1_S0] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_HOST_SECBYTE] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_C1_S2] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_SEC_BYTE] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_C1_S4] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_C1_S6] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_CUR_ADDR] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_ID_REG] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_TEST_REG] = GETDATA(curr, uint32_t); dev->dd.regs[DD_ASIC_TEST_PIN_SEL] = GETDATA(curr, uint32_t); /* C2S buffer is expected to be always zero */ memset(dev->dd.c2s_buf, 0, 0x400); COPYARRAY(dev->dd.ds_buf, curr, uint8_t, 0x100); COPYARRAY(dev->dd.ms_ram, curr, uint8_t, 0x40); dev->dd.rtc.now = (time_t)GETDATA(curr, int64_t); dev->dd.rtc.last_update_rtc = (time_t)GETDATA(curr, int64_t); dev->dd.bm_write = (unsigned char)GETDATA(curr, uint32_t); dev->dd.bm_reset_held = (unsigned char)GETDATA(curr, uint32_t); curr += sizeof(uint32_t); /* was bm_block */ dev->dd.bm_zone = GETDATA(curr, uint32_t); curr += sizeof(uint32_t); /* was bm_track_offset */ } else { curr += (3+DD_ASIC_REGS_COUNT)*sizeof(uint32_t) + 0x100 + 0x40 + 2*sizeof(int64_t) + 2*sizeof(unsigned int); } } if (version >= 0x00010500) { #ifdef NEW_DYNAREC stop_after_jal = GETDATA(curr, uint32_t); #else curr += sizeof(uint32_t); #endif } if (version >= 0x00010700) { dev->sp.fifo[0].dir = GETDATA(curr, uint32_t); dev->sp.fifo[0].length = GETDATA(curr, uint32_t); dev->sp.fifo[0].memaddr = GETDATA(curr, uint32_t); dev->sp.fifo[0].dramaddr = GETDATA(curr, uint32_t); dev->sp.fifo[1].dir = GETDATA(curr, uint32_t); dev->sp.fifo[1].length = GETDATA(curr, uint32_t); dev->sp.fifo[1].memaddr = GETDATA(curr, uint32_t); dev->sp.fifo[1].dramaddr = GETDATA(curr, uint32_t); } else { memset(dev->sp.fifo, 0, SP_DMA_FIFO_SIZE*sizeof(struct sp_dma)); } if (version >= 0x00010800) { /* extra flashram state */ COPYARRAY(dev->cart.flashram.page_buf, curr, uint8_t, 128); COPYARRAY(dev->cart.flashram.silicon_id, curr, uint32_t, 2); dev->cart.flashram.status = GETDATA(curr, uint32_t); dev->cart.flashram.erase_page = GETDATA(curr, uint16_t); dev->cart.flashram.mode = GETDATA(curr, uint16_t); } if (version >= 0x00010900) { /* extra cp0 and cp2 state */ *r4300_cp0_latch(&dev->r4300.cp0) = GETDATA(curr, uint64_t); *r4300_cp2_latch(&dev->r4300.cp2) = GETDATA(curr, uint64_t); } } else { /* extra ai state */ dev->ai.last_read = 0; dev->ai.delayed_carry = 0; /* extra cart_rom state */ dev->cart.cart_rom.last_write = 0; /* extra af-rtc state */ dev->cart.af_rtc.control = 0x200; dev->cart.af_rtc.now = 0; dev->cart.af_rtc.last_update_rtc = 0; /* extra controllers state */ for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { /* skip controllers handled by the input plugin */ if (Controls[i].RawData) continue; dev->controllers[i].flavor->reset(&dev->controllers[i]); if (ROM_SETTINGS.rumble && (Controls[i].Type == CONT_TYPE_STANDARD)) { poweron_rumblepak(&dev->rumblepaks[i]); } if (ROM_SETTINGS.transferpak && (Controls[i].Type == CONT_TYPE_STANDARD)) { poweron_transferpak(&dev->transferpaks[i]); } } /* extra pif channels state * HACK: Assume PIF was in channel processing mode (and not in CIC challenge mode) * Try to parse pif ram to setup pif channels */ setup_channels_format(&dev->pif); /* extra vi state */ dev->vi.count_per_scanline = (dev->vi.regs[VI_V_SYNC_REG] == 0) ? 1500 : ((dev->vi.clock / dev->vi.expected_refresh_rate) / (dev->vi.regs[VI_V_SYNC_REG] + 1)); /* extra si state */ dev->si.dma_dir = SI_NO_DMA; /* extra dp state */ dev->dp.do_on_unfreeze = 0; /* extra rdram state * Best effort, copy values from RDRAM module 0 except for DEVICE_ID * which is set in accordance with the IPL3 procedure with 2M modules. */ for (i = 0; i < RDRAM_MAX_MODULES_COUNT; ++i) { memcpy(dev->rdram.regs[i], dev->rdram.regs[0], RDRAM_REGS_COUNT*sizeof(dev->rdram.regs[0][0])); dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(i * 0x200000) << 2; } /* dd state */ if (dev->dd.rom_size > 0 && dev->dd.idisk != NULL) { poweron_dd(&dev->dd); } } /* Zilmar-Spec plugin expect a call with control_id = -1 when RAM processing is done */ if (input.controllerCommand) { input.controllerCommand(-1, NULL); } /* reset fb state */ poweron_fb(&dev->dp.fb); dev->sp.rsp_task_locked = 0; dev->r4300.cp0.interrupt_unsafe_state = 0; *r4300_cp0_last_addr(&dev->r4300.cp0) = *r4300_pc(&dev->r4300); free(savestateData); main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State loaded from: %s", namefrompath(filepath)); return 1; } static int savestates_load_pj64(struct device* dev, char *filepath, void *handle, int (*read_func)(void *, void *, size_t)) { char buffer[1024]; unsigned int vi_timer, SaveRDRAMSize; size_t i; uint32_t FCR31; unsigned char header[8]; unsigned char RomHeader[0x40]; size_t savestateSize; unsigned char *savestateData, *curr; uint32_t* cp0_regs = r4300_cp0_regs(&dev->r4300.cp0); /* Read and check Project64 magic number. */ if (!read_func(handle, header, 8)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read header from Project64 savestate %s", filepath); return 0; } curr = header; if (memcmp(curr, pj64_magic, 4) != 0) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State file: %s is not a valid Project64 savestate. Unrecognized file format.", filepath); return 0; } curr += 4; SaveRDRAMSize = GETDATA(curr, uint32_t); /* Read the rest of the savestate into memory. */ savestateSize = SaveRDRAMSize + 0x2754; savestateData = curr = (unsigned char *)malloc(savestateSize); if (savestateData == NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to load state."); return 0; } if (!read_func(handle, savestateData, savestateSize)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not read savestate data from Project64 savestate %s", filepath); free(savestateData); return 0; } // check ROM header COPYARRAY(RomHeader, curr, unsigned int, 0x40/4); if(memcmp(RomHeader, dev->cart.cart_rom.rom, 0x40) != 0) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State ROM header does not match current ROM."); free(savestateData); return 0; } // vi_timer vi_timer = GETDATA(curr, uint32_t); // Program Counter *r4300_cp0_last_addr(&dev->r4300.cp0) = GETDATA(curr, uint32_t); // GPR COPYARRAY(r4300_regs(&dev->r4300), curr, int64_t, 32); // FPR cp1_reg *cp1_regs = r4300_cp1_regs(&dev->r4300.cp1); COPYARRAY(&cp1_regs->dword, curr, int64_t, 32); // CP0 COPYARRAY(cp0_regs, curr, uint32_t, CP0_REGS_COUNT); set_fpr_pointers(&dev->r4300.cp1, cp0_regs[CP0_STATUS_REG]); // Initialze the interrupts vi_timer += cp0_regs[CP0_COUNT_REG]; *r4300_cp0_next_interrupt(&dev->r4300.cp0) = (cp0_regs[CP0_COMPARE_REG] < vi_timer) ? cp0_regs[CP0_COMPARE_REG] : vi_timer; dev->vi.field = 0; *((unsigned int*)&buffer[0]) = VI_INT; *((unsigned int*)&buffer[4]) = vi_timer; *((unsigned int*)&buffer[8]) = COMPARE_INT; *((unsigned int*)&buffer[12]) = cp0_regs[CP0_COMPARE_REG]; *((unsigned int*)&buffer[16]) = 0xFFFFFFFF; load_eventqueue_infos(&dev->r4300.cp0, buffer); // FPCR *r4300_cp1_fcr0(&dev->r4300.cp1) = GETDATA(curr, uint32_t); curr += 30 * 4; // FCR1...FCR30 not supported FCR31 = GETDATA(curr, uint32_t); *r4300_cp1_fcr31(&dev->r4300.cp1) = FCR31; update_x86_rounding_mode(&dev->r4300.cp1); // hi / lo *r4300_mult_hi(&dev->r4300) = GETDATA(curr, int64_t); *r4300_mult_lo(&dev->r4300) = GETDATA(curr, int64_t); // rdram register dev->rdram.regs[0][RDRAM_CONFIG_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_DEVICE_ID_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_DELAY_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_MODE_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_REF_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_REF_ROW_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_RAS_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_MIN_INTERVAL_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_ADDR_SELECT_REG] = GETDATA(curr, uint32_t); dev->rdram.regs[0][RDRAM_DEVICE_MANUF_REG] = GETDATA(curr, uint32_t); // sp_register dev->sp.regs[SP_MEM_ADDR_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_RD_LEN_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_WR_LEN_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_STATUS_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_DMA_FULL_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_DMA_BUSY_REG] = GETDATA(curr, uint32_t); dev->sp.regs[SP_SEMAPHORE_REG] = GETDATA(curr, uint32_t); dev->sp.regs2[SP_PC_REG] = GETDATA(curr, uint32_t); dev->sp.regs2[SP_IBIST_REG] = GETDATA(curr, uint32_t); // dpc_register dev->dp.dpc_regs[DPC_START_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_END_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_CURRENT_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_STATUS_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_CLOCK_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_BUFBUSY_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_PIPEBUSY_REG] = GETDATA(curr, uint32_t); dev->dp.dpc_regs[DPC_TMEM_REG] = GETDATA(curr, uint32_t); (void)GETDATA(curr, uint32_t); // Dummy read (void)GETDATA(curr, uint32_t); // Dummy read // mi_register dev->mi.regs[MI_INIT_MODE_REG] = GETDATA(curr, uint32_t); dev->mi.regs[MI_VERSION_REG] = GETDATA(curr, uint32_t); dev->mi.regs[MI_INTR_REG] = GETDATA(curr, uint32_t); dev->mi.regs[MI_INTR_MASK_REG] = GETDATA(curr, uint32_t); // vi_register dev->vi.regs[VI_STATUS_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_ORIGIN_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_WIDTH_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_INTR_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_CURRENT_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_BURST_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_SYNC_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_H_SYNC_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_LEAP_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_H_START_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_START_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_V_BURST_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_X_SCALE_REG] = GETDATA(curr, uint32_t); dev->vi.regs[VI_Y_SCALE_REG] = GETDATA(curr, uint32_t); // TODO vi delay? gfx.viStatusChanged(); gfx.viWidthChanged(); dev->vi.count_per_scanline = (dev->vi.regs[VI_V_SYNC_REG] == 0) ? 1500 : ((dev->vi.clock / dev->vi.expected_refresh_rate) / (dev->vi.regs[VI_V_SYNC_REG] + 1)); /* extra si state */ dev->si.dma_dir = SI_NO_DMA; /* extra dp state */ dev->dp.do_on_unfreeze = 0; // ai_register dev->ai.regs[AI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_LEN_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_CONTROL_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_STATUS_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_DACRATE_REG] = GETDATA(curr, uint32_t); dev->ai.regs[AI_BITRATE_REG] = GETDATA(curr, uint32_t); dev->ai.samples_format_changed = 1; /* extra ai state */ dev->ai.last_read = 0; dev->ai.delayed_carry = 0; // pi_register dev->pi.regs[PI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_CART_ADDR_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_RD_LEN_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_WR_LEN_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_STATUS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_LAT_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_PWD_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_PGS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM1_RLS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_LAT_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_PWD_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_PGS_REG] = GETDATA(curr, uint32_t); dev->pi.regs[PI_BSD_DOM2_RLS_REG] = GETDATA(curr, uint32_t); read_func(handle, dev->pi.regs, PI_REGS_COUNT*sizeof(dev->pi.regs[0])); /* extra cart_rom state */ dev->cart.cart_rom.last_write = 0; // ri_register dev->ri.regs[RI_MODE_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_CONFIG_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_CURRENT_LOAD_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_SELECT_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_REFRESH_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_LATENCY_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_ERROR_REG] = GETDATA(curr, uint32_t); dev->ri.regs[RI_WERROR_REG] = GETDATA(curr, uint32_t); // si_register dev->si.regs[SI_DRAM_ADDR_REG] = GETDATA(curr, uint32_t); dev->si.regs[SI_PIF_ADDR_RD64B_REG] = GETDATA(curr, uint32_t); dev->si.regs[SI_PIF_ADDR_WR64B_REG] = GETDATA(curr, uint32_t); dev->si.regs[SI_STATUS_REG] = GETDATA(curr, uint32_t); // tlb memset(dev->r4300.cp0.tlb.LUT_r, 0, 0x400000); memset(dev->r4300.cp0.tlb.LUT_w, 0, 0x400000); for (i=0; i < 32; i++) { unsigned int MyPageMask, MyEntryHi, MyEntryLo0, MyEntryLo1; (void)GETDATA(curr, uint32_t); // Dummy read - EntryDefined MyPageMask = GETDATA(curr, uint32_t); MyEntryHi = GETDATA(curr, uint32_t); MyEntryLo0 = GETDATA(curr, uint32_t); MyEntryLo1 = GETDATA(curr, uint32_t); // This is copied from TLBWI instruction dev->r4300.cp0.tlb.entries[i].g = (MyEntryLo0 & MyEntryLo1 & 1); dev->r4300.cp0.tlb.entries[i].pfn_even = (MyEntryLo0 & 0x3FFFFFC0) >> 6; dev->r4300.cp0.tlb.entries[i].pfn_odd = (MyEntryLo1 & 0x3FFFFFC0) >> 6; dev->r4300.cp0.tlb.entries[i].c_even = (MyEntryLo0 & 0x38) >> 3; dev->r4300.cp0.tlb.entries[i].c_odd = (MyEntryLo1 & 0x38) >> 3; dev->r4300.cp0.tlb.entries[i].d_even = (MyEntryLo0 & 0x4) >> 2; dev->r4300.cp0.tlb.entries[i].d_odd = (MyEntryLo1 & 0x4) >> 2; dev->r4300.cp0.tlb.entries[i].v_even = (MyEntryLo0 & 0x2) >> 1; dev->r4300.cp0.tlb.entries[i].v_odd = (MyEntryLo1 & 0x2) >> 1; dev->r4300.cp0.tlb.entries[i].asid = (MyEntryHi & 0xFF); dev->r4300.cp0.tlb.entries[i].vpn2 = (MyEntryHi & 0xFFFFE000) >> 13; //dev->r4300.cp0.tlb.entries[i].r = (MyEntryHi & 0xC000000000000000LL) >> 62; dev->r4300.cp0.tlb.entries[i].mask = (MyPageMask & 0x1FFE000) >> 13; dev->r4300.cp0.tlb.entries[i].start_even = dev->r4300.cp0.tlb.entries[i].vpn2 << 13; dev->r4300.cp0.tlb.entries[i].end_even = dev->r4300.cp0.tlb.entries[i].start_even+ (dev->r4300.cp0.tlb.entries[i].mask << 12) + 0xFFF; dev->r4300.cp0.tlb.entries[i].phys_even = dev->r4300.cp0.tlb.entries[i].pfn_even << 12; dev->r4300.cp0.tlb.entries[i].start_odd = dev->r4300.cp0.tlb.entries[i].end_even+1; dev->r4300.cp0.tlb.entries[i].end_odd = dev->r4300.cp0.tlb.entries[i].start_odd+ (dev->r4300.cp0.tlb.entries[i].mask << 12) + 0xFFF; dev->r4300.cp0.tlb.entries[i].phys_odd = dev->r4300.cp0.tlb.entries[i].pfn_odd << 12; tlb_map(&dev->r4300.cp0.tlb, i); } // pif ram COPYARRAY(dev->pif.ram, curr, uint8_t, PIF_RAM_SIZE); /* extra pif channels state * HACK: Assume PIF was in channel processing mode (and not in CIC challenge mode) * Try to parse pif ram to setup pif channels */ setup_channels_format(&dev->pif); /* Zilmar-Spec plugin expect a call with control_id = -1 when RAM processing is done */ if (input.controllerCommand) { input.controllerCommand(-1, NULL); } // RDRAM memset(dev->rdram.dram, 0, RDRAM_MAX_SIZE); COPYARRAY(dev->rdram.dram, curr, uint32_t, SaveRDRAMSize/4); // DMEM + IMEM COPYARRAY(dev->sp.mem, curr, uint32_t, SP_MEM_SIZE/4); // The following values should not matter because we don't have any AI interrupt // dev->ai.fifo[1].delay = 0; dev->ai.fifo[1].length = 0; // dev->ai.fifo[0].delay = 0; dev->ai.fifo[0].length = 0; // The following is not available in PJ64 savestate. Keep the values as is. // dev->dp.dps_regs[DPS_TBIST_REG] = 0; dev->dp.dps_regs[DPS_TEST_MODE_REG] = 0; // dev->dp.dps_regs[DPS_BUFTEST_ADDR_REG] = 0; dev->dp.dps_regs[DPS_BUFTEST_DATA_REG] = 0; *r4300_llbit(&dev->r4300) = 0; // No flashram info in pj64 savestate. poweron_flashram(&dev->cart.flashram); dev->sp.rsp_task_locked = 0; dev->r4300.cp0.interrupt_unsafe_state = 0; /* extra fb state */ poweron_fb(&dev->dp.fb); /* extra af-rtc state */ dev->cart.af_rtc.control = 0x200; dev->cart.af_rtc.now = 0; dev->cart.af_rtc.last_update_rtc = 0; /* extra controllers state */ for(i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { /* skip controllers handled by the input plugin */ if (Controls[i].RawData) continue; dev->controllers[i].flavor->reset(&dev->controllers[i]); if (ROM_SETTINGS.rumble && (Controls[i].Type == CONT_TYPE_STANDARD)) { poweron_rumblepak(&dev->rumblepaks[i]); } if (ROM_SETTINGS.transferpak && (Controls[i].Type == CONT_TYPE_STANDARD)) { poweron_transferpak(&dev->transferpaks[i]); } } /* extra rdram state * Best effort, copy values from RDRAM module 0 except for DEVICE_ID * which is set in accordance with the IPL3 procedure with 2M modules. */ for (i = 0; i < (SaveRDRAMSize / 0x200000); ++i) { memcpy(dev->rdram.regs[i], dev->rdram.regs[0], RDRAM_REGS_COUNT*sizeof(dev->rdram.regs[0][0])); dev->rdram.regs[i][RDRAM_DEVICE_ID_REG] = ri_address_to_id_field(i * 0x200000) << 2; } /* dd state */ if (dev->dd.rom_size > 0 && dev->dd.idisk != NULL) { poweron_dd(&dev->dd); } savestates_load_set_pc(&dev->r4300, *r4300_cp0_last_addr(&dev->r4300.cp0)); // assert(savestateData+savestateSize == curr) free(savestateData); return 1; } static int read_data_from_zip(void *zip, void *buffer, size_t length) { int err = unzReadCurrentFile((unzFile)zip, buffer, (unsigned)length); return (err >= 0) && ((size_t)err == length); } static int savestates_load_pj64_zip(struct device* dev, char *filepath) { char szFileName[256], szExtraField[256], szComment[256]; unzFile zipstatefile = NULL; unz_file_info fileinfo; int ret = 0; /* Open the .zip file. */ zipstatefile = unzOpen(filepath); if (zipstatefile == NULL || unzGoToFirstFile(zipstatefile) != UNZ_OK || unzGetCurrentFileInfo(zipstatefile, &fileinfo, szFileName, 255, szExtraField, 255, szComment, 255) != UNZ_OK || unzOpenCurrentFile(zipstatefile) != UNZ_OK) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Zip error. Could not open state file: %s", filepath); goto clean_and_exit; } if (!savestates_load_pj64(dev, filepath, zipstatefile, read_data_from_zip)) goto clean_and_exit; main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State loaded from: %s", namefrompath(filepath)); ret = 1; clean_and_exit: if (zipstatefile != NULL) unzClose(zipstatefile); return ret; } static int read_data_from_file(void *file, void *buffer, size_t length) { return fread(buffer, 1, length, file) == length; } static int savestates_load_pj64_unc(struct device* dev, char *filepath) { FILE *f; /* Open the file. */ f = osal_file_open(filepath, "rb"); if (f == NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not open state file: %s", filepath); return 0; } if (!savestates_load_pj64(dev, filepath, f, read_data_from_file)) { fclose(f); return 0; } main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "State loaded from: %s", namefrompath(filepath)); fclose(f); return 1; } static savestates_type savestates_detect_type(char *filepath) { unsigned char magic[4]; FILE *f = osal_file_open(filepath, "rb"); if (f == NULL) { DebugMessage(M64MSG_STATUS, "Could not open state file %s\n", filepath); return savestates_type_unknown; } if (fread(magic, 1, 4, f) != 4) { fclose(f); DebugMessage(M64MSG_STATUS, "Could not read from state file %s\n", filepath); return savestates_type_unknown; } fclose(f); if (magic[0] == 0x1f && magic[1] == 0x8b) // GZIP header return savestates_type_m64p; else if (memcmp(magic, "PK\x03\x04", 4) == 0) // ZIP header return savestates_type_pj64_zip; else if (memcmp(magic, pj64_magic, 4) == 0) // PJ64 header return savestates_type_pj64_unc; else { DebugMessage(M64MSG_STATUS, "Unknown state file type %s\n", filepath); return savestates_type_unknown; } } int savestates_load(void) { FILE *fPtr = NULL; char *filepath = NULL; int ret = 0; if (fname == NULL) // For slots, autodetect the savestate type { // try M64P type first type = savestates_type_m64p; filepath = savestates_generate_path(type); fPtr = osal_file_open(filepath, "rb"); // can I open this? if (fPtr == NULL) { free(filepath); // try PJ64 zipped type second type = savestates_type_pj64_zip; filepath = savestates_generate_path(type); fPtr = osal_file_open(filepath, "rb"); // can I open this? if (fPtr == NULL) { free(filepath); // finally, try PJ64 uncompressed type = savestates_type_pj64_unc; filepath = savestates_generate_path(type); fPtr = osal_file_open(filepath, "rb"); // can I open this? if (fPtr == NULL) { free(filepath); filepath = NULL; main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "No Mupen64Plus/PJ64 state file found for slot %i", slot); type = savestates_type_unknown; } } } } else // filename of state file to load was set explicitly in 'fname' { // detect type if unknown if (type == savestates_type_unknown) { type = savestates_detect_type(fname); } filepath = savestates_generate_path(type); if (filepath != NULL) fPtr = osal_file_open(filepath, "rb"); // can I open this? if (fPtr == NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Failed to open savestate file %s", filepath); if (filepath != NULL) free(filepath); filepath = NULL; } } if (fPtr != NULL) fclose(fPtr); if (filepath != NULL) { struct device* dev = &g_dev; switch (type) { case savestates_type_m64p: ret = savestates_load_m64p(dev, filepath); break; case savestates_type_pj64_zip: ret = savestates_load_pj64_zip(dev, filepath); break; case savestates_type_pj64_unc: ret = savestates_load_pj64_unc(dev, filepath); break; default: ret = 0; break; } free(filepath); filepath = NULL; } // deliver callback to indicate completion of state loading operation StateChanged(M64CORE_STATE_LOADCOMPLETE, ret); savestates_clear_job(); return ret; } static void savestates_save_m64p_work(struct work_struct *work) { gzFile f; int gzres; struct savestate_work *save = container_of(work, struct savestate_work, work); SDL_LockMutex(savestates_lock); // Write the state to a GZIP file f = osal_gzopen(save->filepath, "wb"); if (f==NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not open state file: %s", save->filepath); free(save->data); StateChanged(M64CORE_STATE_SAVECOMPLETE, 0); return; } gzres = gzwrite(f, save->data, save->size); if ((gzres < 0) || ((size_t)gzres != save->size)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not write data to state file: %s", save->filepath); gzclose(f); free(save->data); StateChanged(M64CORE_STATE_SAVECOMPLETE, 0); return; } gzclose(f); main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Saved state to: %s", namefrompath(save->filepath)); free(save->data); free(save->filepath); free(save); SDL_UnlockMutex(savestates_lock); StateChanged(M64CORE_STATE_SAVECOMPLETE, 1); } static int savestates_save_m64p(const struct device* dev, char *filepath) { unsigned char outbuf[4]; int i; char queue[1024]; struct savestate_work *save; char *curr; /* OK to cast away const qualifier */ const uint32_t* cp0_regs = r4300_cp0_regs((struct cp0*)&dev->r4300.cp0); save = malloc(sizeof(*save)); if (!save) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to save state."); StateChanged(M64CORE_STATE_SAVECOMPLETE, 0); return 0; } save->filepath = strdup(filepath); if(autoinc_save_slot) savestates_inc_slot(); save_eventqueue_infos(&dev->r4300.cp0, queue); // Allocate memory for the save state data save->size = 16788288 + sizeof(queue) + 4 + 4096; save->data = curr = malloc(save->size); if (save->data == NULL) { free(save->filepath); free(save); main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to save state."); StateChanged(M64CORE_STATE_SAVECOMPLETE, 0); return 0; } memset(save->data, 0, save->size); // Write the save state data to memory PUTARRAY(savestate_magic, curr, unsigned char, 8); outbuf[0] = (savestate_latest_version >> 24) & 0xff; outbuf[1] = (savestate_latest_version >> 16) & 0xff; outbuf[2] = (savestate_latest_version >> 8) & 0xff; outbuf[3] = (savestate_latest_version >> 0) & 0xff; PUTARRAY(outbuf, curr, unsigned char, 4); PUTARRAY(ROM_SETTINGS.MD5, curr, char, 32); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_CONFIG_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_DEVICE_ID_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_DELAY_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_MODE_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_REF_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_REF_ROW_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_RAS_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_MIN_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_ADDR_SELECT_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_DEVICE_MANUF_REG]); PUTDATA(curr, uint32_t, 0); // Padding from old implementation PUTDATA(curr, uint32_t, dev->mi.regs[MI_INIT_MODE_REG]); PUTDATA(curr, uint8_t, dev->mi.regs[MI_INIT_MODE_REG] & 0x7F); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INIT_MODE_REG] & 0x80) != 0); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INIT_MODE_REG] & 0x100) != 0); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INIT_MODE_REG] & 0x200) != 0); PUTDATA(curr, uint32_t, dev->mi.regs[MI_VERSION_REG]); PUTDATA(curr, uint32_t, dev->mi.regs[MI_INTR_REG]); PUTDATA(curr, uint32_t, dev->mi.regs[MI_INTR_MASK_REG]); PUTDATA(curr, uint32_t, 0); //Padding from old implementation PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INTR_MASK_REG] & 0x1) != 0); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INTR_MASK_REG] & 0x2) != 0); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INTR_MASK_REG] & 0x4) != 0); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INTR_MASK_REG] & 0x8) != 0); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INTR_MASK_REG] & 0x10) != 0); PUTDATA(curr, uint8_t, (dev->mi.regs[MI_INTR_MASK_REG] & 0x20) != 0); PUTDATA(curr, uint16_t, 0); // Padding from old implementation PUTDATA(curr, uint32_t, dev->pi.regs[PI_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_CART_ADDR_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_RD_LEN_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_WR_LEN_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_STATUS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_LAT_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_PWD_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_PGS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_RLS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_LAT_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_PWD_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_PGS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_RLS_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_MEM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_RD_LEN_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_WR_LEN_REG]); PUTDATA(curr, uint32_t, 0); /* Padding from old implementation */ PUTDATA(curr, uint32_t, dev->sp.regs[SP_STATUS_REG]); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x1) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x2) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x4) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x8) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x10) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x20) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x40) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x80) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x100) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x200) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x400) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x800) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x1000) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x2000) != 0); PUTDATA(curr, uint8_t, (dev->sp.regs[SP_STATUS_REG] & 0x4000) != 0); PUTDATA(curr, uint8_t, 0); PUTDATA(curr, uint32_t, dev->sp.regs[SP_DMA_FULL_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_DMA_BUSY_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_SEMAPHORE_REG]); PUTDATA(curr, uint32_t, dev->sp.regs2[SP_PC_REG]); PUTDATA(curr, uint32_t, dev->sp.regs2[SP_IBIST_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_PIF_ADDR_RD64B_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_PIF_ADDR_WR64B_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_STATUS_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_STATUS_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_ORIGIN_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_WIDTH_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_INTR_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_CURRENT_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_BURST_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_SYNC_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_H_SYNC_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_LEAP_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_H_START_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_START_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_BURST_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_X_SCALE_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_Y_SCALE_REG]); PUTDATA(curr, uint32_t, dev->vi.delay); PUTDATA(curr, uint32_t, dev->ri.regs[RI_MODE_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_CONFIG_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_CURRENT_LOAD_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_SELECT_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_REFRESH_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_LATENCY_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_ERROR_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_WERROR_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_LEN_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_CONTROL_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_STATUS_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_DACRATE_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_BITRATE_REG]); PUTDATA(curr, uint32_t, dev->ai.fifo[1].duration); PUTDATA(curr, uint32_t , dev->ai.fifo[1].length); PUTDATA(curr, uint32_t, dev->ai.fifo[0].duration); PUTDATA(curr, uint32_t , dev->ai.fifo[0].length); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_START_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_END_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_CURRENT_REG]); PUTDATA(curr, uint32_t, 0); /* Padding from old implementation */ PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_STATUS_REG]); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x1) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x2) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x4) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x8) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x10) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x20) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x40) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x80) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x100) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x200) != 0); PUTDATA(curr, uint8_t, (dev->dp.dpc_regs[DPC_STATUS_REG] & 0x400) != 0); PUTDATA(curr, uint8_t, 0); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_CLOCK_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_BUFBUSY_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_PIPEBUSY_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_TMEM_REG]); PUTDATA(curr, uint32_t, dev->dp.dps_regs[DPS_TBIST_REG]); PUTDATA(curr, uint32_t, dev->dp.dps_regs[DPS_TEST_MODE_REG]); PUTDATA(curr, uint32_t, dev->dp.dps_regs[DPS_BUFTEST_ADDR_REG]); PUTDATA(curr, uint32_t, dev->dp.dps_regs[DPS_BUFTEST_DATA_REG]); PUTARRAY(dev->rdram.dram, curr, uint32_t, RDRAM_MAX_SIZE/4); PUTARRAY(dev->sp.mem, curr, uint32_t, SP_MEM_SIZE/4); PUTARRAY(dev->pif.ram, curr, uint8_t, PIF_RAM_SIZE); PUTDATA(curr, int32_t, dev->cart.use_flashram); curr += 4+8+4+4; // Here used to be flashram state PUTARRAY(dev->r4300.cp0.tlb.LUT_r, curr, uint32_t, 0x100000); PUTARRAY(dev->r4300.cp0.tlb.LUT_w, curr, uint32_t, 0x100000); /* OK to cast away const qualifier */ PUTDATA(curr, uint32_t, *r4300_llbit((struct r4300_core*)&dev->r4300)); PUTARRAY(r4300_regs((struct r4300_core*)&dev->r4300), curr, int64_t, 32); PUTARRAY(cp0_regs, curr, uint32_t, CP0_REGS_COUNT); PUTDATA(curr, int64_t, *r4300_mult_lo((struct r4300_core*)&dev->r4300)); PUTDATA(curr, int64_t, *r4300_mult_hi((struct r4300_core*)&dev->r4300)); const cp1_reg *cp1_regs = r4300_cp1_regs((struct cp1*)&dev->r4300.cp1); PUTARRAY(&cp1_regs->dword, curr, int64_t, 32); PUTDATA(curr, uint32_t, *r4300_cp1_fcr0((struct cp1*)&dev->r4300.cp1)); PUTDATA(curr, uint32_t, *r4300_cp1_fcr31((struct cp1*)&dev->r4300.cp1)); for (i = 0; i < 32; i++) { PUTDATA(curr, int16_t, dev->r4300.cp0.tlb.entries[i].mask); PUTDATA(curr, int16_t, 0); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].vpn2); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].g); PUTDATA(curr, unsigned char, dev->r4300.cp0.tlb.entries[i].asid); PUTDATA(curr, int16_t, 0); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].pfn_even); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].c_even); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].d_even); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].v_even); PUTDATA(curr, char, 0); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].pfn_odd); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].c_odd); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].d_odd); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].v_odd); PUTDATA(curr, char, dev->r4300.cp0.tlb.entries[i].r); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].start_even); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].end_even); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].phys_even); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].start_odd); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].end_odd); PUTDATA(curr, uint32_t, dev->r4300.cp0.tlb.entries[i].phys_odd); } PUTDATA(curr, uint32_t, *r4300_pc((struct r4300_core*)&dev->r4300)); PUTDATA(curr, uint32_t, *r4300_cp0_next_interrupt((struct cp0*)&dev->r4300.cp0)); PUTDATA(curr, uint32_t, 0); /* here there used to be next_vi */ PUTDATA(curr, uint32_t, dev->vi.field); to_little_endian_buffer(queue, 4, sizeof(queue)/4); PUTARRAY(queue, curr, char, sizeof(queue)); #ifdef NEW_DYNAREC PUTDATA(curr, uint32_t, using_tlb); #else PUTDATA(curr, uint32_t, 0); #endif PUTDATA(curr, uint32_t, dev->ai.last_read); PUTDATA(curr, uint32_t, dev->ai.delayed_carry); PUTDATA(curr, uint32_t, dev->cart.cart_rom.last_write); PUTDATA(curr, uint32_t, 0); /* used to be cart_rom.rom_written */ PUTDATA(curr, uint32_t, 0); /* here there used to be rsp_task_locked */ PUTDATA(curr, uint16_t, dev->cart.af_rtc.control); PUTDATA(curr, uint16_t, 0); /* padding to keep things aligned */ PUTDATA(curr, int64_t, dev->cart.af_rtc.now); PUTDATA(curr, int64_t, dev->cart.af_rtc.last_update_rtc); for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { PUTDATA(curr, uint8_t, dev->controllers[i].status); } for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { PUTDATA(curr, uint8_t, dev->rumblepaks[i].state); } for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i) { PUTDATA(curr, uint32_t, dev->transferpaks[i].enabled); PUTDATA(curr, uint32_t, dev->transferpaks[i].bank); PUTDATA(curr, uint32_t, dev->transferpaks[i].access_mode); PUTDATA(curr, uint32_t, dev->transferpaks[i].access_mode_changed); if (dev->transferpaks[i].gb_cart == NULL) { uint8_t gb_fingerprint[GB_CART_FINGERPRINT_SIZE]; memset(gb_fingerprint, 0, GB_CART_FINGERPRINT_SIZE); PUTARRAY(gb_fingerprint, curr, uint8_t, GB_CART_FINGERPRINT_SIZE); } else { uint8_t* rom = dev->transferpaks[i].gb_cart->irom_storage->data(dev->transferpaks[i].gb_cart->rom_storage); PUTARRAY(rom + GB_CART_FINGERPRINT_OFFSET, curr, uint8_t, GB_CART_FINGERPRINT_SIZE); PUTDATA(curr, uint32_t, dev->transferpaks[i].gb_cart->rom_bank); PUTDATA(curr, uint32_t, dev->transferpaks[i].gb_cart->ram_bank); PUTDATA(curr, uint32_t, dev->transferpaks[i].gb_cart->ram_enable); PUTDATA(curr, uint32_t, dev->transferpaks[i].gb_cart->mbc1_mode); PUTDATA(curr, uint32_t, dev->transferpaks[i].gb_cart->rtc.latch); PUTDATA(curr, int64_t, dev->transferpaks[i].gb_cart->rtc.last_time); PUTARRAY(dev->transferpaks[i].gb_cart->rtc.regs, curr, uint8_t, MBC3_RTC_REGS_COUNT); PUTARRAY(dev->transferpaks[i].gb_cart->rtc.latched_regs, curr, uint8_t, MBC3_RTC_REGS_COUNT); PUTARRAY(dev->transferpaks[i].gb_cart->cam.regs, curr, uint8_t, POCKET_CAM_REGS_COUNT); } } for (i = 0; i < PIF_CHANNELS_COUNT; ++i) { PUTDATA(curr, int8_t, (dev->pif.channels[i].tx == NULL) ? (int8_t)-1 : (int8_t)(dev->pif.channels[i].tx - dev->pif.ram)); } PUTDATA(curr, uint8_t, dev->si.dma_dir); PUTDATA(curr, uint8_t, dev->dp.do_on_unfreeze); PUTDATA(curr, uint32_t, dev->vi.count_per_scanline); for (i = 1; i < RDRAM_MAX_MODULES_COUNT; ++i) { PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_CONFIG_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_DEVICE_ID_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_DELAY_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_MODE_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_REF_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_REF_ROW_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_RAS_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_MIN_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_ADDR_SELECT_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[i][RDRAM_DEVICE_MANUF_REG]); } uint32_t* disk_id = ((dev->dd.rom_size > 0) && dev->dd.idisk != NULL) ? (uint32_t*)(dev->dd.idisk->data(dev->dd.disk) + DD_DISK_ID_OFFSET) : NULL; if (disk_id == NULL) { PUTDATA(curr, uint32_t, 0); curr += (3+DD_ASIC_REGS_COUNT)*sizeof(uint32_t) + 0x100 + 0x40 + 2*sizeof(int64_t) + 2*sizeof(uint32_t); } else { PUTDATA(curr, uint32_t, *disk_id); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_DATA]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_MISC_REG]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CMD_STATUS]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CUR_TK]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_BM_STATUS_CTL]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_ERR_SECTOR]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_SEQ_STATUS_CTL]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CUR_SECTOR]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_HARD_RESET]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S0]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_HOST_SECBYTE]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S2]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_SEC_BYTE]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S4]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_C1_S6]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_CUR_ADDR]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_ID_REG]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_TEST_REG]); PUTDATA(curr, uint32_t, dev->dd.regs[DD_ASIC_TEST_PIN_SEL]); PUTARRAY(dev->dd.ds_buf, curr, uint8_t, 0x100); PUTARRAY(dev->dd.ms_ram, curr, uint8_t, 0x40); PUTDATA(curr, int64_t, (int64_t)dev->dd.rtc.now); PUTDATA(curr, int64_t, (int64_t)dev->dd.rtc.last_update_rtc); PUTDATA(curr, uint32_t, dev->dd.bm_write); PUTDATA(curr, uint32_t, dev->dd.bm_reset_held); PUTDATA(curr, uint32_t, 0); /* was bm_track_block */ PUTDATA(curr, uint32_t, dev->dd.bm_zone); PUTDATA(curr, uint32_t, 0); /* was bm_track_offset */ } #ifdef NEW_DYNAREC PUTDATA(curr, uint32_t, stop_after_jal); #else PUTDATA(curr, uint32_t, 0); #endif PUTDATA(curr, uint32_t, dev->sp.fifo[0].dir); PUTDATA(curr, uint32_t, dev->sp.fifo[0].length); PUTDATA(curr, uint32_t, dev->sp.fifo[0].memaddr); PUTDATA(curr, uint32_t, dev->sp.fifo[0].dramaddr); PUTDATA(curr, uint32_t, dev->sp.fifo[1].dir); PUTDATA(curr, uint32_t, dev->sp.fifo[1].length); PUTDATA(curr, uint32_t, dev->sp.fifo[1].memaddr); PUTDATA(curr, uint32_t, dev->sp.fifo[1].dramaddr); /* extra flashram state (since 1.8) */ PUTARRAY(dev->cart.flashram.page_buf, curr, uint8_t, 128); PUTARRAY(dev->cart.flashram.silicon_id, curr, uint32_t, 2); PUTDATA(curr, uint32_t, dev->cart.flashram.status); PUTDATA(curr, uint16_t, dev->cart.flashram.erase_page); PUTDATA(curr, uint16_t, dev->cart.flashram.mode); /* cp0 and cp2 latch (since 1.9) */ PUTDATA(curr, uint64_t, *r4300_cp0_latch((struct cp0*)&dev->r4300.cp0)); PUTDATA(curr, uint64_t, *r4300_cp2_latch((struct cp2*)&dev->r4300.cp2)); init_work(&save->work, savestates_save_m64p_work); queue_work(&save->work); return 1; } static int savestates_save_pj64(const struct device* dev, char *filepath, void *handle, int (*write_func)(void *, const void *, size_t)) { unsigned int i; unsigned int SaveRDRAMSize = RDRAM_MAX_SIZE; size_t savestateSize; unsigned char *savestateData, *curr; const uint32_t* cp0_regs = r4300_cp0_regs((struct cp0*)&dev->r4300.cp0); // Allocate memory for the save state data savestateSize = 8 + SaveRDRAMSize + 0x2754; savestateData = curr = (unsigned char *)malloc(savestateSize); if (savestateData == NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Insufficient memory to save state."); return 0; } // Write the save state data in memory PUTARRAY(pj64_magic, curr, unsigned char, 4); PUTDATA(curr, unsigned int, SaveRDRAMSize); PUTARRAY(dev->cart.cart_rom.rom, curr, unsigned int, 0x40/4); uint32_t* next_vi = get_event(&dev->r4300.cp0.q, VI_INT); if (next_vi != NULL) PUTDATA(curr, uint32_t, *next_vi - cp0_regs[CP0_COUNT_REG]); // vi_timer else PUTDATA(curr, uint32_t, 0 - cp0_regs[CP0_COUNT_REG]); PUTDATA(curr, uint32_t, *r4300_pc((struct r4300_core*)&dev->r4300)); PUTARRAY(r4300_regs((struct r4300_core*)&dev->r4300), curr, int64_t, 32); const cp1_reg* cp1_regs = r4300_cp1_regs((struct cp1*)&dev->r4300.cp1); PUTARRAY(&cp1_regs->dword, curr, int64_t, 32); PUTARRAY(cp0_regs, curr, uint32_t, CP0_REGS_COUNT); PUTDATA(curr, uint32_t, *r4300_cp1_fcr0((struct cp1*)&dev->r4300.cp1)); for (i = 0; i < 30; i++) PUTDATA(curr, int, 0); // FCR1-30 not implemented PUTDATA(curr, uint32_t, *r4300_cp1_fcr31((struct cp1*)&dev->r4300.cp1)); PUTDATA(curr, int64_t, *r4300_mult_hi((struct r4300_core*)&dev->r4300)); PUTDATA(curr, int64_t, *r4300_mult_lo((struct r4300_core*)&dev->r4300)); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_CONFIG_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_DEVICE_ID_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_DELAY_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_MODE_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_REF_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_REF_ROW_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_RAS_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_MIN_INTERVAL_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_ADDR_SELECT_REG]); PUTDATA(curr, uint32_t, dev->rdram.regs[0][RDRAM_DEVICE_MANUF_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_MEM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_RD_LEN_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_WR_LEN_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_STATUS_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_DMA_FULL_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_DMA_BUSY_REG]); PUTDATA(curr, uint32_t, dev->sp.regs[SP_SEMAPHORE_REG]); PUTDATA(curr, uint32_t, dev->sp.regs2[SP_PC_REG]); PUTDATA(curr, uint32_t, dev->sp.regs2[SP_IBIST_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_START_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_END_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_CURRENT_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_STATUS_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_CLOCK_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_BUFBUSY_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_PIPEBUSY_REG]); PUTDATA(curr, uint32_t, dev->dp.dpc_regs[DPC_TMEM_REG]); PUTDATA(curr, uint32_t, 0); // ? PUTDATA(curr, uint32_t, 0); // ? PUTDATA(curr, uint32_t, dev->mi.regs[MI_INIT_MODE_REG]); //TODO Secial handling in pj64 PUTDATA(curr, uint32_t, dev->mi.regs[MI_VERSION_REG]); PUTDATA(curr, uint32_t, dev->mi.regs[MI_INTR_REG]); PUTDATA(curr, uint32_t, dev->mi.regs[MI_INTR_MASK_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_STATUS_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_ORIGIN_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_WIDTH_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_INTR_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_CURRENT_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_BURST_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_SYNC_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_H_SYNC_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_LEAP_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_H_START_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_START_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_V_BURST_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_X_SCALE_REG]); PUTDATA(curr, uint32_t, dev->vi.regs[VI_Y_SCALE_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_LEN_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_CONTROL_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_STATUS_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_DACRATE_REG]); PUTDATA(curr, uint32_t, dev->ai.regs[AI_BITRATE_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_CART_ADDR_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_RD_LEN_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_WR_LEN_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_STATUS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_LAT_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_PWD_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_PGS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM1_RLS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_LAT_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_PWD_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_PGS_REG]); PUTDATA(curr, uint32_t, dev->pi.regs[PI_BSD_DOM2_RLS_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_MODE_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_CONFIG_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_CURRENT_LOAD_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_SELECT_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_REFRESH_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_LATENCY_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_ERROR_REG]); PUTDATA(curr, uint32_t, dev->ri.regs[RI_WERROR_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_DRAM_ADDR_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_PIF_ADDR_RD64B_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_PIF_ADDR_WR64B_REG]); PUTDATA(curr, uint32_t, dev->si.regs[SI_STATUS_REG]); for (i=0; i < 32;i++) { // From TLBR unsigned int EntryDefined, MyPageMask, MyEntryHi, MyEntryLo0, MyEntryLo1; EntryDefined = dev->r4300.cp0.tlb.entries[i].v_even || dev->r4300.cp0.tlb.entries[i].v_odd; MyPageMask = dev->r4300.cp0.tlb.entries[i].mask << 13; MyEntryHi = ((dev->r4300.cp0.tlb.entries[i].vpn2 << 13) | dev->r4300.cp0.tlb.entries[i].asid); MyEntryLo0 = (dev->r4300.cp0.tlb.entries[i].pfn_even << 6) | (dev->r4300.cp0.tlb.entries[i].c_even << 3) | (dev->r4300.cp0.tlb.entries[i].d_even << 2) | (dev->r4300.cp0.tlb.entries[i].v_even << 1) | dev->r4300.cp0.tlb.entries[i].g; MyEntryLo1 = (dev->r4300.cp0.tlb.entries[i].pfn_odd << 6) | (dev->r4300.cp0.tlb.entries[i].c_odd << 3) | (dev->r4300.cp0.tlb.entries[i].d_odd << 2) | (dev->r4300.cp0.tlb.entries[i].v_odd << 1) | dev->r4300.cp0.tlb.entries[i].g; PUTDATA(curr, uint32_t, EntryDefined); PUTDATA(curr, uint32_t, MyPageMask); PUTDATA(curr, uint32_t, MyEntryHi); PUTDATA(curr, uint32_t, MyEntryLo0); PUTDATA(curr, uint32_t, MyEntryLo1); } PUTARRAY(dev->pif.ram, curr, uint8_t, PIF_RAM_SIZE); PUTARRAY(dev->rdram.dram, curr, uint32_t, SaveRDRAMSize/4); PUTARRAY(dev->sp.mem, curr, uint32_t, SP_MEM_SIZE/4); // Write the save state data to the output if (!write_func(handle, savestateData, savestateSize)) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Couldn't write data to Project64 state file %s.", filepath); free(savestateData); return 0; } // assert(savestateData+savestateSize == curr) free(savestateData); return 1; } static int write_data_to_zip(void *zip, const void *buffer, size_t length) { return zipWriteInFileInZip((zipFile)zip, buffer, (unsigned)length) == ZIP_OK; } static int savestates_save_pj64_zip(const struct device* dev, char *filepath) { int retval; zipFile zipfile = NULL; zipfile = zipOpen(filepath, APPEND_STATUS_CREATE); if(zipfile == NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not create PJ64 state file: %s", filepath); goto clean_and_exit; } retval = zipOpenNewFileInZip(zipfile, namefrompath(filepath), NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION); if(retval != ZIP_OK) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Zip error. Could not create state file: %s", filepath); goto clean_and_exit; } if (!savestates_save_pj64(dev, filepath, zipfile, write_data_to_zip)) goto clean_and_exit; main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Saved state to: %s", namefrompath(filepath)); clean_and_exit: if (zipfile != NULL) { zipCloseFileInZip(zipfile); // This may fail, but we don't care zipClose(zipfile, ""); } StateChanged(M64CORE_STATE_SAVECOMPLETE, 1); return 1; } static int write_data_to_file(void *file, const void *buffer, size_t length) { return fwrite(buffer, 1, length, (FILE *)file) == length; } static int savestates_save_pj64_unc(const struct device* dev, char *filepath) { FILE *f; f = osal_file_open(filepath, "wb"); if (f == NULL) { main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Could not create PJ64 state file: %s", filepath); StateChanged(M64CORE_STATE_SAVECOMPLETE, 0); return 0; } if (!savestates_save_pj64(dev, filepath, f, write_data_to_file)) { fclose(f); StateChanged(M64CORE_STATE_SAVECOMPLETE, 0); return 0; } main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "Saved state to: %s", namefrompath(filepath)); fclose(f); StateChanged(M64CORE_STATE_SAVECOMPLETE, 1); return 1; } int savestates_save(void) { char *filepath; int ret = 0; const struct device* dev = &g_dev; /* Can only save PJ64 savestates on VI / COMPARE interrupt. Otherwise try again in a little while. */ if ((type == savestates_type_pj64_zip || type == savestates_type_pj64_unc) && get_next_event_type(&dev->r4300.cp0.q) > COMPARE_INT) return 0; if (fname != NULL && type == savestates_type_unknown) type = savestates_type_m64p; else if (fname == NULL) // Always save slots in M64P format type = savestates_type_m64p; filepath = savestates_generate_path(type); if (filepath != NULL) { switch (type) { case savestates_type_m64p: ret = savestates_save_m64p(dev, filepath); break; case savestates_type_pj64_zip: ret = savestates_save_pj64_zip(dev, filepath); break; case savestates_type_pj64_unc: ret = savestates_save_pj64_unc(dev, filepath); break; default: ret = 0; StateChanged(M64CORE_STATE_SAVECOMPLETE, ret); break; } free(filepath); } else { StateChanged(M64CORE_STATE_SAVECOMPLETE, ret); } savestates_clear_job(); return ret; } void savestates_init(void) { savestates_lock = SDL_CreateMutex(); if (!savestates_lock) { DebugMessage(M64MSG_ERROR, "Could not create savestates list lock"); return; } } void savestates_deinit(void) { SDL_DestroyMutex(savestates_lock); savestates_clear_job(); } mupen64plus-core-src-2.6.0/src/main/savestates.h000066400000000000000000000047541464506436200215260ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - savestates.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 CasualJames * * Copyright (C) 2009 Olejl Tillin9 * * Copyright (C) 2008 Richard42 Tillin9 * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __SAVESTAVES_H__ #define __SAVESTAVES_H__ typedef enum _savestates_job { savestates_job_nothing, savestates_job_load, savestates_job_save } savestates_job; typedef enum _savestates_type { savestates_type_unknown, savestates_type_m64p, savestates_type_pj64_zip, savestates_type_pj64_unc } savestates_type; savestates_job savestates_get_job(void); void savestates_set_job(savestates_job j, savestates_type t, const char *fn); void savestates_init(void); void savestates_deinit(void); int savestates_load(void); int savestates_save(void); void savestates_select_slot(unsigned int s); unsigned int savestates_get_slot(void); void savestates_set_autoinc_slot(int b); void savestates_inc_slot(void); #endif /* __SAVESTAVES_H__ */ mupen64plus-core-src-2.6.0/src/main/screenshot.c000066400000000000000000000217251464506436200215110ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - screenshot.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Richard42 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include #include #include #include #define M64P_CORE_PROTOTYPES 1 #include "api/callbacks.h" #include "api/m64p_config.h" #include "api/m64p_types.h" #include "main/main.h" #include "main/rom.h" #include "main/util.h" #include "osal/files.h" #include "osal/preproc.h" #include "osd/osd.h" #include "plugin/plugin.h" /********************************************************************************************************* * PNG support functions for writing screenshot files */ static void mupen_png_error(png_structp png_write, const char *message) { DebugMessage(M64MSG_ERROR, "PNG Error: %s", message); } static void mupen_png_warn(png_structp png_write, const char *message) { DebugMessage(M64MSG_WARNING, "PNG Warning: %s", message); } static void user_write_data(png_structp png_write, png_bytep data, png_size_t length) { FILE *fPtr = (FILE *) png_get_io_ptr(png_write); if (fwrite(data, 1, length, fPtr) != length) DebugMessage(M64MSG_ERROR, "Failed to write %zi bytes to screenshot file.", length); } static void user_flush_data(png_structp png_write) { FILE *fPtr = (FILE *) png_get_io_ptr(png_write); fflush(fPtr); } /********************************************************************************************************* * Other Local (static) functions */ static int SaveRGBBufferToFile(const char *filename, const unsigned char *buf, int width, int height, int pitch) { int i; // allocate PNG structures png_structp png_write = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, mupen_png_error, mupen_png_warn); if (!png_write) { DebugMessage(M64MSG_ERROR, "Error creating PNG write struct."); return 1; } png_infop png_info = png_create_info_struct(png_write); if (!png_info) { png_destroy_write_struct(&png_write, (png_infopp)NULL); DebugMessage(M64MSG_ERROR, "Error creating PNG info struct."); return 2; } // Set the jumpback if (setjmp(png_jmpbuf(png_write))) { png_destroy_write_struct(&png_write, &png_info); DebugMessage(M64MSG_ERROR, "Error calling setjmp()"); return 3; } // open the file to write FILE *savefile = osal_file_open(filename, "wb"); if (savefile == NULL) { DebugMessage(M64MSG_ERROR, "Error opening '%s' to save screenshot.", filename); return 4; } // set function pointers in the PNG library, for write callbacks png_set_write_fn(png_write, (png_voidp) savefile, user_write_data, user_flush_data); // set the info png_set_IHDR(png_write, png_info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // allocate row pointers and scale each row to 24-bit color png_byte **row_pointers; row_pointers = (png_byte **) malloc(height * sizeof(png_bytep)); for (i = 0; i < height; i++) { row_pointers[i] = (png_byte *) (buf + (height - 1 - i) * pitch); } // set the row pointers png_set_rows(png_write, png_info, row_pointers); // write the picture to disk png_write_png(png_write, png_info, 0, NULL); // free memory free(row_pointers); png_destroy_write_struct(&png_write, &png_info); // close file fclose(savefile); // all done return 0; } static int CurrentShotIndex; static char *GetNextScreenshotPath(void) { char *ScreenshotPath; char ScreenshotFileName[60 + 8 + 1]; char *pch; // if there are any characters in the ROM header name with the highest bit set, // we assume it's encoded in Shift-JIS character set, and translate it to UTF-8 const unsigned char *pccNameChar = (unsigned char *) ROM_PARAMS.headername; while (*pccNameChar != 0) { if ((*pccNameChar & 0x80) == 0x80) break; pccNameChar++; } if (*pccNameChar == 0) { // generate the base name of the screenshot // add the ROM name, convert to lowercase, convert spaces to underscores strcpy(ScreenshotFileName, ROM_PARAMS.headername); for (pch = ScreenshotFileName; *pch != '\0'; pch++) *pch = ((*pch == ' ') || (*pch == ':')) ? '_' : tolower(*pch); } else { ShiftJis2UTF8((unsigned char *) ROM_PARAMS.headername, (unsigned char *) ScreenshotFileName, sizeof(ScreenshotFileName)); for (pch = ScreenshotFileName; *pch != '\0'; pch++) { if (*pch == ' ' || *pch == ':') *pch = '_'; } } strcat(ScreenshotFileName, "-###.png"); // add the base path to the screenshot file name const char *SshotDir = ConfigGetParamString(g_CoreConfig, "ScreenshotPath"); if (SshotDir == NULL || *SshotDir == '\0') { // note the trick to avoid an allocation. we add a NUL character // instead of the separator, call mkdir, then add the separator ScreenshotPath = formatstr("%sscreenshot%c%s", ConfigGetUserDataPath(), '\0', ScreenshotFileName); if (ScreenshotPath == NULL) return NULL; osal_mkdirp(ScreenshotPath, 0700); ScreenshotPath[strlen(ScreenshotPath)] = OSAL_DIR_SEPARATORS[0]; } else { ScreenshotPath = combinepath(SshotDir, ScreenshotFileName); if (ScreenshotPath == NULL) return NULL; } // patch the number part of the name (the '###' part) until we find a free spot char *NumberPtr = ScreenshotPath + strlen(ScreenshotPath) - 7; for (; CurrentShotIndex < 1000; CurrentShotIndex++) { sprintf(NumberPtr, "%03i.png", CurrentShotIndex); FILE *pFile = osal_file_open(ScreenshotPath, "r"); if (pFile == NULL) break; fclose(pFile); } if (CurrentShotIndex >= 1000) { DebugMessage(M64MSG_ERROR, "Can't save screenshot; folder already contains 1000 screenshots for this ROM"); free(ScreenshotPath); return NULL; } CurrentShotIndex++; return ScreenshotPath; } /********************************************************************************************************* * Global screenshot functions */ void ScreenshotRomOpen(void) { CurrentShotIndex = 0; } void TakeScreenshot(int iFrameNumber) { char *filename; // look for an unused screenshot filename filename = GetNextScreenshotPath(); if (filename == NULL) { StateChanged(M64CORE_SCREENSHOT_CAPTURED, 0); return; } // get the width and height int width = 640; int height = 480; gfx.readScreen(NULL, &width, &height, 0); // allocate memory for the image unsigned char *pucFrame = (unsigned char *) malloc(width * height * 3); if (pucFrame == NULL) { StateChanged(M64CORE_SCREENSHOT_CAPTURED, 0); free(filename); return; } // grab the back image from OpenGL by calling the video plugin gfx.readScreen(pucFrame, &width, &height, 0); // write the image to a PNG int rval = SaveRGBBufferToFile(filename, pucFrame, width, height, width * 3); // free the memory free(pucFrame); free(filename); // print message -- this allows developers to capture frames and use them in the regression test if (rval != 0) { StateChanged(M64CORE_SCREENSHOT_CAPTURED, 0); } else { main_message(M64MSG_INFO, OSD_BOTTOM_LEFT, "Captured screenshot for frame %i.", iFrameNumber); StateChanged(M64CORE_SCREENSHOT_CAPTURED, 1); } } mupen64plus-core-src-2.6.0/src/main/screenshot.h000066400000000000000000000032221464506436200215060ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - screenshot.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Richard42 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef M64P_MAIN_SCREENSHOT_H #define M64P_MAIN_SCREENSHOT_H void ScreenshotRomOpen(void); void TakeScreenshot(int iFrameNumber); #endif mupen64plus-core-src-2.6.0/src/main/sdl_key_converter.c000066400000000000000000001075741464506436200230640ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - sdl_key_converter.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2013 Mupen64plus development team * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "sdl_key_converter.h" #include #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) uint16_t sdl_keysym2scancode(uint16_t keysym) { static const uint16_t keysym2scancode[323] = { 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x002au, /* SDLK_BACKSPACE -> SDL_SCANCODE_BACKSPACE */ 0x002bu, /* SDLK_TAB -> SDL_SCANCODE_TAB */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x009cu, /* SDLK_CLEAR -> SDL_SCANCODE_CLEAR */ 0x0028u, /* SDLK_RETURN -> SDL_SCANCODE_RETURN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0048u, /* SDLK_PAUSE -> SDL_SCANCODE_PAUSE */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0029u, /* SDLK_ESCAPE -> SDL_SCANCODE_ESCAPE */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x002cu, /* SDLK_SPACE -> SDL_SCANCODE_SPACE */ 0x0000u, /* SDLK_EXCLAIM -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_QUOTEDBL -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_HASH -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_DOLLAR -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_AMPERSAND -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_QUOTE -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_LEFTPAREN -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_RIGHTPAREN -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_ASTERISK -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_PLUS -> SDL_SCANCODE_UNKNOWN */ 0x0036u, /* SDLK_COMMA -> SDL_SCANCODE_COMMA */ 0x002du, /* SDLK_MINUS -> SDL_SCANCODE_MINUS */ 0x0037u, /* SDLK_PERIOD -> SDL_SCANCODE_PERIOD */ 0x0038u, /* SDLK_SLASH -> SDL_SCANCODE_SLASH */ 0x0027u, /* SDLK_0 -> SDL_SCANCODE_0 */ 0x001eu, /* SDLK_1 -> SDL_SCANCODE_1 */ 0x001fu, /* SDLK_2 -> SDL_SCANCODE_2 */ 0x0020u, /* SDLK_3 -> SDL_SCANCODE_3 */ 0x0021u, /* SDLK_4 -> SDL_SCANCODE_4 */ 0x0022u, /* SDLK_5 -> SDL_SCANCODE_5 */ 0x0023u, /* SDLK_6 -> SDL_SCANCODE_6 */ 0x0024u, /* SDLK_7 -> SDL_SCANCODE_7 */ 0x0025u, /* SDLK_8 -> SDL_SCANCODE_8 */ 0x0026u, /* SDLK_9 -> SDL_SCANCODE_9 */ 0x0000u, /* SDLK_COLON -> SDL_SCANCODE_UNKNOWN */ 0x0033u, /* SDLK_SEMICOLON -> SDL_SCANCODE_SEMICOLON */ 0x0000u, /* SDLK_LESS -> SDL_SCANCODE_UNKNOWN */ 0x002eu, /* SDLK_EQUALS -> SDL_SCANCODE_EQUALS */ 0x0000u, /* SDLK_GREATER -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_QUESTION -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_AT -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x002fu, /* SDLK_LEFTBRACKET -> SDL_SCANCODE_LEFTBRACKET */ 0x0031u, /* SDLK_BACKSLASH -> SDL_SCANCODE_BACKSLASH */ 0x0030u, /* SDLK_RIGHTBRACKET -> SDL_SCANCODE_RIGHTBRACKET */ 0x0000u, /* SDLK_CARET -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_UNDERSCORE -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_BACKQUOTE -> SDL_SCANCODE_UNKNOWN */ 0x0004u, /* SDLK_a -> SDL_SCANCODE_A */ 0x0005u, /* SDLK_b -> SDL_SCANCODE_B */ 0x0006u, /* SDLK_c -> SDL_SCANCODE_C */ 0x0007u, /* SDLK_d -> SDL_SCANCODE_D */ 0x0008u, /* SDLK_e -> SDL_SCANCODE_E */ 0x0009u, /* SDLK_f -> SDL_SCANCODE_F */ 0x000au, /* SDLK_g -> SDL_SCANCODE_G */ 0x000bu, /* SDLK_h -> SDL_SCANCODE_H */ 0x000cu, /* SDLK_i -> SDL_SCANCODE_I */ 0x000du, /* SDLK_j -> SDL_SCANCODE_J */ 0x000eu, /* SDLK_k -> SDL_SCANCODE_K */ 0x000fu, /* SDLK_l -> SDL_SCANCODE_L */ 0x0010u, /* SDLK_m -> SDL_SCANCODE_M */ 0x0011u, /* SDLK_n -> SDL_SCANCODE_N */ 0x0012u, /* SDLK_o -> SDL_SCANCODE_O */ 0x0013u, /* SDLK_p -> SDL_SCANCODE_P */ 0x0014u, /* SDLK_q -> SDL_SCANCODE_Q */ 0x0015u, /* SDLK_r -> SDL_SCANCODE_R */ 0x0016u, /* SDLK_s -> SDL_SCANCODE_S */ 0x0017u, /* SDLK_t -> SDL_SCANCODE_T */ 0x0018u, /* SDLK_u -> SDL_SCANCODE_U */ 0x0019u, /* SDLK_v -> SDL_SCANCODE_V */ 0x001au, /* SDLK_w -> SDL_SCANCODE_W */ 0x001bu, /* SDLK_x -> SDL_SCANCODE_X */ 0x001cu, /* SDLK_y -> SDL_SCANCODE_Y */ 0x001du, /* SDLK_z -> SDL_SCANCODE_Z */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x004cu, /* SDLK_DELETE -> SDL_SCANCODE_DELETE */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_0 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_1 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_2 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_3 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_4 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_5 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_6 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_7 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_8 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_9 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_10 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_11 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_12 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_13 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_14 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_15 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_16 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_17 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_18 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_19 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_20 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_21 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_22 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_23 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_24 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_25 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_26 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_27 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_28 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_29 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_30 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_31 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_32 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_33 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_34 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_35 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_36 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_37 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_38 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_39 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_40 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_41 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_42 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_43 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_44 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_45 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_46 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_47 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_48 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_49 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_50 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_51 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_52 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_53 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_54 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_55 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_56 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_57 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_58 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_59 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_60 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_61 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_62 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_63 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_64 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_65 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_66 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_67 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_68 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_69 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_70 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_71 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_72 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_73 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_74 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_75 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_76 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_77 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_78 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_79 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_80 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_81 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_82 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_83 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_84 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_85 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_86 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_87 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_88 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_89 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_90 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_91 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_92 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_93 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_94 -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_WORLD_95 -> SDL_SCANCODE_UNKNOWN */ 0x0062u, /* SDLK_KP0 -> SDL_SCANCODE_KP_0 */ 0x0059u, /* SDLK_KP1 -> SDL_SCANCODE_KP_1 */ 0x005au, /* SDLK_KP2 -> SDL_SCANCODE_KP_2 */ 0x005bu, /* SDLK_KP3 -> SDL_SCANCODE_KP_3 */ 0x005cu, /* SDLK_KP4 -> SDL_SCANCODE_KP_4 */ 0x005du, /* SDLK_KP5 -> SDL_SCANCODE_KP_5 */ 0x005eu, /* SDLK_KP6 -> SDL_SCANCODE_KP_6 */ 0x005fu, /* SDLK_KP7 -> SDL_SCANCODE_KP_7 */ 0x0060u, /* SDLK_KP8 -> SDL_SCANCODE_KP_8 */ 0x0061u, /* SDLK_KP9 -> SDL_SCANCODE_KP_9 */ 0x0063u, /* SDLK_KP_PERIOD -> SDL_SCANCODE_KP_PERIOD */ 0x0054u, /* SDLK_KP_DIVIDE -> SDL_SCANCODE_KP_DIVIDE */ 0x0055u, /* SDLK_KP_MULTIPLY -> SDL_SCANCODE_KP_MULTIPLY */ 0x0056u, /* SDLK_KP_MINUS -> SDL_SCANCODE_KP_MINUS */ 0x0057u, /* SDLK_KP_PLUS -> SDL_SCANCODE_KP_PLUS */ 0x0058u, /* SDLK_KP_ENTER -> SDL_SCANCODE_KP_ENTER */ 0x0067u, /* SDLK_KP_EQUALS -> SDL_SCANCODE_KP_EQUALS */ 0x0052u, /* SDLK_UP -> SDL_SCANCODE_UP */ 0x0051u, /* SDLK_DOWN -> SDL_SCANCODE_DOWN */ 0x004fu, /* SDLK_RIGHT -> SDL_SCANCODE_RIGHT */ 0x0050u, /* SDLK_LEFT -> SDL_SCANCODE_LEFT */ 0x0049u, /* SDLK_INSERT -> SDL_SCANCODE_INSERT */ 0x004au, /* SDLK_HOME -> SDL_SCANCODE_HOME */ 0x004du, /* SDLK_END -> SDL_SCANCODE_END */ 0x004bu, /* SDLK_PAGEUP -> SDL_SCANCODE_PAGEUP */ 0x004eu, /* SDLK_PAGEDOWN -> SDL_SCANCODE_PAGEDOWN */ 0x003au, /* SDLK_F1 -> SDL_SCANCODE_F1 */ 0x003bu, /* SDLK_F2 -> SDL_SCANCODE_F2 */ 0x003cu, /* SDLK_F3 -> SDL_SCANCODE_F3 */ 0x003du, /* SDLK_F4 -> SDL_SCANCODE_F4 */ 0x003eu, /* SDLK_F5 -> SDL_SCANCODE_F5 */ 0x003fu, /* SDLK_F6 -> SDL_SCANCODE_F6 */ 0x0040u, /* SDLK_F7 -> SDL_SCANCODE_F7 */ 0x0041u, /* SDLK_F8 -> SDL_SCANCODE_F8 */ 0x0042u, /* SDLK_F9 -> SDL_SCANCODE_F9 */ 0x0043u, /* SDLK_F10 -> SDL_SCANCODE_F10 */ 0x0044u, /* SDLK_F11 -> SDL_SCANCODE_F11 */ 0x0045u, /* SDLK_F12 -> SDL_SCANCODE_F12 */ 0x0068u, /* SDLK_F13 -> SDL_SCANCODE_F13 */ 0x0069u, /* SDLK_F14 -> SDL_SCANCODE_F14 */ 0x006au, /* SDLK_F15 -> SDL_SCANCODE_F15 */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* unassigned -> SDL_SCANCODE_UNKNOWN */ 0x0053u, /* SDLK_NUMLOCK -> SDL_SCANCODE_NUMLOCKCLEAR */ 0x0039u, /* SDLK_CAPSLOCK -> SDL_SCANCODE_CAPSLOCK */ 0x0000u, /* SDLK_SCROLLOCK -> SDL_SCANCODE_UNKNOWN */ 0x00e5u, /* SDLK_RSHIFT -> SDL_SCANCODE_RSHIFT */ 0x00e1u, /* SDLK_LSHIFT -> SDL_SCANCODE_LSHIFT */ 0x00e4u, /* SDLK_RCTRL -> SDL_SCANCODE_RCTRL */ 0x00e0u, /* SDLK_LCTRL -> SDL_SCANCODE_LCTRL */ 0x00e6u, /* SDLK_RALT -> SDL_SCANCODE_RALT */ 0x00e2u, /* SDLK_LALT -> SDL_SCANCODE_LALT */ 0x0000u, /* SDLK_RMETA -> SDL_SCANCODE_UNKNOWN */ 0x0000u, /* SDLK_LMETA -> SDL_SCANCODE_UNKNOWN */ 0x00e3u, /* SDLK_LSUPER -> SDL_SCANCODE_LGUI */ 0x00e7u, /* SDLK_RSUPER -> SDL_SCANCODE_RGUI */ 0x0101u, /* SDLK_MODE -> SDL_SCANCODE_MODE */ 0x0000u, /* SDLK_COMPOSE -> SDL_SCANCODE_UNKNOWN */ 0x0075u, /* SDLK_HELP -> SDL_SCANCODE_HELP */ 0x0000u, /* SDLK_PRINT -> SDL_SCANCODE_UNKNOWN */ 0x009au, /* SDLK_SYSREQ -> SDL_SCANCODE_SYSREQ */ 0x0000u, /* SDLK_BREAK -> SDL_SCANCODE_UNKNOWN */ 0x0076u, /* SDLK_MENU -> SDL_SCANCODE_MENU */ 0x0066u, /* SDLK_POWER -> SDL_SCANCODE_POWER */ 0x0000u, /* SDLK_EURO -> SDL_SCANCODE_UNKNOWN */ 0x007au, /* SDLK_UNDO -> SDL_SCANCODE_UNDO */ }; if (keysym >= ARRAY_SIZE(keysym2scancode)) return 0; return keysym2scancode[keysym]; } uint16_t sdl_scancode2keysym(uint16_t scancode) { static const uint16_t scancode2keysym[285] = { 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0061u, /* SDL_SCANCODE_A -> SDLK_a */ 0x0062u, /* SDL_SCANCODE_B -> SDLK_b */ 0x0063u, /* SDL_SCANCODE_C -> SDLK_c */ 0x0064u, /* SDL_SCANCODE_D -> SDLK_d */ 0x0065u, /* SDL_SCANCODE_E -> SDLK_e */ 0x0066u, /* SDL_SCANCODE_F -> SDLK_f */ 0x0067u, /* SDL_SCANCODE_G -> SDLK_g */ 0x0068u, /* SDL_SCANCODE_H -> SDLK_h */ 0x0069u, /* SDL_SCANCODE_I -> SDLK_i */ 0x006au, /* SDL_SCANCODE_J -> SDLK_j */ 0x006bu, /* SDL_SCANCODE_K -> SDLK_k */ 0x006cu, /* SDL_SCANCODE_L -> SDLK_l */ 0x006du, /* SDL_SCANCODE_M -> SDLK_m */ 0x006eu, /* SDL_SCANCODE_N -> SDLK_n */ 0x006fu, /* SDL_SCANCODE_O -> SDLK_o */ 0x0070u, /* SDL_SCANCODE_P -> SDLK_p */ 0x0071u, /* SDL_SCANCODE_Q -> SDLK_q */ 0x0072u, /* SDL_SCANCODE_R -> SDLK_r */ 0x0073u, /* SDL_SCANCODE_S -> SDLK_s */ 0x0074u, /* SDL_SCANCODE_T -> SDLK_t */ 0x0075u, /* SDL_SCANCODE_U -> SDLK_u */ 0x0076u, /* SDL_SCANCODE_V -> SDLK_v */ 0x0077u, /* SDL_SCANCODE_W -> SDLK_w */ 0x0078u, /* SDL_SCANCODE_X -> SDLK_x */ 0x0079u, /* SDL_SCANCODE_Y -> SDLK_y */ 0x007au, /* SDL_SCANCODE_Z -> SDLK_z */ 0x0031u, /* SDL_SCANCODE_1 -> SDLK_1 */ 0x0032u, /* SDL_SCANCODE_2 -> SDLK_2 */ 0x0033u, /* SDL_SCANCODE_3 -> SDLK_3 */ 0x0034u, /* SDL_SCANCODE_4 -> SDLK_4 */ 0x0035u, /* SDL_SCANCODE_5 -> SDLK_5 */ 0x0036u, /* SDL_SCANCODE_6 -> SDLK_6 */ 0x0037u, /* SDL_SCANCODE_7 -> SDLK_7 */ 0x0038u, /* SDL_SCANCODE_8 -> SDLK_8 */ 0x0039u, /* SDL_SCANCODE_9 -> SDLK_9 */ 0x0030u, /* SDL_SCANCODE_0 -> SDLK_0 */ 0x000du, /* SDL_SCANCODE_RETURN -> SDLK_RETURN */ 0x001bu, /* SDL_SCANCODE_ESCAPE -> SDLK_ESCAPE */ 0x0008u, /* SDL_SCANCODE_BACKSPACE -> SDLK_BACKSPACE */ 0x0009u, /* SDL_SCANCODE_TAB -> SDLK_TAB */ 0x0020u, /* SDL_SCANCODE_SPACE -> SDLK_SPACE */ 0x002du, /* SDL_SCANCODE_MINUS -> SDLK_MINUS */ 0x003du, /* SDL_SCANCODE_EQUALS -> SDLK_EQUALS */ 0x005bu, /* SDL_SCANCODE_LEFTBRACKET -> SDLK_LEFTBRACKET */ 0x005du, /* SDL_SCANCODE_RIGHTBRACKET -> SDLK_RIGHTBRACKET */ 0x005cu, /* SDL_SCANCODE_BACKSLASH -> SDLK_BACKSLASH */ 0x0000u, /* SDL_SCANCODE_NONUSHASH -> SDLK_UNKNOWN */ 0x003bu, /* SDL_SCANCODE_SEMICOLON -> SDLK_SEMICOLON */ 0x0000u, /* SDL_SCANCODE_APOSTROPHE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_GRAVE -> SDLK_UNKNOWN */ 0x002cu, /* SDL_SCANCODE_COMMA -> SDLK_COMMA */ 0x002eu, /* SDL_SCANCODE_PERIOD -> SDLK_PERIOD */ 0x002fu, /* SDL_SCANCODE_SLASH -> SDLK_SLASH */ 0x012du, /* SDL_SCANCODE_CAPSLOCK -> SDLK_CAPSLOCK */ 0x011au, /* SDL_SCANCODE_F1 -> SDLK_F1 */ 0x011bu, /* SDL_SCANCODE_F2 -> SDLK_F2 */ 0x011cu, /* SDL_SCANCODE_F3 -> SDLK_F3 */ 0x011du, /* SDL_SCANCODE_F4 -> SDLK_F4 */ 0x011eu, /* SDL_SCANCODE_F5 -> SDLK_F5 */ 0x011fu, /* SDL_SCANCODE_F6 -> SDLK_F6 */ 0x0120u, /* SDL_SCANCODE_F7 -> SDLK_F7 */ 0x0121u, /* SDL_SCANCODE_F8 -> SDLK_F8 */ 0x0122u, /* SDL_SCANCODE_F9 -> SDLK_F9 */ 0x0123u, /* SDL_SCANCODE_F10 -> SDLK_F10 */ 0x0124u, /* SDL_SCANCODE_F11 -> SDLK_F11 */ 0x0125u, /* SDL_SCANCODE_F12 -> SDLK_F12 */ 0x0000u, /* SDL_SCANCODE_PRINTSCREEN -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_SCROLLLOCK -> SDLK_UNKNOWN */ 0x0013u, /* SDL_SCANCODE_PAUSE -> SDLK_PAUSE */ 0x0115u, /* SDL_SCANCODE_INSERT -> SDLK_INSERT */ 0x0116u, /* SDL_SCANCODE_HOME -> SDLK_HOME */ 0x0118u, /* SDL_SCANCODE_PAGEUP -> SDLK_PAGEUP */ 0x007fu, /* SDL_SCANCODE_DELETE -> SDLK_DELETE */ 0x0117u, /* SDL_SCANCODE_END -> SDLK_END */ 0x0119u, /* SDL_SCANCODE_PAGEDOWN -> SDLK_PAGEDOWN */ 0x0113u, /* SDL_SCANCODE_RIGHT -> SDLK_RIGHT */ 0x0114u, /* SDL_SCANCODE_LEFT -> SDLK_LEFT */ 0x0112u, /* SDL_SCANCODE_DOWN -> SDLK_DOWN */ 0x0111u, /* SDL_SCANCODE_UP -> SDLK_UP */ 0x012cu, /* SDL_SCANCODE_NUMLOCKCLEAR -> SDLK_NUMLOCK */ 0x010bu, /* SDL_SCANCODE_KP_DIVIDE -> SDLK_KP_DIVIDE */ 0x010cu, /* SDL_SCANCODE_KP_MULTIPLY -> SDLK_KP_MULTIPLY */ 0x010du, /* SDL_SCANCODE_KP_MINUS -> SDLK_KP_MINUS */ 0x010eu, /* SDL_SCANCODE_KP_PLUS -> SDLK_KP_PLUS */ 0x010fu, /* SDL_SCANCODE_KP_ENTER -> SDLK_KP_ENTER */ 0x0101u, /* SDL_SCANCODE_KP_1 -> SDLK_KP1 */ 0x0102u, /* SDL_SCANCODE_KP_2 -> SDLK_KP2 */ 0x0103u, /* SDL_SCANCODE_KP_3 -> SDLK_KP3 */ 0x0104u, /* SDL_SCANCODE_KP_4 -> SDLK_KP4 */ 0x0105u, /* SDL_SCANCODE_KP_5 -> SDLK_KP5 */ 0x0106u, /* SDL_SCANCODE_KP_6 -> SDLK_KP6 */ 0x0107u, /* SDL_SCANCODE_KP_7 -> SDLK_KP7 */ 0x0108u, /* SDL_SCANCODE_KP_8 -> SDLK_KP8 */ 0x0109u, /* SDL_SCANCODE_KP_9 -> SDLK_KP9 */ 0x0100u, /* SDL_SCANCODE_KP_0 -> SDLK_KP0 */ 0x010au, /* SDL_SCANCODE_KP_PERIOD -> SDLK_KP_PERIOD */ 0x0000u, /* SDL_SCANCODE_NONUSBACKSLASH -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_APPLICATION -> SDLK_UNKNOWN */ 0x0140u, /* SDL_SCANCODE_POWER -> SDLK_POWER */ 0x0110u, /* SDL_SCANCODE_KP_EQUALS -> SDLK_KP_EQUALS */ 0x0126u, /* SDL_SCANCODE_F13 -> SDLK_F13 */ 0x0127u, /* SDL_SCANCODE_F14 -> SDLK_F14 */ 0x0128u, /* SDL_SCANCODE_F15 -> SDLK_F15 */ 0x0000u, /* SDL_SCANCODE_F16 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F17 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F18 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F19 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F20 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F21 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F22 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F23 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_F24 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_EXECUTE -> SDLK_UNKNOWN */ 0x013bu, /* SDL_SCANCODE_HELP -> SDLK_HELP */ 0x013fu, /* SDL_SCANCODE_MENU -> SDLK_MENU */ 0x0000u, /* SDL_SCANCODE_SELECT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_STOP -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AGAIN -> SDLK_UNKNOWN */ 0x0142u, /* SDL_SCANCODE_UNDO -> SDLK_UNDO */ 0x0000u, /* SDL_SCANCODE_CUT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_COPY -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_PASTE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_FIND -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_MUTE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_VOLUMEUP -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_VOLUMEDOWN -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_COMMA -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_EQUALSAS400 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL1 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL2 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL3 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL4 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL5 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL6 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL7 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL8 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_INTERNATIONAL9 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG1 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG2 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG3 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG4 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG5 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG6 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG7 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG8 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_LANG9 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_ALTERASE -> SDLK_UNKNOWN */ 0x013du, /* SDL_SCANCODE_SYSREQ -> SDLK_SYSREQ */ 0x0000u, /* SDL_SCANCODE_CANCEL -> SDLK_UNKNOWN */ 0x000cu, /* SDL_SCANCODE_CLEAR -> SDLK_CLEAR */ 0x0000u, /* SDL_SCANCODE_PRIOR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_RETURN2 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_SEPARATOR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_OUT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_OPER -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_CLEARAGAIN -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_CRSEL -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_EXSEL -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_00 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_000 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_THOUSANDSSEPARATOR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_DECIMALSEPARATOR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_CURRENCYUNIT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_CURRENCYSUBUNIT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_LEFTPAREN -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_RIGHTPAREN -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_LEFTBRACE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_RIGHTBRACE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_TAB -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_BACKSPACE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_A -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_B -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_C -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_D -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_E -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_F -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_XOR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_POWER -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_PERCENT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_LESS -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_GREATER -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_AMPERSAND -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_DBLAMPERSAND -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_VERTICALBAR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_DBLVERTICALBAR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_COLON -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_HASH -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_SPACE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_AT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_EXCLAM -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_MEMSTORE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_MEMRECALL -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_MEMCLEAR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_MEMADD -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_MEMSUBTRACT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_MEMMULTIPLY -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_MEMDIVIDE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_PLUSMINUS -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_CLEAR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_CLEARENTRY -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_BINARY -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_OCTAL -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_DECIMAL -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KP_HEXADECIMAL -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0132u, /* SDL_SCANCODE_LCTRL -> SDLK_LCTRL */ 0x0130u, /* SDL_SCANCODE_LSHIFT -> SDLK_LSHIFT */ 0x0134u, /* SDL_SCANCODE_LALT -> SDLK_LALT */ 0x0137u, /* SDL_SCANCODE_LGUI -> SDLK_LSUPER */ 0x0131u, /* SDL_SCANCODE_RCTRL -> SDLK_RCTRL */ 0x012fu, /* SDL_SCANCODE_RSHIFT -> SDLK_RSHIFT */ 0x0133u, /* SDL_SCANCODE_RALT -> SDLK_RALT */ 0x0138u, /* SDL_SCANCODE_RGUI -> SDLK_RSUPER */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0000u, /* unassigned -> SDLK_UNKNOWN */ 0x0139u, /* SDL_SCANCODE_MODE -> SDLK_MODE */ 0x0000u, /* SDL_SCANCODE_AUDIONEXT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AUDIOPREV -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AUDIOSTOP -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AUDIOPLAY -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AUDIOMUTE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_MEDIASELECT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_WWW -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_MAIL -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_CALCULATOR -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_COMPUTER -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AC_SEARCH -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AC_HOME -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AC_BACK -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AC_FORWARD -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AC_STOP -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AC_REFRESH -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_AC_BOOKMARKS -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_BRIGHTNESSDOWN -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_BRIGHTNESSUP -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_DISPLAYSWITCH -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KBDILLUMTOGGLE -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KBDILLUMDOWN -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_KBDILLUMUP -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_EJECT -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_SLEEP -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_APP1 -> SDLK_UNKNOWN */ 0x0000u, /* SDL_SCANCODE_APP2 -> SDLK_UNKNOWN */ }; if (scancode >= ARRAY_SIZE(scancode2keysym)) return 0; return scancode2keysym[scancode]; } mupen64plus-core-src-2.6.0/src/main/sdl_key_converter.h000066400000000000000000000041341464506436200230550ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - sdl_key_converter.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2013 Mupen64plus development team * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "osal/preproc.h" uint16_t sdl_keysym2scancode(uint16_t keysym); uint16_t sdl_scancode2keysym(uint16_t scancode); #if SDL_VERSION_ATLEAST(1,3,0) static osal_inline uint16_t sdl_keysym2native(uint16_t keysym) { return sdl_keysym2scancode(keysym); } static osal_inline uint16_t sdl_native2keysym(uint16_t native) { return sdl_scancode2keysym(native); } #else static osal_inline uint16_t sdl_keysym2native(uint16_t keysym) { return keysym; } static osal_inline uint16_t sdl_native2keysym(uint16_t native) { return native; } #endif mupen64plus-core-src-2.6.0/src/main/util.c000066400000000000000000004621471464506436200203200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - util.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2020 Richard42 * * Copyright (C) 2012 CasualJames * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * Provides common utilities to the rest of the code: * -String functions */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS #include #include "osal/files.h" #include "osal/preproc.h" #include "rom.h" #include "util.h" /********************** File utilities **********************/ file_status_t read_from_file(const char *filename, void *data, size_t size) { FILE *f = osal_file_open(filename, "rb"); if (f == NULL) { return file_open_error; } if (fread(data, 1, size, f) != size) { fclose(f); return file_read_error; } fclose(f); return file_ok; } file_status_t write_to_file(const char *filename, const void *data, size_t size) { FILE *f = osal_file_open(filename, "wb"); if (f == NULL) { return file_open_error; } if (fwrite(data, 1, size, f) != size) { fclose(f); return file_write_error; } fclose(f); return file_ok; } file_status_t write_chunk_to_file(const char *filename, const void *data, size_t size, size_t offset) { FILE *f; /* first try to open with rb+ to avoid wiping existing content, * otherwise create file */ if ((f = osal_file_open(filename, "rb+")) == NULL) { if ((f = osal_file_open(filename, "wb")) == NULL) { return file_open_error; } } /* According to POSIX fseek past file size is supported and will fill with zeros bytes * (and use sparse file if supported). * So we can use it to position next write operation at desired offset. */ if (fseek(f, offset, SEEK_SET)) { fclose(f); return file_open_error; } if (fwrite(data, 1, size, f) != size) { fclose(f); return file_write_error; } fclose(f); return file_ok; } file_status_t load_file(const char* filename, void** buffer, size_t* size) { FILE* fd; size_t l_size, bytes_read; void* l_buffer; int err; file_status_t ret; /* open file */ ret = file_open_error; fd = osal_file_open(filename, "rb"); if (fd == NULL) { return file_open_error; } /* obtain file size */ ret = file_size_error; err = fseek(fd, 0, SEEK_END); if (err != 0) { goto close_file; } err = ftell(fd); if (err == -1) { goto close_file; } l_size = (size_t)err; err = fseek(fd, 0, SEEK_SET); if (err != 0) { goto close_file; } /* allocate buffer */ l_buffer = malloc(l_size); if (l_buffer == NULL) { goto close_file; } /* copy file content to buffer */ ret = file_read_error; bytes_read = fread(l_buffer, 1, l_size, fd); if (bytes_read != l_size) { free(l_buffer); goto close_file; } /* commit buffer,size */ ret = file_ok; *buffer = l_buffer; *size = l_size; /* close file */ close_file: fclose(fd); return ret; } file_status_t get_file_size(const char* filename, size_t* size) { FILE* fd; int err; file_status_t ret; /* open file */ ret = file_open_error; fd = osal_file_open(filename, "rb"); if (fd == NULL) { return file_open_error; } /* obtain file size */ ret = file_size_error; err = fseek(fd, 0, SEEK_END); if (err != 0) { goto close_file; } err = ftell(fd); if (err == -1) { goto close_file; } ret = file_ok; *size = (size_t)err; /* close file */ close_file: fclose(fd); return ret; } /********************** Byte swap utilities **********************/ void swap_buffer(void *buffer, size_t length, size_t count) { size_t i; if (length == 2) { uint16_t *pun = (uint16_t *) buffer; for (i = 0; i < count; i++) pun[i] = m64p_swap16(pun[i]); } else if (length == 4) { uint32_t *pun = (uint32_t *) buffer; for (i = 0; i < count; i++) pun[i] = m64p_swap32(pun[i]); } else if (length == 8) { uint64_t *pun = (uint64_t *) buffer; for (i = 0; i < count; i++) pun[i] = m64p_swap64(pun[i]); } } void to_little_endian_buffer(void *buffer, size_t length, size_t count) { #if defined(M64P_BIG_ENDIAN) swap_buffer(buffer, length, count); #endif } void to_big_endian_buffer(void *buffer, size_t length, size_t count) { #if !defined(M64P_BIG_ENDIAN) swap_buffer(buffer, length, count); #endif } /* Simple serialization primitives, * Use byte access to avoid alignment issues. */ uint8_t load_beu8(const unsigned char *ptr) { return (uint8_t)ptr[0]; } uint16_t load_beu16(const unsigned char *ptr) { return ((uint16_t)ptr[0] << 8) | ((uint16_t)ptr[1] << 0); } uint32_t load_beu32(const unsigned char *ptr) { return ((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) | ((uint32_t)ptr[2] << 8) | ((uint32_t)ptr[3] << 0); } uint64_t load_beu64(const unsigned char *ptr) { return ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1] << 48) | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3] << 32) | ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5] << 16) | ((uint64_t)ptr[6] << 8) | ((uint64_t)ptr[7] << 0); } uint8_t load_leu8(const unsigned char *ptr) { return (uint8_t)ptr[0]; } uint16_t load_leu16(const unsigned char *ptr) { return ((uint16_t)ptr[0] << 0) | ((uint16_t)ptr[1] << 8); } uint32_t load_leu32(const unsigned char *ptr) { return ((uint32_t)ptr[0] << 0) | ((uint32_t)ptr[1] << 8) | ((uint32_t)ptr[2] << 16) | ((uint32_t)ptr[3] << 24); } uint64_t load_leu64(const unsigned char *ptr) { return ((uint64_t)ptr[0] << 0) | ((uint64_t)ptr[1] << 8) | ((uint64_t)ptr[2] << 16) | ((uint64_t)ptr[3] << 24) | ((uint64_t)ptr[4] << 32) | ((uint64_t)ptr[5] << 40) | ((uint64_t)ptr[6] << 48) | ((uint64_t)ptr[7] << 56); } void store_beu8(uint8_t value, unsigned char *ptr) { ptr[0] = (uint8_t)value; } void store_beu16(uint16_t value, unsigned char *ptr) { ptr[0] = (uint8_t)(value >> 8); ptr[1] = (uint8_t)(value >> 0); } void store_beu32(uint32_t value, unsigned char *ptr) { ptr[0] = (uint8_t)(value >> 24); ptr[1] = (uint8_t)(value >> 16); ptr[2] = (uint8_t)(value >> 8); ptr[3] = (uint8_t)(value >> 0); } void store_beu64(uint64_t value, unsigned char *ptr) { ptr[0] = (uint8_t)(value >> 56); ptr[1] = (uint8_t)(value >> 48); ptr[2] = (uint8_t)(value >> 40); ptr[3] = (uint8_t)(value >> 32); ptr[4] = (uint8_t)(value >> 24); ptr[5] = (uint8_t)(value >> 16); ptr[6] = (uint8_t)(value >> 8); ptr[7] = (uint8_t)(value >> 0); } void store_leu8(uint8_t value, unsigned char *ptr) { ptr[0] = (uint8_t)value; } void store_leu16(uint16_t value, unsigned char *ptr) { ptr[0] = (uint8_t)(value >> 0); ptr[1] = (uint8_t)(value >> 8); } void store_leu32(uint32_t value, unsigned char *ptr) { ptr[0] = (uint8_t)(value >> 0); ptr[1] = (uint8_t)(value >> 8); ptr[2] = (uint8_t)(value >> 16); ptr[3] = (uint8_t)(value >> 24); } void store_leu64(uint64_t value, unsigned char *ptr) { ptr[0] = (uint8_t)(value >> 0); ptr[1] = (uint8_t)(value >> 8); ptr[2] = (uint8_t)(value >> 16); ptr[3] = (uint8_t)(value >> 24); ptr[4] = (uint8_t)(value >> 32); ptr[5] = (uint8_t)(value >> 40); ptr[6] = (uint8_t)(value >> 48); ptr[7] = (uint8_t)(value >> 56); } /********************** Random utilities **********************/ static inline uint64_t rotl(uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } struct splitmix64_state { uint64_t x; }; static uint64_t splitmix64_next(struct splitmix64_state* s) { uint64_t z = (s->x += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; return z ^ (z >> 31); } struct xoshiro256pp_state xoshiro256pp_seed(uint64_t seed) { struct xoshiro256pp_state xs; struct splitmix64_state ss = { seed }; size_t i; for (i = 0; i < 4; ++i) { xs.s[i] = splitmix64_next(&ss); } return xs; } uint64_t xoshiro256pp_next(struct xoshiro256pp_state* s) { uint64_t result = rotl(s->s[0] + s->s[3], 23) + s->s[0]; uint64_t t = s->s[1] << 17; s->s[2] ^= s->s[0]; s->s[3] ^= s->s[1]; s->s[1] ^= s->s[2]; s->s[0] ^= s->s[3]; s->s[2] ^= t; s->s[3] = rotl(s->s[3], 45); return result; } /********************** GUI utilities **********************/ void countrycodestring(uint16_t countrycode, char *string) { switch (countrycode) { case 0: /* Demo */ strcpy(string, "Demo"); break; case '7': /* Beta */ strcpy(string, "Beta"); break; case 0x41: /* Japan / USA */ strcpy(string, "USA/Japan"); break; case 0x44: /* Germany */ strcpy(string, "Germany"); break; case 0x45: /* USA */ strcpy(string, "USA"); break; case 0x46: /* France */ strcpy(string, "France"); break; case 'I': /* Italy */ strcpy(string, "Italy"); break; case 0x4A: /* Japan */ strcpy(string, "Japan"); break; case 'S': /* Spain */ strcpy(string, "Spain"); break; case 0x55: case 0x59: /* Australia */ sprintf(string, "Australia (0x%02" PRIX16 ")", countrycode); break; case 0x50: case 0x58: case 0x20: case 0x21: case 0x38: case 0x70: sprintf(string, "Europe (0x%02" PRIX16 ")", countrycode); break; default: sprintf(string, "Unknown (0x%02" PRIX16 ")", countrycode); break; } } void imagestring(unsigned char imagetype, char *string) { switch (imagetype) { case Z64IMAGE: strcpy(string, ".z64 (native)"); break; case V64IMAGE: strcpy(string, ".v64 (byteswapped)"); break; case N64IMAGE: strcpy(string, ".n64 (wordswapped)"); break; default: string[0] = '\0'; } } /********************** Path utilities **********************/ const char* namefrompath(const char* path) { const char* last_separator_ptr = strpbrk_reverse(OSAL_DIR_SEPARATORS, (char*)path, strlen(path)); if (last_separator_ptr != NULL) return last_separator_ptr + 1; else return path; } static int is_path_separator(char c) { return strchr(OSAL_DIR_SEPARATORS, c) != NULL; } char* combinepath(const char* first, const char *second) { size_t len_first, off_second = 0; if (first == NULL || second == NULL) return NULL; len_first = strlen(first); while (is_path_separator(first[len_first-1])) len_first--; while (is_path_separator(second[off_second])) off_second++; return formatstr("%.*s%c%s", (int) len_first, first, OSAL_DIR_SEPARATORS[0], second + off_second); } /********************** String utilities **********************/ char* strpbrk_reverse(const char* needles, char* haystack, size_t haystack_len) { size_t counter; for (counter = haystack_len; counter > 0; --counter) { if (strchr(needles, haystack[counter-1])) break; } if (counter == 0) return NULL; return haystack + counter - 1; } char *trim(char *str) { char *start = str, *end = str + strlen(str); while (start < end && isspace((unsigned char)(*start))) start++; while (end > start && isspace((unsigned char)(*(end-1)))) end--; memmove(str, start, end - start); str[end - start] = '\0'; return str; } int string_replace_chars(char* str, const char* chars, const char r) { int i, y; int str_size, chars_size; int replacements = 0; str_size = strlen(str); chars_size = strlen(chars); for (i = 0; i < str_size; i++) { for (y = 0; y < chars_size; y++) { if (str[i] == chars[y]) { str[i] = r; replacements++; break; } } } return replacements; } int string_to_int(const char *str, int *result) { char *endptr; long int n; if (*str == '\0' || isspace((unsigned char)(*str))) return 0; errno = 0; n = strtol(str, &endptr, 10); if (*endptr != '\0' || errno != 0 || n < INT_MIN || n > INT_MAX) return 0; *result = (int)n; return 1; } static unsigned char char2hex(char c) { c = tolower(c); if(c >= '0' && c <= '9') return c - '0'; else if(c >= 'a' && c <= 'f') return c - 'a' + 10; else return 0xFF; } int parse_hex(const char *str, unsigned char *output, size_t output_size) { size_t i, j; for (i = 0; i < output_size; i++) { output[i] = 0; for (j = 0; j < 2; j++) { unsigned char h = char2hex(*str++); if (h == 0xFF) return 0; output[i] = (output[i] << 4) | h; } } if (*str != '\0') return 0; return 1; } char *formatstr(const char *fmt, ...) { int size = 128, ret; char *str = (char *)malloc(size), *newstr; va_list args; /* There are two implementations of vsnprintf we have to deal with: * C99 version: Returns the number of characters which would have been written * if the buffer had been large enough, and -1 on failure. * Windows version: Returns the number of characters actually written, * and -1 on failure or truncation. * NOTE: An implementation equivalent to the Windows one appears in glibc <2.1. */ while (str != NULL) { va_start(args, fmt); ret = vsnprintf(str, size, fmt, args); va_end(args); // Successful result? if (ret >= 0 && ret < size) return str; // Increment the capacity of the buffer if (ret >= size) size = ret + 1; // C99 version: We got the needed buffer size else size *= 2; // Windows version: Keep guessing newstr = (char *)realloc(str, size); if (newstr == NULL) free(str); str = newstr; } return NULL; } ini_line ini_parse_line(char **lineptr) { char *line = *lineptr, *endline = strchr(*lineptr, '\n'), *equal; ini_line l; // Null terminate the current line and point to the next line if (endline != NULL) *endline = '\0'; *lineptr = line + strlen(line) + 1; // Parse the line contents trim(line); if (line[0] == '#' || line[0] == ';') { line++; l.type = INI_COMMENT; l.name = NULL; l.value = trim(line); } else if (line[0] == '[' && line[strlen(line)-1] == ']') { line[strlen(line)-1] = '\0'; line++; l.type = INI_SECTION; l.name = trim(line); l.value = NULL; } else if ((equal = strchr(line, '=')) != NULL) { char *name = line, *value = equal + 1; *equal = '\0'; l.type = INI_PROPERTY; l.name = trim(name); l.value = trim(value); } else { l.type = (*line == '\0') ? INI_BLANK : INI_TRASH; l.name = NULL; l.value = NULL; } return l; } static uint8_t pucTable[25088] = { 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0, 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64, 0, 65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83, 0, 84, 0, 85, 0, 86, 0, 87, 0, 88, 0, 89, 0, 90, 0, 91, 0,165, 0, 93, 0, 94, 0, 95, 0, 96, 0, 97, 0, 98, 0, 99, 0,100, 0,101, 0,102, 0,103, 0,104, 0,105, 0,106, 0,107, 0,108, 0,109, 0,110, 0,111, 0,112, 0,113, 0,114, 0,115, 0,116, 0,117, 0,118, 0,119, 0,120, 0,121, 0,122, 0,123, 0,124, 0,125, 32, 62, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,255, 97,255, 98,255, 99,255,100,255,101,255,102,255,103, 255,104,255,105,255,106,255,107,255,108,255,109,255,110,255,111,255,112,255,113,255,114,255,115, 255,116,255,117,255,118,255,119,255,120,255,121,255,122,255,123,255,124,255,125,255,126,255,127, 255,128,255,129,255,130,255,131,255,132,255,133,255,134,255,135,255,136,255,137,255,138,255,139, 255,140,255,141,255,142,255,143,255,144,255,145,255,146,255,147,255,148,255,149,255,150,255,151, 255,152,255,153,255,154,255,155,255,156,255,157,255,158,255,159, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 48, 0, 48, 1, 48, 2,255, 12,255, 14, 48,251,255, 26,255, 27,255, 31,255, 1, 48,155, 48,156, 0,180,255, 64, 0,168,255, 62,255,227,255, 63, 48,253, 48,254, 48,157, 48,158, 48, 3, 78,221, 48, 5, 48, 6, 48, 7, 48,252, 32, 21, 32, 16,255, 15, 0, 92, 48, 28, 32, 22,255, 92, 32, 38, 32, 37, 32, 24, 32, 25, 32, 28, 32, 29,255, 8,255, 9, 48, 20, 48, 21,255, 59,255, 61,255, 91, 255, 93, 48, 8, 48, 9, 48, 10, 48, 11, 48, 12, 48, 13, 48, 14, 48, 15, 48, 16, 48, 17,255, 11, 34, 18, 0,177, 0,215, 0, 32, 0,247,255, 29, 34, 96,255, 28,255, 30, 34,102, 34,103, 34, 30, 34, 52, 38, 66, 38, 64, 0,176, 32, 50, 32, 51, 33, 3,255,229,255, 4, 0,162, 0,163,255, 5, 255, 3,255, 6,255, 10,255, 32, 0,167, 38, 6, 38, 5, 37,203, 37,207, 37,206, 37,199, 37,198, 37,161, 37,160, 37,179, 37,178, 37,189, 37,188, 32, 59, 48, 18, 33,146, 33,144, 33,145, 33,147, 48, 19, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 34, 8, 34, 11, 34,134, 34,135, 34,130, 34,131, 34, 42, 34, 41, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 34, 39, 34, 40, 0,172, 33,210, 33,212, 34, 0, 34, 3, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 34, 32, 34,165, 35, 18, 34, 2, 34, 7, 34, 97, 34, 82, 34,106, 34,107, 34, 26, 34, 61, 34, 29, 34, 53, 34, 43, 34, 44, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 33, 43, 32, 48, 38,111, 38,109, 38,106, 32, 32, 32, 33, 0,182, 0, 32, 0, 32, 0, 32, 0, 32, 37,239, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,255, 16,255, 17,255, 18,255, 19,255, 20, 255, 21,255, 22,255, 23,255, 24,255, 25, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 255, 33,255, 34,255, 35,255, 36,255, 37,255, 38,255, 39,255, 40,255, 41,255, 42,255, 43,255, 44, 255, 45,255, 46,255, 47,255, 48,255, 49,255, 50,255, 51,255, 52,255, 53,255, 54,255, 55,255, 56, 255, 57,255, 58, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,255, 65,255, 66,255, 67, 255, 68,255, 69,255, 70,255, 71,255, 72,255, 73,255, 74,255, 75,255, 76,255, 77,255, 78,255, 79, 255, 80,255, 81,255, 82,255, 83,255, 84,255, 85,255, 86,255, 87,255, 88,255, 89,255, 90, 0, 32, 0, 32, 0, 32, 0, 32, 48, 65, 48, 66, 48, 67, 48, 68, 48, 69, 48, 70, 48, 71, 48, 72, 48, 73, 48, 74, 48, 75, 48, 76, 48, 77, 48, 78, 48, 79, 48, 80, 48, 81, 48, 82, 48, 83, 48, 84, 48, 85, 48, 86, 48, 87, 48, 88, 48, 89, 48, 90, 48, 91, 48, 92, 48, 93, 48, 94, 48, 95, 48, 96, 48, 97, 48, 98, 48, 99, 48,100, 48,101, 48,102, 48,103, 48,104, 48,105, 48,106, 48,107, 48,108, 48,109, 48,110, 48,111, 48,112, 48,113, 48,114, 48,115, 48,116, 48,117, 48,118, 48,119, 48,120, 48,121, 48,122, 48,123, 48,124, 48,125, 48,126, 48,127, 48,128, 48,129, 48,130, 48,131, 48,132, 48,133, 48,134, 48,135, 48,136, 48,137, 48,138, 48,139, 48,140, 48,141, 48,142, 48,143, 48,144, 48,145, 48,146, 48,147, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 48,161, 48,162, 48,163, 48,164, 48,165, 48,166, 48,167, 48,168, 48,169, 48,170, 48,171, 48,172, 48,173, 48,174, 48,175, 48,176, 48,177, 48,178, 48,179, 48,180, 48,181, 48,182, 48,183, 48,184, 48,185, 48,186, 48,187, 48,188, 48,189, 48,190, 48,191, 48,192, 48,193, 48,194, 48,195, 48,196, 48,197, 48,198, 48,199, 48,200, 48,201, 48,202, 48,203, 48,204, 48,205, 48,206, 48,207, 48,208, 48,209, 48,210, 48,211, 48,212, 48,213, 48,214, 48,215, 48,216, 48,217, 48,218, 48,219, 48,220, 48,221, 48,222, 48,223, 0, 32, 48,224, 48,225, 48,226, 48,227, 48,228, 48,229, 48,230, 48,231, 48,232, 48,233, 48,234, 48,235, 48,236, 48,237, 48,238, 48,239, 48,240, 48,241, 48,242, 48,243, 48,244, 48,245, 48,246, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 3,145, 3,146, 3,147, 3,148, 3,149, 3,150, 3,151, 3,152, 3,153, 3,154, 3,155, 3,156, 3,157, 3,158, 3,159, 3,160, 3,161, 3,163, 3,164, 3,165, 3,166, 3,167, 3,168, 3,169, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 3,177, 3,178, 3,179, 3,180, 3,181, 3,182, 3,183, 3,184, 3,185, 3,186, 3,187, 3,188, 3,189, 3,190, 3,191, 3,192, 3,193, 3,195, 3,196, 3,197, 3,198, 3,199, 3,200, 3,201, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 4, 16, 4, 17, 4, 18, 4, 19, 4, 20, 4, 21, 4, 1, 4, 22, 4, 23, 4, 24, 4, 25, 4, 26, 4, 27, 4, 28, 4, 29, 4, 30, 4, 31, 4, 32, 4, 33, 4, 34, 4, 35, 4, 36, 4, 37, 4, 38, 4, 39, 4, 40, 4, 41, 4, 42, 4, 43, 4, 44, 4, 45, 4, 46, 4, 47, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 4, 48, 4, 49, 4, 50, 4, 51, 4, 52, 4, 53, 4, 81, 4, 54, 4, 55, 4, 56, 4, 57, 4, 58, 4, 59, 4, 60, 4, 61, 0, 32, 4, 62, 4, 63, 4, 64, 4, 65, 4, 66, 4, 67, 4, 68, 4, 69, 4, 70, 4, 71, 4, 72, 4, 73, 4, 74, 4, 75, 4, 76, 4, 77, 4, 78, 4, 79, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 37, 0, 37, 2, 37, 12, 37, 16, 37, 24, 37, 20, 37, 28, 37, 44, 37, 36, 37, 52, 37, 60, 37, 1, 37, 3, 37, 15, 37, 19, 37, 27, 37, 23, 37, 35, 37, 51, 37, 43, 37, 59, 37, 75, 37, 32, 37, 47, 37, 40, 37, 55, 37, 63, 37, 29, 37, 48, 37, 37, 37, 56, 37, 66, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 78,156, 85, 22, 90, 3,150, 63, 84,192, 97, 27, 99, 40, 89,246,144, 34, 132,117,131, 28,122, 80, 96,170, 99,225,110, 37,101,237,132,102,130,166,155,245,104,147, 87, 39, 101,161, 98,113, 91,155, 89,208,134,123,152,244,125, 98,125,190,155,142, 98, 22,124,159,136,183, 91,137, 94,181, 99, 9,102,151,104, 72,149,199,151,141,103, 79, 78,229, 79, 10, 79, 77, 79,157, 80, 73, 86,242, 89, 55, 89,212, 90, 1, 92, 9, 96,223, 97, 15, 97,112,102, 19,105, 5,112,186, 117, 79,117,112,121,251,125,173,125,239,128,195,132, 14,136, 99,139, 2,144, 85,144,122, 83, 59, 78,149, 78,165, 87,223,128,178,144,193,120,239, 78, 0, 88,241,110,162,144, 56,122, 50,131, 40, 130,139,156, 47, 81, 65, 83,112, 84,189, 84,225, 86,224, 89,251, 95, 21,152,242,109,235,128,228, 133, 45, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,150, 98,150,112,150,160,151,251, 84, 11, 83,243, 91,135,112,207,127,189,143,194,150,232, 83,111,157, 92,122,186, 78, 17,120,147, 129,252,110, 38, 86, 24, 85, 4,107, 29,133, 26,156, 59, 89,229, 83,169,109,102,116,220,149,143, 86, 66, 78,145,144, 75,150,242,131, 79,153, 12, 83,225, 85,182, 91, 48, 95,113,102, 32,102,243, 104, 4,108, 56,108,243,109, 41,116, 91,118,200,122, 78,152, 52,130,241,136, 91,138, 96,146,237, 109,178,117,171,118,202,153,197, 96,166,139, 1,141,138,149,178,105,142, 83,173, 81,134, 0, 32, 87, 18, 88, 48, 89, 68, 91,180, 94,246, 96, 40, 99,169, 99,244,108,191,111, 20,112,142,113, 20, 113, 89,113,213,115, 63,126, 1,130,118,130,209,133,151,144, 96,146, 91,157, 27, 88,105,101,188, 108, 90,117, 37, 81,249, 89, 46, 89,101, 95,128, 95,220, 98,188,101,250,106, 42,107, 39,107,180, 115,139,127,193,137, 86,157, 44,157, 14,158,196, 92,161,108,150,131,123, 81, 4, 92, 75, 97,182, 129,198,104,118,114, 97, 78, 89, 79,250, 83,120, 96,105,110, 41,122, 79,151,243, 78, 11, 83, 22, 78,238, 79, 85, 79, 61, 79,161, 79,115, 82,160, 83,239, 86, 9, 89, 15, 90,193, 91,182, 91,225, 121,209,102,135,103,156,103,182,107, 76,108,179,112,107,115,194,121,141,121,190,122, 60,123,135, 130,177,130,219,131, 4,131,119,131,239,131,211,135,102,138,178, 86, 41,140,168,143,230,144, 78, 151, 30,134,138, 79,196, 92,232, 98, 17,114, 89,117, 59,129,229,130,189,134,254,140,192,150,197, 153, 19,153,213, 78,203, 79, 26,137,227, 86,222, 88, 74, 88,202, 94,251, 95,235, 96, 42, 96,148, 96, 98, 97,208, 98, 18, 98,208,101, 57, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 155, 65,102,102,104,176,109,119,112,112,117, 76,118,134,125,117,130,165,135,249,149,139,150,142, 140,157, 81,241, 82,190, 89, 22, 84,179, 91,179, 93, 22, 97,104,105,130,109,175,120,141,132,203, 136, 87,138,114,147,167,154,184,109,108,153,168,134,217, 87,163,103,255,134,206,146, 14, 82,131, 86,135, 84, 4, 94,211, 98,225,100,185,104, 60,104, 56,107,187,115,114,120,186,122,107,137,154, 137,210,141,107,143, 3,144,237,149,163,150,148,151,105, 91,102, 92,179,105,125,152, 77,152, 78, 99,155,123, 32,106, 43, 0, 32,106,127,104,182,156, 13,111, 95, 82,114, 85,157, 96,112, 98,236, 109, 59,110, 7,110,209,132, 91,137, 16,143, 68, 78, 20,156, 57, 83,246,105, 27,106, 58,151,132, 104, 42, 81, 92,122,195,132,178,145,220,147,140, 86, 91,157, 40,104, 34,131, 5,132, 49,124,165, 82, 8,130,197,116,230, 78,126, 79,131, 81,160, 91,210, 82, 10, 82,216, 82,231, 93,251, 85,154, 88, 42, 89,230, 91,140, 91,152, 91,219, 94,114, 94,121, 96,163, 97, 31, 97, 99, 97,190, 99,219, 101, 98,103,209,104, 83,104,250,107, 62,107, 83,108, 87,111, 34,111,151,111, 69,116,176,117, 24, 118,227,119, 11,122,255,123,161,124, 33,125,233,127, 54,127,240,128,157,130,102,131,158,137,179, 138,204,140,171,144,132,148, 81,149,147,149,145,149,162,150,101,151,211,153, 40,130, 24, 78, 56, 84, 43, 92,184, 93,204,115,169,118, 76,119, 60, 92,169,127,235,141, 11,150,193,152, 17,152, 84, 152, 88, 79, 1, 79, 14, 83,113, 85,156, 86,104, 87,250, 89, 71, 91, 9, 91,196, 92,144, 94, 12, 94,126, 95,204, 99,238,103, 58,101,215,101,226,103, 31,104,203,104,196, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,106, 95, 94, 48,107,197,108, 23,108,125,117,127,121, 72, 91, 99, 122, 0,125, 0, 95,189,137,143,138, 24,140,180,141,119,142,204,143, 29,152,226,154, 14,155, 60, 78,128, 80,125, 81, 0, 89,147, 91,156, 98, 47, 98,128,100,236,107, 58,114,160,117,145,121, 71, 127,169,135,251,138,188,139,112, 99,172,131,202,151,160, 84, 9, 84, 3, 85,171,104, 84,106, 88, 138,112,120, 39,103,117,158,205, 83,116, 91,162,129, 26,134, 80,144, 6, 78, 24, 78, 69, 78,199, 79, 17, 83,202, 84, 56, 91,174, 95, 19, 96, 37,101, 81, 0, 32,103, 61,108, 66,108,114,108,227, 112,120,116, 3,122,118,122,174,123, 8,125, 26,124,254,125,102,101,231,114, 91, 83,187, 92, 69, 93,232, 98,210, 98,224, 99, 25,110, 32,134, 90,138, 49,141,221,146,248,111, 1,121,166,155, 90, 78,168, 78,171, 78,172, 79,155, 79,160, 80,209, 81, 71,122,246, 81,113, 81,246, 83, 84, 83, 33, 83,127, 83,235, 85,172, 88,131, 92,225, 95, 55, 95, 74, 96, 47, 96, 80, 96,109, 99, 31,101, 89, 106, 75,108,193,114,194,114,237,119,239,128,248,129, 5,130, 8,133, 78,144,247,147,225,151,255, 153, 87,154, 90, 78,240, 81,221, 92, 45,102,129,105,109, 92, 64,102,242,105,117,115,137,104, 80, 124,129, 80,197, 82,228, 87, 71, 93,254,147, 38,101,164,107, 35,107, 61,116, 52,121,129,121,189, 123, 75,125,202,130,185,131,204,136,127,137, 95,139, 57,143,209,145,209, 84, 31,146,128, 78, 93, 80, 54, 83,229, 83, 58,114,215,115,150,119,233,130,230,142,175,153,198,153,200,153,210, 81,119, 97, 26,134, 94, 85,176,122,122, 80,118, 91,211,144, 71,150,133, 78, 50,106,219,145,231, 92, 81, 92, 72, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 99,152,122,159,108,147,151,116, 143, 97,122,170,113,138,150,136,124,130,104, 23,126,112,104, 81,147,108, 82,242, 84, 27,133,171, 138, 19,127,164,142,205,144,225, 83,102,136,136,121, 65, 79,194, 80,190, 82, 17, 81, 68, 85, 83, 87, 45,115,234, 87,139, 89, 81, 95, 98, 95,132, 96,117, 97,118, 97,103, 97,169, 99,178,100, 58, 101,108,102,111,104, 66,110, 19,117,102,122, 61,124,251,125, 76,125,153,126, 75,127,107,131, 14, 131, 74,134,205,138, 8,138, 99,139,102,142,253,152, 26,157,143,130,184,143,206,155,232, 0, 32, 82,135, 98, 31,100,131,111,192,150,153,104, 65, 80,145,107, 32,108,122,111, 84,122,116,125, 80, 136, 64,138, 35,103, 8, 78,246, 80, 57, 80, 38, 80,101, 81,124, 82, 56, 82, 99, 85,167, 87, 15, 88, 5, 90,204, 94,250, 97,178, 97,248, 98,243, 99,114,105, 28,106, 41,114,125,114,172,115, 46, 120, 20,120,111,125,121,119, 12,128,169,137,139,139, 25,140,226,142,210,144, 99,147,117,150,122, 152, 85,154, 19,158,120, 81, 67, 83,159, 83,179, 94,123, 95, 38,110, 27,110,144,115,132,115,254, 125, 67,130, 55,138, 0,138,250,150, 80, 78, 78, 80, 11, 83,228, 84,124, 86,250, 89,209, 91,100, 93,241, 94,171, 95, 39, 98, 56,101, 69,103,175,110, 86,114,208,124,202,136,180,128,161,128,225, 131,240,134, 78,138,135,141,232,146, 55,150,199,152,103,159, 19, 78,148, 78,146, 79, 13, 83, 72, 84, 73, 84, 62, 90, 47, 95,140, 95,161, 96,159,104,167,106,142,116, 90,120,129,138,158,138,164, 139,119,145,144, 78, 94,155,201, 78,164, 79,124, 79,175, 80, 25, 80, 22, 81, 73, 81,108, 82,159, 82,185, 82,254, 83,154, 83,227, 84, 17, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 84, 14, 85,137, 87, 81, 87,162, 89,125, 91, 84, 91, 93, 91,143, 93,229, 93,231, 93,247, 94,120, 94,131, 94,154, 94,183, 95, 24, 96, 82, 97, 76, 98,151, 98,216, 99,167,101, 59,102, 2,102, 67, 102,244,103,109,104, 33,104,151,105,203,108, 95,109, 42,109,105,110, 47,110,157,117, 50,118,135, 120,108,122, 63,124,224,125, 5,125, 24,125, 94,125,177,128, 21,128, 3,128,175,128,177,129, 84, 129,143,130, 42,131, 82,136, 76,136, 97,139, 27,140,162,140,252,144,202,145,117,146,113,120, 63, 146,252,149,164,150, 77, 0, 32,152, 5,153,153,154,216,157, 59, 82, 91, 82,171, 83,247, 84, 8, 88,213, 98,247,111,224,140,106,143, 95,158,185, 81, 75, 82, 59, 84, 74, 86,253,122, 64,145,119, 157, 96,158,210,115, 68,111, 9,129,112,117, 17, 95,253, 96,218,154,168,114,219,143,188,107,100, 152, 3, 78,202, 86,240, 87,100, 88,190, 90, 90, 96,104, 97,199,102, 15,102, 6,104, 57,104,177, 109,247,117,213,125, 58,130,110,155, 66, 78,155, 79, 80, 83,201, 85, 6, 93,111, 93,230, 93,238, 103,251,108,153,116,115,120, 2,138, 80,147,150,136,223, 87, 80, 94,167, 99, 43, 80,181, 80,172, 81,141,103, 0, 84,201, 88, 94, 89,187, 91,176, 95,105, 98, 77, 99,161,104, 61,107,115,110, 8, 112,125,145,199,114,128,120, 21,120, 38,121,109,101,142,125, 48,131,220,136,193,143, 9,150,155, 82,100, 87, 40,103, 80,127,106,140,161, 81,180, 87, 66,150, 42, 88, 58,105,138,128,180, 84,178, 93, 14, 87,252,120,149,157,250, 79, 92, 82, 74, 84,139,100, 62,102, 40,103, 20,103,245,122,132, 123, 86,125, 34,147, 47,104, 92,155,173,123, 57, 83, 25, 81,138, 82, 55, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 91,223, 98,246,100,174,100,230,103, 45,107,186,133,169,150,209, 118,144,155,214, 99, 76,147, 6,155,171,118,191,102, 82, 78, 9, 80,152, 83,194, 92,113, 96,232, 100,146,101, 99,104, 95,113,230,115,202,117, 35,123,151,126,130,134,149,139,131,140,219,145,120, 153, 16,101,172,102,171,107,139, 78,213, 78,212, 79, 58, 79,127, 82, 58, 83,248, 83,242, 85,227, 86,219, 88,235, 89,203, 89,201, 89,255, 91, 80, 92, 77, 94, 2, 94, 43, 95,215, 96, 29, 99, 7, 101, 47, 91, 92,101,175,101,189,101,232,103,157,107, 98, 0, 32,107,123,108, 15,115, 69,121, 73, 121,193,124,248,125, 25,125, 43,128,162,129, 2,129,243,137,150,138, 94,138,105,138,102,138,140, 138,238,140,199,140,220,150,204,152,252,107,111, 78,139, 79, 60, 79,141, 81, 80, 91, 87, 91,250, 97, 72, 99, 1,102, 66,107, 33,110,203,108,187,114, 62,116,189,117,212,120,193,121, 58,128, 12, 128, 51,129,234,132,148,143,158,108, 80,158,127, 95, 15,139, 88,157, 43,122,250,142,248, 91,141, 150,235, 78, 3, 83,241, 87,247, 89, 49, 90,201, 91,164, 96,137,110,127,111, 6,117,190,140,234, 91,159,133, 0,123,224, 80,114,103,244,130,157, 92, 97,133, 74,126, 30,130, 14, 81,153, 92, 4, 99,104,141,102,101,156,113,110,121, 62,125, 23,128, 5,139, 29,142,202,144,110,134,199,144,170, 80, 31, 82,250, 92, 58,103, 83,112,124,114, 53,145, 76,145,200,147, 43,130,229, 91,194, 95, 49, 96,249, 78, 59, 83,214, 91,136, 98, 75,103, 49,107,138,114,233,115,224,122, 46,129,107,141,163, 145, 82,153,150, 81, 18, 83,215, 84,106, 91,255, 99,136,106, 57,125,172,151, 0, 86,218, 83,206, 84,104, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 91,151, 92, 49, 93,222, 79,238, 97, 1, 98,254,109, 50,121,192,121,203,125, 66,126, 77,127,210,129,237,130, 31,132,144,136, 70, 137,114,139,144,142,116,143, 47,144, 49,145, 75,145,108,150,198,145,156, 78,192, 79, 79, 81, 69, 83, 65, 95,147, 98, 14,103,212,108, 65,110, 11,115, 99,126, 38,145,205,146,131, 83,212, 89, 25, 91,191,109,209,121, 93,126, 46,124,155, 88,126,113,159, 81,250,136, 83,143,240, 79,202, 92,251, 102, 37,119,172,122,227,130, 28,153,255, 81,198, 95,170,101,236,105,111,107,137,109,243, 0, 32, 110,150,111,100,118,254,125, 20, 93,225,144,117,145,135,152, 6, 81,230, 82, 29, 98, 64,102,145, 102,217,110, 26, 94,182,125,210,127,114,102,248,133,175,133,247,138,248, 82,169, 83,217, 89,115, 94,143, 95,144, 96, 85,146,228,150,100, 80,183, 81, 31, 82,221, 83, 32, 83, 71, 83,236, 84,232, 85, 70, 85, 49, 86, 23, 89,104, 89,190, 90, 60, 91,181, 92, 6, 92, 15, 92, 17, 92, 26, 94,132, 94,138, 94,224, 95,112, 98,127, 98,132, 98,219, 99,140, 99,119,102, 7,102, 12,102, 45,102,118, 103,126,104,162,106, 31,106, 53,108,188,109,136,110, 9,110, 88,113, 60,113, 38,113,103,117,199, 119, 1,120, 93,121, 1,121,101,121,240,122,224,123, 17,124,167,125, 57,128,150,131,214,132,139, 133, 73,136, 93,136,243,138, 31,138, 60,138, 84,138,115,140, 97,140,222,145,164,146,102,147,126, 148, 24,150,156,151,152, 78, 10, 78, 8, 78, 30, 78, 87, 81,151, 82,112, 87,206, 88, 52, 88,204, 91, 34, 94, 56, 96,197,100,254,103, 97,103, 86,109, 68,114,182,117,115,122, 99,132,184,139,114, 145,184,147, 32, 86, 49, 87,244,152,254, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 98,237,105, 13,107,150,113,237,126, 84,128,119,130,114,137,230,152,223,135, 85,143,177, 92, 59, 79, 56, 79,225, 79,181, 85, 7, 90, 32, 91,221, 91,233, 95,195, 97, 78, 99, 47,101,176,102, 75, 104,238,105,155,109,120,109,241,117, 51,117,185,119, 31,121, 94,121,230,125, 51,129,227,130,175, 133,170,137,170,138, 58,142,171,143,155,144, 50,145,221,151, 7, 78,186, 78,193, 82, 3, 88,117, 88,236, 92, 11,117, 26, 92, 61,129, 78,138, 10,143,197,150, 99,151,109,123, 37,138,207,152, 8, 145, 98, 86,243, 83,168, 0, 32,144, 23, 84, 57, 87,130, 94, 37, 99,168,108, 52,112,138,119, 97, 124,139,127,224,136,112,144, 66,145, 84,147, 16,147, 24,150,143,116, 94,154,196, 93, 7, 93,105, 101,112,103,162,141,168,150,219, 99,110,103, 73,105, 25,131,197,152, 23,150,192,136,254,111,132, 100,122, 91,248, 78, 22,112, 44,117, 93,102, 47, 81,196, 82, 54, 82,226, 89,211, 95,129, 96, 39, 98, 16,101, 63,101,116,102, 31,102,116,104,242,104, 22,107, 99,110, 5,114,114,117, 31,118,219, 124,190,128, 86, 88,240,136,253,137,127,138,160,138,147,138,203,144, 29,145,146,151, 82,151, 89, 101,137,122, 14,129, 6,150,187, 94, 45, 96,220, 98, 26,101,165,102, 20,103,144,119,243,122, 77, 124, 77,126, 62,129, 10,140,172,141,100,141,225,142, 95,120,169, 82, 7, 98,217, 99,165,100, 66, 98,152,138, 45,122,131,123,192,138,172,150,234,125,118,130, 12,135, 73, 78,217, 81, 72, 83, 67, 83, 96, 91,163, 92, 2, 92, 22, 93,221, 98, 38, 98, 71,100,176,104, 19,104, 52,108,201,109, 69, 109, 23,103,211,111, 92,113, 78,113,125,101,203,122,127,123,173,125,218, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,126, 74,127,168,129,122,130, 27,130, 57,133,166,138,110,140,206, 141,245,144,120,144,119,146,173,146,145,149,131,155,174, 82, 77, 85,132,111, 56,113, 54, 81,104, 121,133,126, 85,129,179,124,206, 86, 76, 88, 81, 92,168, 99,170,102,254,102,253,105, 90,114,217, 117,143,117,142,121, 14,121, 86,121,223,124,151,125, 32,125, 68,134, 7,138, 52,150, 59,144, 97, 159, 32, 80,231, 82,117, 83,204, 83,226, 80, 9, 85,170, 88,238, 89, 79,114, 61, 91,139, 92,100, 83, 29, 96,227, 96,243, 99, 92, 99,131, 99, 63, 99,187, 0, 32,100,205,101,233,102,249, 93,227, 105,205,105,253,111, 21,113,229, 78,137,117,233,118,248,122,147,124,223,125,207,125,156,128, 97, 131, 73,131, 88,132,108,132,188,133,251,136,197,141,112,144, 1,144,109,147,151,151, 28,154, 18, 80,207, 88,151, 97,142,129,211,133, 53,141, 8,144, 32, 79,195, 80,116, 82, 71, 83,115, 96,111, 99, 73,103, 95,110, 44,141,179,144, 31, 79,215, 92, 94,140,202,101,207,125,154, 83, 82,136,150, 81,118, 99,195, 91, 88, 91,107, 92, 10,100, 13,103, 81,144, 92, 78,214, 89, 26, 89, 42,108,112, 138, 81, 85, 62, 88, 21, 89,165, 96,240, 98, 83,103,193,130, 53,105, 85,150, 64,153,196,154, 40, 79, 83, 88, 6, 91,254,128, 16, 92,177, 94, 47, 95,133, 96, 32, 97, 75, 98, 52,102,255,108,240, 110,222,128,206,129,127,130,212,136,139,140,184,144, 0,144, 46,150,138,158,219,155,219, 78,227, 83,240, 89, 39,123, 44,145,141,152, 76,157,249,110,221,112, 39, 83, 83, 85, 68, 91,133, 98, 88, 98,158, 98,211,108,162,111,239,116, 34,138, 23,148, 56,111,193,138,254,131, 56, 81,231,134,248, 83,234, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 83,233, 79, 70,144, 84,143,176, 89,106,129, 49, 93,253,122,234,143,191,104,218,140, 55,114,248,156, 72,106, 61,138,176, 78, 57, 83, 88, 86, 6, 87,102, 98,197, 99,162,101,230,107, 78,109,225,110, 91,112,173,119,237,122,239, 123,170,125,187,128, 61,128,198,134,203,138,149,147, 91, 86,227, 88,199, 95, 62,101,173,102,150, 106,128,107,181,117, 55,138,199, 80, 36,119,229, 87, 48, 95, 27, 96,101,102,122,108, 96,117,244, 122, 26,127,110,129,244,135, 24,144, 69,153,179,123,201,117, 92,122,249,123, 81,132,196, 0, 32, 144, 16,121,233,122,146,131, 54, 90,225,119, 64, 78, 45, 78,242, 91,153, 95,224, 98,189,102, 60, 103,241,108,232,134,107,136,119,138, 59,145, 78,146,243,153,208,106, 23,112, 38,115, 42,130,231, 132, 87,140,175, 78, 1, 81, 70, 81,203, 85,139, 91,245, 94, 22, 94, 51, 94,129, 95, 20, 95, 53, 95,107, 95,180, 97,242, 99, 17,102,162,103, 29,111,110,114, 82,117, 58,119, 58,128,116,129, 57, 129,120,135,118,138,191,138,220,141,133,141,243,146,154,149,119,152, 2,156,229, 82,197, 99, 87, 118,244,103, 21,108,136,115,205,140,195,147,174,150,115,109, 37, 88,156,105, 14,105,204,143,253, 147,154,117,219,144, 26, 88, 90,104, 2, 99,180,105,251, 79, 67,111, 44,103,216,143,187,133, 38, 125,180,147, 84,105, 63,111,112, 87,106, 88,247, 91, 44,125, 44,114, 42, 84, 10,145,227,157,180, 78,173, 79, 78, 80, 92, 80,117, 82, 67,140,158, 84, 72, 88, 36, 91,154, 94, 29, 94,149, 94,173, 94,247, 95, 31, 96,140, 98,181, 99, 58, 99,208,104,175,108, 64,120,135,121,142,122, 11,125,224, 130, 71,138, 2,138,230,142, 68,144, 19, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 144,184,145, 45,145,216,159, 14,108,229,100, 88,100,226,101,117,110,244,118,132,123, 27,144,105, 147,209,110,186, 84,242, 95,185,100,164,143, 77,143,237,146, 68, 81,120, 88,107, 89, 41, 92, 85, 94,151,109,251,126,143,117, 28,140,188,142,226,152, 91,112,185, 79, 29,107,191,111,177,117, 48, 150,251, 81, 78, 84, 16, 88, 53, 88, 87, 89,172, 92, 96, 95,146,101,151,103, 92,110, 33,118,123, 131,223,140,237,144, 20,144,253,147, 77,120, 37,120, 58, 82,170, 94,166, 87, 31, 89,116, 96, 18, 80, 18, 81, 90, 81,172, 0, 32, 81,205, 82, 0, 85, 16, 88, 84, 88, 88, 89, 87, 91,149, 92,246, 93,139, 96,188, 98,149,100, 45,103,113,104, 67,104,188,104,223,118,215,109,216,110,111,109,155, 112,111,113,200, 95, 83,117,216,121,119,123, 73,123, 84,123, 82,124,214,125,113, 82, 48,132, 99, 133,105,133,228,138, 14,139, 4,140, 70,142, 15,144, 3,144, 15,148, 25,150,118,152, 45,154, 48, 149,216, 80,205, 82,213, 84, 12, 88, 2, 92, 14, 97,167,100,158,109, 30,119,179,122,229,128,244, 132, 4,144, 83,146,133, 92,224,157, 7, 83, 63, 95,151, 95,179,109,156,114,121,119, 99,121,191, 123,228,107,210,114,236,138,173,104, 3,106, 97, 81,248,122,129,105, 52, 92, 74,156,246,130,235, 91,197,145, 73,112, 30, 86,120, 92,111, 96,199,101,102,108,140,140, 90,144, 65,152, 19, 84, 81, 102,199,146, 13, 89, 72,144,163, 81,133, 78, 77, 81,234,133,153,139, 14,112, 88, 99,122,147, 75, 105, 98,153,180,126, 4,117,119, 83, 87,105, 96,142,223,150,227,108, 93, 78,140, 92, 60, 95, 16, 143,233, 83, 2,140,209,128,137,134,121, 94,255,101,229, 78,115, 81,101, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 89,130, 92, 63,151,238, 78,251, 89,138, 95,205,138,141,111,225, 121,176,121, 98, 91,231,132,113,115, 43,113,177, 94,116, 95,245, 99,123,100,154,113,195,124,152, 78, 67, 94,252, 78, 75, 87,220, 86,162, 96,169,111,195,125, 13,128,253,129, 51,129,191,143,178, 137,151,134,164, 93,244, 98,138,100,173,137,135,103,119,108,226,109, 62,116, 54,120, 52, 90, 70, 127,117,130,173,153,172, 79,243, 94,195, 98,221, 99,146,101, 87,103,111,118,195,114, 76,128,204, 128,186,143, 41,145, 77, 80, 13, 87,249, 90,146,104,133, 0, 32,105,115,113,100,114,253,140,183, 88,242,140,224,150,106,144, 25,135,127,121,228,119,231,132, 41, 79, 47, 82,101, 83, 90, 98,205, 103,207,108,202,118,125,123,148,124,149,130, 54,133,132,143,235,102,221,111, 32,114, 6,126, 27, 131,171,153,193,158,166, 81,253,123,177,120,114,123,184,128,135,123, 72,106,232, 94, 97,128,140, 117, 81,117, 96, 81,107,146, 98,110,140,118,122,145,151,154,234, 79, 16,127,112, 98,156,123, 79, 149,165,156,233, 86,122, 88, 89,134,228,150,188, 79, 52, 82, 36, 83, 74, 83,205, 83,219, 94, 6, 100, 44,101,145,103,127,108, 62,108, 78,114, 72,114,175,115,237,117, 84,126, 65,130, 44,133,233, 140,169,123,196,145,198,113,105,152, 18,152,239, 99, 61,102,105,117,106,118,228,120,208,133, 67, 134,238, 83, 42, 83, 81, 84, 38, 89,131, 94,135, 95,124, 96,178, 98, 73, 98,121, 98,171,101,144, 107,212,108,204,117,178,118,174,120,145,121,216,125,203,127,119,128,165,136,171,138,185,140,187, 144,127,151, 94,152,219,106, 11,124, 56, 80,153, 92, 62, 95,174,103,135,107,216,116, 53,119, 9, 127,142, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,159, 59,103,202,122, 23, 83, 57, 117,139,154,237, 95,102,129,157,131,241,128,152, 95, 60, 95,197,117, 98,123, 70,144, 60,104,103, 89,235, 90,155,125, 16,118,126,139, 44, 79,245, 95,106,106, 25,108, 55,111, 2,116,226,121,104, 136,104,138, 85,140,121, 94,223, 99,207,117,197,121,210,130,215,147, 40,146,242,132,156,134,237, 156, 45, 84,193, 95,108,101,140,109, 92,112, 21,140,167,140,211,152, 59,101, 79,116,246, 78, 13, 78,216, 87,224, 89, 43, 90,102, 91,204, 81,168, 94, 3, 94,156, 96, 22, 98,118,101,119, 0, 32, 101,167,102,110,109,110,114, 54,123, 38,129, 80,129,154,130,153,139, 92,140,160,140,230,141,116, 150, 28,150, 68, 79,174,100,171,107,102,130, 30,132, 97,133,106,144,232, 92, 1,105, 83,152,168, 132,122,133, 87, 79, 15, 82,111, 95,169, 94, 69,103, 13,121,143,129,121,137, 7,137,134,109,245, 95, 23, 98, 85,108,184, 78,207,114,105,155,146, 82, 6, 84, 59, 86,116, 88,179, 97,164, 98,110, 113, 26, 89,110,124,137,124,222,125, 27,150,240,101,135,128, 94, 78, 25, 79,117, 81,117, 88, 64, 94, 99, 94,115, 95, 10,103,196, 78, 38,133, 61,149,137,150, 91,124,115,152, 1, 80,251, 88,193, 118, 86,120,167, 82, 37,119,165,133, 17,123,134, 80, 79, 89, 9,114, 71,123,199,125,232,143,186, 143,212,144, 77, 79,191, 82,201, 90, 41, 95, 1,151,173, 79,221,130, 23,146,234, 87, 3, 99, 85, 107,105,117, 43,136,220,143, 20,122, 66, 82,223, 88,147, 97, 85, 98, 10,102,174,107,205,124, 63, 131,233, 80, 35, 79,248, 83, 5, 84, 70, 88, 49, 89, 73, 91,157, 92,240, 92,239, 93, 41, 94,150, 98,177, 99,103,101, 62,101,185,103, 11, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 108,213,108,225,112,249,120, 50,126, 43,128,222,130,179,132, 12,132,236,135, 2,137, 18,138, 42, 140, 74,144,166,146,210,152,253,156,243,157,108, 78, 79, 78,161, 80,141, 82, 86, 87, 74, 89,168, 94, 61, 95,216, 95,217, 98, 63,102,180,103, 27,103,208,104,210, 81,146,125, 33,128,170,129,168, 139, 0,140,140,140,191,146,126,150, 50, 84, 32,152, 44, 83, 23, 80,213, 83, 92, 88,168,100,178, 103, 52,114,103,119,102,122, 70,145,230, 82,195,108,161,107,134, 88, 0, 94, 76, 89, 84,103, 44, 127,251, 81,225,118,198, 0, 32,100,105,120,232,155, 84,158,187, 87,203, 89,185,102, 39,103,154, 107,206, 84,233,105,217, 94, 85,129,156,103,149,155,170,103,254,156, 82,104, 93, 78,166, 79,227, 83,200, 98,185,103, 43,108,171,143,196, 79,173,126,109,158,191, 78, 7, 97, 98,110,128,111, 43, 133, 19, 84,115,103, 42,155, 69, 93,243,123,149, 92,172, 91,198,135, 28,110, 74,132,209,122, 20, 129, 8, 89,153,124,141,108, 17,119, 32, 82,217, 89, 34,113, 33,114, 95,119,219,151, 39,157, 97, 105, 11, 90,127, 90, 24, 81,165, 84, 13, 84,125,102, 14,118,223,143,247,146,152,156,244, 89,234, 114, 93,110,197, 81, 77,104,201,125,191,125,236,151, 98,158,186,100,120,106, 33,131, 2, 89,132, 91, 95,107,219,115, 27,118,242,125,178,128, 23,132,153, 81, 50,103, 40,158,217,118,238,103, 98, 82,255,153, 5, 92, 36, 98, 59,124,126,140,176, 85, 79, 96,182,125, 11,149,128, 83, 1, 78, 95, 81,182, 89, 28,114, 58,128, 54,145,206, 95, 37,119,226, 83,132, 95,121,125, 4,133,172,138, 51, 142,141,151, 86,103,243,133,174,148, 83, 97, 9, 97, 8,108,185,118, 82, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,138,237,143, 56, 85, 47, 79, 81, 81, 42, 82,199, 83,203, 91,165, 94,125, 96,160, 97,130, 99,214,103, 9,103,218,110,103,109,140,115, 54,115, 55,117, 49,121, 80, 136,213,138,152,144, 74,144,145,144,245,150,196,135,141, 89, 21, 78,136, 79, 89, 78, 14,138,137, 143, 63,152, 16, 80,173, 94,124, 89,150, 91,185, 94,184, 99,218, 99,250,100,193,102,220,105, 74, 105,216,109, 11,110,182,113,148,117, 40,122,175,127,138,128, 0,132, 73,132,201,137,129,139, 33, 142, 10,144,101,150,125,153, 10, 97,126, 98,145,107, 50, 0, 32,108,131,109,116,127,204,127,252, 109,192,127,133,135,186,136,248,103,101,131,177,152, 60,150,247,109, 27,125, 97,132, 61,145,106, 78,113, 83,117, 93, 80,107, 4,111,235,133,205,134, 45,137,167, 82, 41, 84, 15, 92,101,103, 78, 104,168,116, 6,116,131,117,226,136,207,136,225,145,204,150,226,150,120, 95,139,115,135,122,203, 132, 78, 99,160,117,101, 82,137,109, 65,110,156,116, 9,117, 89,120,107,124,146,150,134,122,220, 159,141, 79,182, 97,110,101,197,134, 92, 78,134, 78,174, 80,218, 78, 33, 81,204, 91,238,101,153, 104,129,109,188,115, 31,118, 66,119,173,122, 28,124,231,130,111,138,210,144,124,145,207,150,117, 152, 24, 82,155,125,209, 80, 43, 83,152,103,151,109,203,113,208,116, 51,129,232,143, 42,150,163, 156, 87,158,159,116, 96, 88, 65,109,153,125, 47,152, 94, 78,228, 79, 54, 79,139, 81,183, 82,177, 93,186, 96, 28,115,178,121, 60,130,211,146, 52,150,183,150,246,151, 10,158,151,159, 98,102,166, 107,116, 82, 23, 82,163,112,200,136,194, 94,201, 96, 75, 97,144,111, 35,113, 73,124, 62,125,244, 128,111, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,132,238,144, 35,147, 44, 84, 66, 155,111,106,211,112,137,140,194,141,239,151, 50, 82,180, 90, 65, 94,202, 95, 4,103, 23,105,124, 105,148,109,106,111, 15,114, 98,114,252,123,237,128, 1,128,126,135, 75,144,206, 81,109,158,147, 121,132,128,139,147, 50,138,214, 80, 45, 84,140,138,113,107,106,140,196,129, 7, 96,209,103,160, 157,242, 78,153, 78,152,156, 16,138,107,133,193,133,104,105, 0,110,126,120,151,129, 85, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 95, 12, 78, 16, 78, 21, 78, 42, 78, 49, 78, 54, 78, 60, 78, 63, 78, 66, 78, 86, 78, 88, 78,130, 78,133,140,107, 78,138,130, 18, 95, 13, 78,142, 78,158, 78,159, 78,160, 78,162, 78,176, 78,179, 78,182, 78,206, 78,205, 78,196, 78,198, 78,194, 78,215, 78,222, 78,237, 78,223, 78,247, 79, 9, 79, 90, 79, 48, 79, 91, 79, 93, 79, 87, 79, 71, 79,118, 79,136, 79,143, 79,152, 79,123, 79,105, 79,112, 79,145, 79,111, 79,134, 79,150, 81, 24, 79,212, 79,223, 79,206, 79,216, 79,219, 79,209, 79,218, 79,208, 79,228, 79,229, 80, 26, 80, 40, 80, 20, 80, 42, 80, 37, 80, 5, 79, 28, 79,246, 80, 33, 80, 41, 80, 44, 79,254, 79,239, 80, 17, 80, 6, 80, 67, 80, 71,103, 3, 80, 85, 80, 80, 80, 72, 80, 90, 80, 86, 80,108, 80,120, 80,128, 80,154, 80,133, 80,180, 80,178, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 80,201, 80,202, 80,179, 80,194, 80,214, 80,222, 80,229, 80,237, 80,227, 80,238, 80,249, 80,245, 81, 9, 81, 1, 81, 2, 81, 22, 81, 21, 81, 20, 81, 26, 81, 33, 81, 58, 81, 55, 81, 60, 81, 59, 81, 63, 81, 64, 81, 82, 81, 76, 81, 84, 81, 98,122,248, 81,105, 81,106, 81,110, 81,128, 81,130, 86,216, 81,140, 81,137, 81,143, 81,145, 81,147, 81,149, 81,150, 81,164, 81,166, 81,162, 81,169, 81,170, 81,171, 81,179, 81,177, 81,178, 81,176, 81,181, 81,189, 81,197, 81,201, 81,219, 81,224, 134, 85, 81,233, 81,237, 0, 32, 81,240, 81,245, 81,254, 82, 4, 82, 11, 82, 20, 82, 14, 82, 39, 82, 42, 82, 46, 82, 51, 82, 57, 82, 79, 82, 68, 82, 75, 82, 76, 82, 94, 82, 84, 82,106, 82,116, 82,105, 82,115, 82,127, 82,125, 82,141, 82,148, 82,146, 82,113, 82,136, 82,145,143,168,143,167, 82,172, 82,173, 82,188, 82,181, 82,193, 82,205, 82,215, 82,222, 82,227, 82,230,152,237, 82,224, 82,243, 82,245, 82,248, 82,249, 83, 6, 83, 8,117, 56, 83, 13, 83, 16, 83, 15, 83, 21, 83, 26, 83, 35, 83, 47, 83, 49, 83, 51, 83, 56, 83, 64, 83, 70, 83, 69, 78, 23, 83, 73, 83, 77, 81,214, 83, 94, 83,105, 83,110, 89, 24, 83,123, 83,119, 83,130, 83,150, 83,160, 83,166, 83,165, 83,174, 83,176, 83,182, 83,195,124, 18,150,217, 83,223,102,252,113,238, 83,238, 83,232, 83,237, 83,250, 84, 1, 84, 61, 84, 64, 84, 44, 84, 45, 84, 60, 84, 46, 84, 54, 84, 41, 84, 29, 84, 78, 84,143, 84,117, 84,142, 84, 95, 84,113, 84,119, 84,112, 84,146, 84,123, 84,128, 84,118, 84,132, 84,144, 84,134, 84,199, 84,162, 84,184, 84,165, 84,172, 84,196, 84,200, 84,168, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 84,171, 84,194, 84,164, 84,190, 84,188, 84,216, 84,229, 84,230, 85, 15, 85, 20, 84,253, 84,238, 84,237, 84,250, 84,226, 85, 57, 85, 64, 85, 99, 85, 76, 85, 46, 85, 92, 85, 69, 85, 86, 85, 87, 85, 56, 85, 51, 85, 93, 85,153, 85,128, 84,175, 85,138, 85,159, 85,123, 85,126, 85,152, 85,158, 85,174, 85,124, 85,131, 85,169, 85,135, 85,168, 85,218, 85,197, 85,223, 85,196, 85,220, 85,228, 85,212, 86, 20, 85,247, 86, 22, 85,254, 85,253, 86, 27, 85,249, 86, 78, 86, 80,113,223, 86, 52, 86, 54, 86, 50, 86, 56, 0, 32, 86,107, 86,100, 86, 47, 86,108, 86,106, 86,134, 86,128, 86,138, 86,160, 86,148, 86,143, 86,165, 86,174, 86,182, 86,180, 86,194, 86,188, 86,193, 86,195, 86,192, 86,200, 86,206, 86,209, 86,211, 86,215, 86,238, 86,249, 87, 0, 86,255, 87, 4, 87, 9, 87, 8, 87, 11, 87, 13, 87, 19, 87, 24, 87, 22, 85,199, 87, 28, 87, 38, 87, 55, 87, 56, 87, 78, 87, 59, 87, 64, 87, 79, 87,105, 87,192, 87,136, 87, 97, 87,127, 87,137, 87,147, 87,160, 87,179, 87,164, 87,170, 87,176, 87,195, 87,198, 87,212, 87,210, 87,211, 88, 10, 87,214, 87,227, 88, 11, 88, 25, 88, 29, 88,114, 88, 33, 88, 98, 88, 75, 88,112,107,192, 88, 82, 88, 61, 88,121, 88,133, 88,185, 88,159, 88,171, 88,186, 88,222, 88,187, 88,184, 88,174, 88,197, 88,211, 88,209, 88,215, 88,217, 88,216, 88,229, 88,220, 88,228, 88,223, 88,239, 88,250, 88,249, 88,251, 88,252, 88,253, 89, 2, 89, 10, 89, 16, 89, 27,104,166, 89, 37, 89, 44, 89, 45, 89, 50, 89, 56, 89, 62,122,210, 89, 85, 89, 80, 89, 78, 89, 90, 89, 88, 89, 98, 89, 96, 89,103, 89,108, 89,105, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 89,120, 89,129, 89,157, 79, 94, 79,171, 89,163, 89,178, 89,198, 89,232, 89,220, 89,141, 89,217, 89,218, 90, 37, 90, 31, 90, 17, 90, 28, 90, 9, 90, 26, 90, 64, 90,108, 90, 73, 90, 53, 90, 54, 90, 98, 90,106, 90,154, 90,188, 90,190, 90,203, 90,194, 90,189, 90,227, 90,215, 90,230, 90,233, 90,214, 90,250, 90,251, 91, 12, 91, 11, 91, 22, 91, 50, 90,208, 91, 42, 91, 54, 91, 62, 91, 67, 91, 69, 91, 64, 91, 81, 91, 85, 91, 90, 91, 91, 91,101, 91,105, 91,112, 91,115, 91,117, 91,120,101,136, 91,122, 91,128, 0, 32, 91,131, 91,166, 91,184, 91,195, 91,199, 91,201, 91,212, 91,208, 91,228, 91,230, 91,226, 91,222, 91,229, 91,235, 91,240, 91,246, 91,243, 92, 5, 92, 7, 92, 8, 92, 13, 92, 19, 92, 32, 92, 34, 92, 40, 92, 56, 92, 57, 92, 65, 92, 70, 92, 78, 92, 83, 92, 80, 92, 79, 91,113, 92,108, 92,110, 78, 98, 92,118, 92,121, 92,140, 92,145, 92,148, 89,155, 92,171, 92,187, 92,182, 92,188, 92,183, 92,197, 92,190, 92,199, 92,217, 92,233, 92,253, 92,250, 92,237, 93,140, 92,234, 93, 11, 93, 21, 93, 23, 93, 92, 93, 31, 93, 27, 93, 17, 93, 20, 93, 34, 93, 26, 93, 25, 93, 24, 93, 76, 93, 82, 93, 78, 93, 75, 93,108, 93,115, 93,118, 93,135, 93,132, 93,130, 93,162, 93,157, 93,172, 93,174, 93,189, 93,144, 93,183, 93,188, 93,201, 93,205, 93,211, 93,210, 93,214, 93,219, 93,235, 93,242, 93,245, 94, 11, 94, 26, 94, 25, 94, 17, 94, 27, 94, 54, 94, 55, 94, 68, 94, 67, 94, 64, 94, 78, 94, 87, 94, 84, 94, 95, 94, 98, 94,100, 94, 71, 94,117, 94,118, 94,122,158,188, 94,127, 94,160, 94,193, 94,194, 94,200, 94,208, 94,207, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 94,214, 94,227, 94,221, 94,218, 94,219, 94,226, 94,225, 94,232, 94,233, 94,236, 94,241, 94,243, 94,240, 94,244, 94,248, 94,254, 95, 3, 95, 9, 95, 93, 95, 92, 95, 11, 95, 17, 95, 22, 95, 41, 95, 45, 95, 56, 95, 65, 95, 72, 95, 76, 95, 78, 95, 47, 95, 81, 95, 86, 95, 87, 95, 89, 95, 97, 95,109, 95,115, 95,119, 95,131, 95,130, 95,127, 95,138, 95,136, 95,145, 95,135, 95,158, 95,153, 95,152, 95,160, 95,168, 95,173, 95,188, 95,214, 95,251, 95,228, 95,248, 95,241, 95,221, 96,179, 95,255, 96, 33, 96, 96, 0, 32, 96, 25, 96, 16, 96, 41, 96, 14, 96, 49, 96, 27, 96, 21, 96, 43, 96, 38, 96, 15, 96, 58, 96, 90, 96, 65, 96,106, 96,119, 96, 95, 96, 74, 96, 70, 96, 77, 96, 99, 96, 67, 96,100, 96, 66, 96,108, 96,107, 96, 89, 96,129, 96,141, 96,231, 96,131, 96,154, 96,132, 96,155, 96,150, 96,151, 96,146, 96,167, 96,139, 96,225, 96,184, 96,224, 96,211, 96,180, 95,240, 96,189, 96,198, 96,181, 96,216, 97, 77, 97, 21, 97, 6, 96,246, 96,247, 97, 0, 96,244, 96,250, 97, 3, 97, 33, 96,251, 96,241, 97, 13, 97, 14, 97, 71, 97, 62, 97, 40, 97, 39, 97, 74, 97, 63, 97, 60, 97, 44, 97, 52, 97, 61, 97, 66, 97, 68, 97,115, 97,119, 97, 88, 97, 89, 97, 90, 97,107, 97,116, 97,111, 97,101, 97,113, 97, 95, 97, 93, 97, 83, 97,117, 97,153, 97,150, 97,135, 97,172, 97,148, 97,154, 97,138, 97,145, 97,171, 97,174, 97,204, 97,202, 97,201, 97,247, 97,200, 97,195, 97,198, 97,186, 97,203,127,121, 97,205, 97,230, 97,227, 97,246, 97,250, 97,244, 97,255, 97,253, 97,252, 97,254, 98, 0, 98, 8, 98, 9, 98, 13, 98, 12, 98, 20, 98, 27, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 98, 30, 98, 33, 98, 42, 98, 46, 98, 48, 98, 50, 98, 51, 98, 65, 98, 78, 98, 94, 98, 99, 98, 91, 98, 96, 98,104, 98,124, 98,130, 98,137, 98,126, 98,146, 98,147, 98,150, 98,212, 98,131, 98,148, 98,215, 98,209, 98,187, 98,207, 98,255, 98,198,100,212, 98,200, 98,220, 98,204, 98,202, 98,194, 98,199, 98,155, 98,201, 99, 12, 98,238, 98,241, 99, 39, 99, 2, 99, 8, 98,239, 98,245, 99, 80, 99, 62, 99, 77,100, 28, 99, 79, 99,150, 99,142, 99,128, 99,171, 99,118, 99,163, 99,143, 99,137, 99,159, 99,181, 99,107, 0, 32, 99,105, 99,190, 99,233, 99,192, 99,198, 99,227, 99,201, 99,210, 99,246, 99,196,100, 22,100, 52,100, 6,100, 19,100, 38,100, 54, 101, 29,100, 23,100, 40,100, 15,100,103,100,111,100,118,100, 78,101, 42,100,149,100,147,100,165, 100,169,100,136,100,188,100,218,100,210,100,197,100,199,100,187,100,216,100,194,100,241,100,231, 130, 9,100,224,100,225, 98,172,100,227,100,239,101, 44,100,246,100,244,100,242,100,250,101, 0, 100,253,101, 24,101, 28,101, 5,101, 36,101, 35,101, 43,101, 52,101, 53,101, 55,101, 54,101, 56, 117, 75,101, 72,101, 86,101, 85,101, 77,101, 88,101, 94,101, 93,101,114,101,120,101,130,101,131, 139,138,101,155,101,159,101,171,101,183,101,195,101,198,101,193,101,196,101,204,101,210,101,219, 101,217,101,224,101,225,101,241,103,114,102, 10,102, 3,101,251,103,115,102, 53,102, 54,102, 52, 102, 28,102, 79,102, 68,102, 73,102, 65,102, 94,102, 93,102,100,102,103,102,104,102, 95,102, 98, 102,112,102,131,102,136,102,142,102,137,102,132,102,152,102,157,102,193,102,185,102,201,102,190, 102,188, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,102,196,102,184,102,214,102,218, 102,224,102, 63,102,230,102,233,102,240,102,245,102,247,103, 15,103, 22,103, 30,103, 38,103, 39, 151, 56,103, 46,103, 63,103, 54,103, 65,103, 56,103, 55,103, 70,103, 94,103, 96,103, 89,103, 99, 103,100,103,137,103,112,103,169,103,124,103,106,103,140,103,139,103,166,103,161,103,133,103,183, 103,239,103,180,103,236,103,179,103,233,103,184,103,228,103,222,103,221,103,226,103,238,103,185, 103,206,103,198,103,231,106,156,104, 30,104, 70,104, 41,104, 64,104, 77,104, 50,104, 78, 0, 32, 104,179,104, 43,104, 89,104, 99,104,119,104,127,104,159,104,143,104,173,104,148,104,157,104,155, 104,131,106,174,104,185,104,116,104,181,104,160,104,186,105, 15,104,141,104,126,105, 1,104,202, 105, 8,104,216,105, 34,105, 38,104,225,105, 12,104,205,104,212,104,231,104,213,105, 54,105, 18, 105, 4,104,215,104,227,105, 37,104,249,104,224,104,239,105, 40,105, 42,105, 26,105, 35,105, 33, 104,198,105,121,105,119,105, 92,105,120,105,107,105, 84,105,126,105,110,105, 57,105,116,105, 61, 105, 89,105, 48,105, 97,105, 94,105, 93,105,129,105,106,105,178,105,174,105,208,105,191,105,193, 105,211,105,190,105,206, 91,232,105,202,105,221,105,187,105,195,105,167,106, 46,105,145,105,160, 105,156,105,149,105,180,105,222,105,232,106, 2,106, 27,105,255,107, 10,105,249,105,242,105,231, 106, 5,105,177,106, 30,105,237,106, 20,105,235,106, 10,106, 18,106,193,106, 35,106, 19,106, 68, 106, 12,106,114,106, 54,106,120,106, 71,106, 98,106, 89,106,102,106, 72,106, 56,106, 34,106,144, 106,141,106,160,106,132,106,162,106,163, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 106,151,134, 23,106,187,106,195,106,194,106,184,106,179,106,172,106,222,106,209,106,223,106,170, 106,218,106,234,106,251,107, 5,134, 22,106,250,107, 18,107, 22,155, 49,107, 31,107, 56,107, 55, 118,220,107, 57,152,238,107, 71,107, 67,107, 73,107, 80,107, 89,107, 84,107, 91,107, 95,107, 97, 107,120,107,121,107,127,107,128,107,132,107,131,107,141,107,152,107,149,107,158,107,164,107,170, 107,171,107,175,107,178,107,177,107,179,107,183,107,188,107,198,107,203,107,211,107,223,107,236, 107,235,107,243,107,239, 0, 32,158,190,108, 8,108, 19,108, 20,108, 27,108, 36,108, 35,108, 94, 108, 85,108, 98,108,106,108,130,108,141,108,154,108,129,108,155,108,126,108,104,108,115,108,146, 108,144,108,196,108,241,108,211,108,189,108,215,108,197,108,221,108,174,108,177,108,190,108,186, 108,219,108,239,108,217,108,234,109, 31,136, 77,109, 54,109, 43,109, 61,109, 56,109, 25,109, 53, 109, 51,109, 18,109, 12,109, 99,109,147,109,100,109, 90,109,121,109, 89,109,142,109,149,111,228, 109,133,109,249,110, 21,110, 10,109,181,109,199,109,230,109,184,109,198,109,236,109,222,109,204, 109,232,109,210,109,197,109,250,109,217,109,228,109,213,109,234,109,238,110, 45,110,110,110, 46, 110, 25,110,114,110, 95,110, 62,110, 35,110,107,110, 43,110,118,110, 77,110, 31,110, 67,110, 58, 110, 78,110, 36,110,255,110, 29,110, 56,110,130,110,170,110,152,110,201,110,183,110,211,110,189, 110,175,110,196,110,178,110,212,110,213,110,143,110,165,110,194,110,159,111, 65,111, 17,112, 76, 110,236,110,248,110,254,111, 63,110,242,111, 49,110,239,111, 50,110,204, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,111, 62,111, 19,110,247,111,134,111,122,111,120,111,129,111,128, 111,111,111, 91,111,243,111,109,111,130,111,124,111, 88,111,142,111,145,111,194,111,102,111,179, 111,163,111,161,111,164,111,185,111,198,111,170,111,223,111,213,111,236,111,212,111,216,111,241, 111,238,111,219,112, 9,112, 11,111,250,112, 17,112, 1,112, 15,111,254,112, 27,112, 26,111,116, 112, 29,112, 24,112, 31,112, 48,112, 62,112, 50,112, 81,112, 99,112,153,112,146,112,175,112,241, 112,172,112,184,112,179,112,174,112,223,112,203,112,221, 0, 32,112,217,113, 9,112,253,113, 28, 113, 25,113,101,113, 85,113,136,113,102,113, 98,113, 76,113, 86,113,108,113,143,113,251,113,132, 113,149,113,168,113,172,113,215,113,185,113,190,113,210,113,201,113,212,113,206,113,224,113,236, 113,231,113,245,113,252,113,249,113,255,114, 13,114, 16,114, 27,114, 40,114, 45,114, 44,114, 48, 114, 50,114, 59,114, 60,114, 63,114, 64,114, 70,114, 75,114, 88,114,116,114,126,114,130,114,129, 114,135,114,146,114,150,114,162,114,167,114,185,114,178,114,195,114,198,114,196,114,206,114,210, 114,226,114,224,114,225,114,249,114,247, 80, 15,115, 23,115, 10,115, 28,115, 22,115, 29,115, 52, 115, 47,115, 41,115, 37,115, 62,115, 78,115, 79,158,216,115, 87,115,106,115,104,115,112,115,120, 115,117,115,123,115,122,115,200,115,179,115,206,115,187,115,192,115,229,115,238,115,222,116,162, 116, 5,116,111,116, 37,115,248,116, 50,116, 58,116, 85,116, 63,116, 95,116, 89,116, 65,116, 92, 116,105,116,112,116, 99,116,106,116,118,116,126,116,139,116,158,116,167,116,202,116,207,116,212, 115,241, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,116,224,116,227,116,231,116,233, 116,238,116,242,116,240,116,241,116,248,116,247,117, 4,117, 3,117, 5,117, 12,117, 14,117, 13, 117, 21,117, 19,117, 30,117, 38,117, 44,117, 60,117, 68,117, 77,117, 74,117, 73,117, 91,117, 70, 117, 90,117,105,117,100,117,103,117,107,117,109,117,120,117,118,117,134,117,135,117,116,117,138, 117,137,117,130,117,148,117,154,117,157,117,165,117,163,117,194,117,179,117,195,117,181,117,189, 117,184,117,188,117,177,117,205,117,202,117,210,117,217,117,227,117,222,117,254,117,255, 0, 32, 117,252,118, 1,117,240,117,250,117,242,117,243,118, 11,118, 13,118, 9,118, 31,118, 39,118, 32, 118, 33,118, 34,118, 36,118, 52,118, 48,118, 59,118, 71,118, 72,118, 70,118, 92,118, 88,118, 97, 118, 98,118,104,118,105,118,106,118,103,118,108,118,112,118,114,118,118,118,120,118,124,118,128, 118,131,118,136,118,139,118,142,118,150,118,147,118,153,118,154,118,176,118,180,118,184,118,185, 118,186,118,194,118,205,118,214,118,210,118,222,118,225,118,229,118,231,118,234,134, 47,118,251, 119, 8,119, 7,119, 4,119, 41,119, 36,119, 30,119, 37,119, 38,119, 27,119, 55,119, 56,119, 71, 119, 90,119,104,119,107,119, 91,119,101,119,127,119,126,119,121,119,142,119,139,119,145,119,160, 119,158,119,176,119,182,119,185,119,191,119,188,119,189,119,187,119,199,119,205,119,215,119,218, 119,220,119,227,119,238,119,252,120, 12,120, 18,121, 38,120, 32,121, 42,120, 69,120,142,120,116, 120,134,120,124,120,154,120,140,120,163,120,181,120,170,120,175,120,209,120,198,120,203,120,212, 120,190,120,188,120,197,120,202,120,236, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 120,231,120,218,120,253,120,244,121, 7,121, 18,121, 17,121, 25,121, 44,121, 43,121, 64,121, 96, 121, 87,121, 95,121, 90,121, 85,121, 83,121,122,121,127,121,138,121,157,121,167,159, 75,121,170, 121,174,121,179,121,185,121,186,121,201,121,213,121,231,121,236,121,225,121,227,122, 8,122, 13, 122, 24,122, 25,122, 32,122, 31,121,128,122, 49,122, 59,122, 62,122, 55,122, 67,122, 87,122, 73, 122, 97,122, 98,122,105,159,157,122,112,122,121,122,125,122,136,122,151,122,149,122,152,122,150, 122,169,122,200,122,176, 0, 32,122,182,122,197,122,196,122,191,144,131,122,199,122,202,122,205, 122,207,122,213,122,211,122,217,122,218,122,221,122,225,122,226,122,230,122,237,122,240,123, 2, 123, 15,123, 10,123, 6,123, 51,123, 24,123, 25,123, 30,123, 53,123, 40,123, 54,123, 80,123,122, 123, 4,123, 77,123, 11,123, 76,123, 69,123,117,123,101,123,116,123,103,123,112,123,113,123,108, 123,110,123,157,123,152,123,159,123,141,123,156,123,154,123,139,123,146,123,143,123, 93,123,153, 123,203,123,193,123,204,123,207,123,180,123,198,123,221,123,233,124, 17,124, 20,123,230,123,229, 124, 96,124, 0,124, 7,124, 19,123,243,123,247,124, 23,124, 13,123,246,124, 35,124, 39,124, 42, 124, 31,124, 55,124, 43,124, 61,124, 76,124, 67,124, 84,124, 79,124, 64,124, 80,124, 88,124, 95, 124,100,124, 86,124,101,124,108,124,117,124,131,124,144,124,164,124,173,124,162,124,171,124,161, 124,168,124,179,124,178,124,177,124,174,124,185,124,189,124,192,124,197,124,194,124,216,124,210, 124,220,124,226,155, 59,124,239,124,242,124,244,124,246,124,250,125, 6, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,125, 2,125, 28,125, 21,125, 10,125, 69,125, 75,125, 46,125, 50, 125, 63,125, 53,125, 70,125,115,125, 86,125, 78,125,114,125,104,125,110,125, 79,125, 99,125,147, 125,137,125, 91,125,143,125,125,125,155,125,186,125,174,125,163,125,181,125,199,125,189,125,171, 126, 61,125,162,125,175,125,220,125,184,125,159,125,176,125,216,125,221,125,228,125,222,125,251, 125,242,125,225,126, 5,126, 10,126, 35,126, 33,126, 18,126, 49,126, 31,126, 9,126, 11,126, 34, 126, 70,126,102,126, 59,126, 53,126, 57,126, 67,126, 55, 0, 32,126, 50,126, 58,126,103,126, 93, 126, 86,126, 94,126, 89,126, 90,126,121,126,106,126,105,126,124,126,123,126,131,125,213,126,125, 143,174,126,127,126,136,126,137,126,140,126,146,126,144,126,147,126,148,126,150,126,142,126,155, 126,156,127, 56,127, 58,127, 69,127, 76,127, 77,127, 78,127, 80,127, 81,127, 85,127, 84,127, 88, 127, 95,127, 96,127,104,127,105,127,103,127,120,127,130,127,134,127,131,127,136,127,135,127,140, 127,148,127,158,127,157,127,154,127,163,127,175,127,178,127,185,127,174,127,182,127,184,139,113, 127,197,127,198,127,202,127,213,127,212,127,225,127,230,127,233,127,243,127,249,152,220,128, 6, 128, 4,128, 11,128, 18,128, 24,128, 25,128, 28,128, 33,128, 40,128, 63,128, 59,128, 74,128, 70, 128, 82,128, 88,128, 90,128, 95,128, 98,128,104,128,115,128,114,128,112,128,118,128,121,128,125, 128,127,128,132,128,134,128,133,128,155,128,147,128,154,128,173, 81,144,128,172,128,219,128,229, 128,217,128,221,128,196,128,218,128,214,129, 9,128,239,128,241,129, 27,129, 41,129, 35,129, 47, 129, 75, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,150,139,129, 70,129, 62,129, 83, 129, 81,128,252,129,113,129,110,129,101,129,102,129,116,129,131,129,136,129,138,129,128,129,130, 129,160,129,149,129,164,129,163,129, 95,129,147,129,169,129,176,129,181,129,190,129,184,129,189, 129,192,129,194,129,186,129,201,129,205,129,209,129,217,129,216,129,200,129,218,129,223,129,224, 129,231,129,250,129,251,129,254,130, 1,130, 2,130, 5,130, 7,130, 10,130, 13,130, 16,130, 22, 130, 41,130, 43,130, 56,130, 51,130, 64,130, 89,130, 88,130, 93,130, 90,130, 95,130,100, 0, 32, 130, 98,130,104,130,106,130,107,130, 46,130,113,130,119,130,120,130,126,130,141,130,146,130,171, 130,159,130,187,130,172,130,225,130,227,130,223,130,210,130,244,130,243,130,250,131,147,131, 3, 130,251,130,249,130,222,131, 6,130,220,131, 9,130,217,131, 53,131, 52,131, 22,131, 50,131, 49, 131, 64,131, 57,131, 80,131, 69,131, 47,131, 43,131, 23,131, 24,131,133,131,154,131,170,131,159, 131,162,131,150,131, 35,131,142,131,135,131,138,131,124,131,181,131,115,131,117,131,160,131,137, 131,168,131,244,132, 19,131,235,131,206,131,253,132, 3,131,216,132, 11,131,193,131,247,132, 7, 131,224,131,242,132, 13,132, 34,132, 32,131,189,132, 56,133, 6,131,251,132,109,132, 42,132, 60, 133, 90,132,132,132,119,132,107,132,173,132,110,132,130,132,105,132, 70,132, 44,132,111,132,121, 132, 53,132,202,132, 98,132,185,132,191,132,159,132,217,132,205,132,187,132,218,132,208,132,193, 132,198,132,214,132,161,133, 33,132,255,132,244,133, 23,133, 24,133, 44,133, 31,133, 21,133, 20, 132,252,133, 64,133, 99,133, 88,133, 72, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 133, 65,134, 2,133, 75,133, 85,133,128,133,164,133,136,133,145,133,138,133,168,133,109,133,148, 133,155,133,234,133,135,133,156,133,119,133,126,133,144,133,201,133,186,133,207,133,185,133,208, 133,213,133,221,133,229,133,220,133,249,134, 10,134, 19,134, 11,133,254,133,250,134, 6,134, 34, 134, 26,134, 48,134, 63,134, 77, 78, 85,134, 84,134, 95,134,103,134,113,134,147,134,163,134,169, 134,170,134,139,134,140,134,182,134,175,134,196,134,198,134,176,134,201,136, 35,134,171,134,212, 134,222,134,233,134,236, 0, 32,134,223,134,219,134,239,135, 18,135, 6,135, 8,135, 0,135, 3, 134,251,135, 17,135, 9,135, 13,134,249,135, 10,135, 52,135, 63,135, 55,135, 59,135, 37,135, 41, 135, 26,135, 96,135, 95,135,120,135, 76,135, 78,135,116,135, 87,135,104,135,110,135, 89,135, 83, 135, 99,135,106,136, 5,135,162,135,159,135,130,135,175,135,203,135,189,135,192,135,208,150,214, 135,171,135,196,135,179,135,199,135,198,135,187,135,239,135,242,135,224,136, 15,136, 13,135,254, 135,246,135,247,136, 14,135,210,136, 17,136, 22,136, 21,136, 34,136, 33,136, 49,136, 54,136, 57, 136, 39,136, 59,136, 68,136, 66,136, 82,136, 89,136, 94,136, 98,136,107,136,129,136,126,136,158, 136,117,136,125,136,181,136,114,136,130,136,151,136,146,136,174,136,153,136,162,136,141,136,164, 136,176,136,191,136,177,136,195,136,196,136,212,136,216,136,217,136,221,136,249,137, 2,136,252, 136,244,136,232,136,242,137, 4,137, 12,137, 10,137, 19,137, 67,137, 30,137, 37,137, 42,137, 43, 137, 65,137, 68,137, 59,137, 54,137, 56,137, 76,137, 29,137, 96,137, 94, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,137,102,137,100,137,109,137,106,137,111,137,116,137,119,137,126, 137,131,137,136,137,138,137,147,137,152,137,161,137,169,137,166,137,172,137,175,137,178,137,186, 137,189,137,191,137,192,137,218,137,220,137,221,137,231,137,244,137,248,138, 3,138, 22,138, 16, 138, 12,138, 27,138, 29,138, 37,138, 54,138, 65,138, 91,138, 82,138, 70,138, 72,138,124,138,109, 138,108,138, 98,138,133,138,130,138,132,138,168,138,161,138,145,138,165,138,166,138,154,138,163, 138,196,138,205,138,194,138,218,138,235,138,243,138,231, 0, 32,138,228,138,241,139, 20,138,224, 138,226,138,247,138,222,138,219,139, 12,139, 7,139, 26,138,225,139, 22,139, 16,139, 23,139, 32, 139, 51,151,171,139, 38,139, 43,139, 62,139, 40,139, 65,139, 76,139, 79,139, 78,139, 73,139, 86, 139, 91,139, 90,139,107,139, 95,139,108,139,111,139,116,139,125,139,128,139,140,139,142,139,146, 139,147,139,150,139,153,139,154,140, 58,140, 65,140, 63,140, 72,140, 76,140, 78,140, 80,140, 85, 140, 98,140,108,140,120,140,122,140,130,140,137,140,133,140,138,140,141,140,142,140,148,140,124, 140,152, 98, 29,140,173,140,170,140,189,140,178,140,179,140,174,140,182,140,200,140,193,140,228, 140,227,140,218,140,253,140,250,140,251,141, 4,141, 5,141, 10,141, 7,141, 15,141, 13,141, 16, 159, 78,141, 19,140,205,141, 20,141, 22,141,103,141,109,141,113,141,115,141,129,141,153,141,194, 141,190,141,186,141,207,141,218,141,214,141,204,141,219,141,203,141,234,141,235,141,223,141,227, 141,252,142, 8,142, 9,141,255,142, 29,142, 30,142, 16,142, 31,142, 66,142, 53,142, 48,142, 52, 142, 74, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,142, 71,142, 73,142, 76,142, 80, 142, 72,142, 89,142,100,142, 96,142, 42,142, 99,142, 85,142,118,142,114,142,124,142,129,142,135, 142,133,142,132,142,139,142,138,142,147,142,145,142,148,142,153,142,170,142,161,142,172,142,176, 142,198,142,177,142,190,142,197,142,200,142,203,142,219,142,227,142,252,142,251,142,235,142,254, 143, 10,143, 5,143, 21,143, 18,143, 25,143, 19,143, 28,143, 31,143, 27,143, 12,143, 38,143, 51, 143, 59,143, 57,143, 69,143, 66,143, 62,143, 76,143, 73,143, 70,143, 78,143, 87,143, 92, 0, 32, 143, 98,143, 99,143,100,143,156,143,159,143,163,143,173,143,175,143,183,143,218,143,229,143,226, 143,234,143,239,144,135,143,244,144, 5,143,249,143,250,144, 17,144, 21,144, 33,144, 13,144, 30, 144, 22,144, 11,144, 39,144, 54,144, 53,144, 57,143,248,144, 79,144, 80,144, 81,144, 82,144, 14, 144, 73,144, 62,144, 86,144, 88,144, 94,144,104,144,111,144,118,150,168,144,114,144,130,144,125, 144,129,144,128,144,138,144,137,144,143,144,168,144,175,144,177,144,181,144,226,144,228, 98, 72, 144,219,145, 2,145, 18,145, 25,145, 50,145, 48,145, 74,145, 86,145, 88,145, 99,145,101,145,105, 145,115,145,114,145,139,145,137,145,130,145,162,145,171,145,175,145,170,145,181,145,180,145,186, 145,192,145,193,145,201,145,203,145,208,145,214,145,223,145,225,145,219,145,252,145,245,145,246, 146, 30,145,255,146, 20,146, 44,146, 21,146, 17,146, 94,146, 87,146, 69,146, 73,146,100,146, 72, 146,149,146, 63,146, 75,146, 80,146,156,146,150,146,147,146,155,146, 90,146,207,146,185,146,183, 146,233,147, 15,146,250,147, 68,147, 46, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 147, 25,147, 34,147, 26,147, 35,147, 58,147, 53,147, 59,147, 92,147, 96,147,124,147,110,147, 86, 147,176,147,172,147,173,147,148,147,185,147,214,147,215,147,232,147,229,147,216,147,195,147,221, 147,208,147,200,147,228,148, 26,148, 20,148, 19,148, 3,148, 7,148, 16,148, 54,148, 43,148, 53, 148, 33,148, 58,148, 65,148, 82,148, 68,148, 91,148, 96,148, 98,148, 94,148,106,146, 41,148,112, 148,117,148,119,148,125,148, 90,148,124,148,126,148,129,148,127,149,130,149,135,149,138,149,148, 149,150,149,152,149,153, 0, 32,149,160,149,168,149,167,149,173,149,188,149,187,149,185,149,190, 149,202,111,246,149,195,149,205,149,204,149,213,149,212,149,214,149,220,149,225,149,229,149,226, 150, 33,150, 40,150, 46,150, 47,150, 66,150, 76,150, 79,150, 75,150,119,150, 92,150, 94,150, 93, 150, 95,150,102,150,114,150,108,150,141,150,152,150,149,150,151,150,170,150,167,150,177,150,178, 150,176,150,180,150,182,150,184,150,185,150,206,150,203,150,201,150,205,137, 77,150,220,151, 13, 150,213,150,249,151, 4,151, 6,151, 8,151, 19,151, 14,151, 17,151, 15,151, 22,151, 25,151, 36, 151, 42,151, 48,151, 57,151, 61,151, 62,151, 68,151, 70,151, 72,151, 66,151, 73,151, 92,151, 96, 151,100,151,102,151,104, 82,210,151,107,151,113,151,121,151,133,151,124,151,129,151,122,151,134, 151,139,151,143,151,144,151,156,151,168,151,166,151,163,151,179,151,180,151,195,151,198,151,200, 151,203,151,220,151,237,159, 79,151,242,122,223,151,246,151,245,152, 15,152, 12,152, 56,152, 36, 152, 33,152, 55,152, 61,152, 70,152, 79,152, 75,152,107,152,111,152,112, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,152,113,152,116,152,115,152,170,152,175,152,177,152,182,152,196, 152,195,152,198,152,233,152,235,153, 3,153, 9,153, 18,153, 20,153, 24,153, 33,153, 29,153, 30, 153, 36,153, 32,153, 44,153, 46,153, 61,153, 62,153, 66,153, 73,153, 69,153, 80,153, 75,153, 81, 153, 82,153, 76,153, 85,153,151,153,152,153,165,153,173,153,174,153,188,153,223,153,219,153,221, 153,216,153,209,153,237,153,238,153,241,153,242,153,251,153,248,154, 1,154, 15,154, 5,153,226, 154, 25,154, 43,154, 55,154, 69,154, 66,154, 64,154, 67, 0, 32,154, 62,154, 85,154, 77,154, 91, 154, 87,154, 95,154, 98,154,101,154,100,154,105,154,107,154,106,154,173,154,176,154,188,154,192, 154,207,154,209,154,211,154,212,154,222,154,223,154,226,154,227,154,230,154,239,154,235,154,238, 154,244,154,241,154,247,154,251,155, 6,155, 24,155, 26,155, 31,155, 34,155, 35,155, 37,155, 39, 155, 40,155, 41,155, 42,155, 46,155, 47,155, 50,155, 68,155, 67,155, 79,155, 77,155, 78,155, 81, 155, 88,155,116,155,147,155,131,155,145,155,150,155,151,155,159,155,160,155,168,155,180,155,192, 155,202,155,185,155,198,155,207,155,209,155,210,155,227,155,226,155,228,155,212,155,225,156, 58, 155,242,155,241,155,240,156, 21,156, 20,156, 9,156, 19,156, 12,156, 6,156, 8,156, 18,156, 10, 156, 4,156, 46,156, 27,156, 37,156, 36,156, 33,156, 48,156, 71,156, 50,156, 70,156, 62,156, 90, 156, 96,156,103,156,118,156,120,156,231,156,236,156,240,157, 9,157, 8,156,235,157, 3,157, 6, 157, 42,157, 38,157,175,157, 35,157, 31,157, 68,157, 21,157, 18,157, 65,157, 63,157, 62,157, 70, 157, 72, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32,157, 93,157, 94,157,100,157, 81, 157, 80,157, 89,157,114,157,137,157,135,157,171,157,111,157,122,157,154,157,164,157,169,157,178, 157,196,157,193,157,187,157,184,157,186,157,198,157,207,157,194,157,217,157,211,157,248,157,230, 157,237,157,239,157,253,158, 26,158, 27,158, 30,158,117,158,121,158,125,158,129,158,136,158,139, 158,140,158,146,158,149,158,145,158,157,158,165,158,169,158,184,158,170,158,173,151, 97,158,204, 158,206,158,207,158,208,158,212,158,220,158,222,158,221,158,224,158,229,158,232,158,239, 0, 32, 158,244,158,246,158,247,158,249,158,251,158,252,158,253,159, 7,159, 8,118,183,159, 21,159, 33, 159, 44,159, 62,159, 74,159, 82,159, 84,159, 99,159, 95,159, 96,159, 97,159,102,159,103,159,108, 159,106,159,119,159,114,159,118,159,149,159,156,159,160, 88, 47,105,199,144, 89,116,100, 81,220, 113,153, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32 }; void ShiftJis2UTF8(const unsigned char *pccInput, unsigned char *pucOutput, int outputLength) { int idxIn = 0, idxOut = 0; while (pccInput[idxIn] != 0 && idxOut < outputLength) { char arraySection = pccInput[idxIn] >> 4; int arrayOffset = 0; if (arraySection == 0x8) arrayOffset = 0x100; //these are two-byte shiftjis else if(arraySection == 0x9) arrayOffset = 0x1100; else if(arraySection == 0xE) arrayOffset = 0x2100; //determining real array offset if (arrayOffset) { arrayOffset += (pccInput[idxIn] & 0xf) << 8; idxIn++; if (pccInput[idxIn] == 0) break; } arrayOffset += pccInput[idxIn++]; arrayOffset <<= 1; //unicode number is... uint16_t unicodeValue = (pucTable[arrayOffset] << 8) | pucTable[arrayOffset + 1]; //converting to UTF8 if (unicodeValue < 0x80) { pucOutput[idxOut++] = unicodeValue; } else if (unicodeValue < 0x800) { pucOutput[idxOut++] = 0xC0 | (unicodeValue >> 6); pucOutput[idxOut++] = 0x80 | (unicodeValue & 0x3f); } else { pucOutput[idxOut++] = 0xE0 | (unicodeValue >> 12); pucOutput[idxOut++] = 0x80 | ((unicodeValue & 0xfff) >> 6); pucOutput[idxOut++] = 0x80 | (unicodeValue & 0x3f); } } if (idxOut < outputLength) pucOutput[idxOut] = 0; else pucOutput[outputLength-1] = 0; } mupen64plus-core-src-2.6.0/src/main/util.h000066400000000000000000000231341464506436200203120ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - util.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2020 Richard42 * * Copyright (C) 2012 CasualJames * * Copyright (C) 2002 Hacktarux * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __UTIL_H__ #define __UTIL_H__ #include #include #include #include "osal/preproc.h" #if defined(__GNUC__) #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) #else #define ATTR_FMT(fmtpos, attrpos) #endif /********************** File utilities **********************/ typedef enum _file_status { file_ok, file_open_error, file_read_error, file_write_error, file_size_error } file_status_t; /** read_from_file * opens a file and reads the specified number of bytes. * returns zero on success, nonzero on failure */ file_status_t read_from_file(const char *filename, void *data, size_t size); /** write_to_file * opens a file and writes the specified number of bytes. * returns zero on success, nonzero on failure */ file_status_t write_to_file(const char *filename, const void *data, size_t size); /** write_chunk_to_file * opens a file, seek to offset and writes the specified number of bytes. * returns zero on success, nonzero on failure */ file_status_t write_chunk_to_file(const char *filename, const void *data, size_t size, size_t offset); /** load_file * load the file content into a newly allocated buffer. * returns zero on success, nonzero on failure */ file_status_t load_file(const char* filename, void** buffer, size_t* size); /** get_file_size * get file size. * returns zero on success, nonzero on failure */ file_status_t get_file_size(const char* filename, size_t* size); /********************** Byte swap utilities **********************/ #ifdef _MSC_VER #include #endif /* GCC has also byte swap intrinsics (__builtin_bswap32, etc.), but they were * added in relatively recent versions. In addition, GCC can detect the byte * swap code and optimize it with a high enough optimization level. */ static osal_inline unsigned short m64p_swap16(unsigned short x) { #ifdef _MSC_VER return _byteswap_ushort(x); #else return ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8); #endif } static osal_inline unsigned int m64p_swap32(unsigned int x) { #ifdef _MSC_VER return _byteswap_ulong(x); // long is always 32-bit in Windows #else return ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24); #endif } static osal_inline unsigned long long int m64p_swap64(unsigned long long int x) { #ifdef _MSC_VER return _byteswap_uint64(x); #else return ((x & 0x00000000000000FFULL) << 56) | ((x & 0x000000000000FF00ULL) << 40) | ((x & 0x0000000000FF0000ULL) << 24) | ((x & 0x00000000FF000000ULL) << 8) | ((x & 0x000000FF00000000ULL) >> 8) | ((x & 0x0000FF0000000000ULL) >> 24) | ((x & 0x00FF000000000000ULL) >> 40) | ((x & 0xFF00000000000000ULL) >> 56); #endif } #ifdef M64P_BIG_ENDIAN #define big16(x) (x) #define big32(x) (x) #define big64(x) (x) #define little16(x) m64p_swap16(x) #define little32(x) m64p_swap32(x) #define little64(x) m64p_swap64(x) #else #define big16(x) m64p_swap16(x) #define big32(x) m64p_swap32(x) #define big64(x) m64p_swap64(x) #define little16(x) (x) #define little32(x) (x) #define little64(x) (x) #endif /* Byte swaps, converts to little endian or converts to big endian a buffer, * containing 'count' elements, each of size 'length'. */ void swap_buffer(void *buffer, size_t length, size_t count); void to_little_endian_buffer(void *buffer, size_t length, size_t count); void to_big_endian_buffer(void *buffer, size_t length, size_t count); /* Simple serialization primitives, * Loosely modeled after N2827 proposal. */ uint8_t load_beu8(const unsigned char *ptr); uint16_t load_beu16(const unsigned char *ptr); uint32_t load_beu32(const unsigned char *ptr); uint64_t load_beu64(const unsigned char *ptr); uint8_t load_leu8(const unsigned char *ptr); uint16_t load_leu16(const unsigned char *ptr); uint32_t load_leu32(const unsigned char *ptr); uint64_t load_leu64(const unsigned char *ptr); void store_beu8(uint8_t value, unsigned char *ptr); void store_beu16(uint16_t value, unsigned char *ptr); void store_beu32(uint32_t value, unsigned char *ptr); void store_beu64(uint64_t value, unsigned char *ptr); void store_leu8(uint8_t value, unsigned char *ptr); void store_leu16(uint16_t value, unsigned char *ptr); void store_leu32(uint32_t value, unsigned char *ptr); void store_leu64(uint64_t value, unsigned char *ptr); /********************** Random utilities **********************/ struct xoshiro256pp_state { uint64_t s[4]; }; struct xoshiro256pp_state xoshiro256pp_seed(uint64_t seed); uint64_t xoshiro256pp_next(struct xoshiro256pp_state* s); /********************** GUI utilities **********************/ void countrycodestring(uint16_t countrycode, char *string); void imagestring(unsigned char imagetype, char *string); /********************** Path utilities **********************/ /* Extracts the full file name (with extension) from a path string. * Returns the same string, advanced until the file name. */ const char* namefrompath(const char* path); /* Creates a path string by joining two path strings. * The given path strings may or may not start or end with a path separator. * Returns a malloc'd string with the resulting path. */ char* combinepath(const char* first, const char *second); /********************** String utilities **********************/ /* strpbrk_reverse * Looks for an instance of ANY of the characters in 'needles' in 'haystack', * starting from the end of 'haystack'. Returns a pointer to the last position * of some character on 'needles' on 'haystack'. If not found, returns NULL. */ char* strpbrk_reverse(const char* needles, char* haystack, size_t haystack_len); /** trim * Removes leading and trailing whitespace from str. Function modifies str * and also returns modified string. */ char *trim(char *str); /* Replaces all occurences of any char in chars with r in string. * returns amount of replaced chars */ int string_replace_chars(char *str, const char *chars, const char r); /* Converts an string to an integer. * Returns 1 on success, 0 on failure. 'result' is undefined on failure. * * The following conditions cause this function to fail: * - Empty string * - Leading characters (including whitespace) * - Trailing characters (including whitespace) * - Overflow or underflow. */ int string_to_int(const char *str, int *result); /* Converts an string of hexadecimal characters to a byte array. * 'output_size' is the number of bytes (hex digraphs) to convert. * Returns 1 on success, 0 on failure. 'output' is undefined on failure. */ int parse_hex(const char *str, unsigned char *output, size_t output_size); /* Formats an string, using the same syntax as printf. * Returns the result in a malloc'd string. */ char* formatstr(const char* fmt, ...) ATTR_FMT(1, 2); typedef enum _ini_line_type { INI_BLANK, INI_COMMENT, INI_SECTION, INI_PROPERTY, INI_TRASH } ini_line_type; typedef struct _ini_line { ini_line_type type; char *name; char *value; } ini_line; /* Parses the INI file line pointer by 'lineptr'. * The first line pointed by 'lineptr' may be modifed. * 'lineptr' will point to the next line after this function runs. * * Returns a ini_line structure with information about the line. * For INI_COMMENT, the value field contains the comment. * For INI_SECTION, the name field contains the section name. * For INI_PROPERTY, the name and value fields contain the property parameters. * The line type is INI_BLANK if the line is blank or invalid. * * The name and value fields (if any) of ini_line point to 'lineptr' * (so their lifetime is associated to that of 'lineptr'). */ ini_line ini_parse_line(char **lineptr); /* Convert text in Shift-JIS (code page 932) to UTF-8 */ void ShiftJis2UTF8(const unsigned char *pccInput, unsigned char *pucOutput, int outputLength); #endif // __UTIL_H__ mupen64plus-core-src-2.6.0/src/main/version.h000066400000000000000000000037421464506436200210250ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - version.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008-2012 Richard42 DarkJeztr Tillin9 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Version macros automatically replaced by Makefiles. */ #ifndef __VERSION_H__ #define __VERSION_H__ #define MUPEN_CORE_NAME "Mupen64Plus Core" #define MUPEN_CORE_VERSION 0x020600 #define FRONTEND_API_VERSION 0x020106 #define CONFIG_API_VERSION 0x020302 #define DEBUG_API_VERSION 0x020001 #define VIDEXT_API_VERSION 0x030300 #define NETPLAY_API_VERSION 0x010001 #define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff) #endif /* __VERSION_H__ */ mupen64plus-core-src-2.6.0/src/main/workqueue.c000066400000000000000000000137701464506436200213640ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - util.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 Mupen64plus development team * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "workqueue.h" #include #include #include #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "main/list.h" #define WORKQUEUE_THREADS 1 struct workqueue_mgmt_globals { struct list_head work_queue; struct list_head thread_queue; struct list_head thread_list; SDL_mutex *lock; }; struct workqueue_thread { SDL_Thread *thread; SDL_cond *work_avail; struct list_head list; struct list_head list_mgmt; }; static struct workqueue_mgmt_globals workqueue_mgmt; static void workqueue_dismiss(struct work_struct *work) { } static struct work_struct *workqueue_get_work(struct workqueue_thread *thread) { int found = 0; struct work_struct *work; for (;;) { SDL_LockMutex(workqueue_mgmt.lock); list_del_init(&thread->list); if (!list_empty(&workqueue_mgmt.work_queue)) { found = 1; work = list_first_entry(&workqueue_mgmt.work_queue, struct work_struct, list); list_del_init(&work->list); } else { list_add(&thread->list, &workqueue_mgmt.thread_queue); SDL_CondWait(thread->work_avail, workqueue_mgmt.lock); } SDL_UnlockMutex(workqueue_mgmt.lock); if (found) break; } return work; } static int workqueue_thread_handler(void *data) { struct workqueue_thread *thread = data; struct work_struct *work; for (;;) { work = workqueue_get_work(thread); if (work->func == workqueue_dismiss) { free(work); break; } work->func(work); } return 0; } int workqueue_init(void) { size_t i; struct workqueue_thread *thread; memset(&workqueue_mgmt, 0, sizeof(workqueue_mgmt)); INIT_LIST_HEAD(&workqueue_mgmt.work_queue); INIT_LIST_HEAD(&workqueue_mgmt.thread_queue); INIT_LIST_HEAD(&workqueue_mgmt.thread_list); workqueue_mgmt.lock = SDL_CreateMutex(); if (!workqueue_mgmt.lock) { DebugMessage(M64MSG_ERROR, "Could not create workqueue management"); return -1; } SDL_LockMutex(workqueue_mgmt.lock); for (i = 0; i < WORKQUEUE_THREADS; i++) { thread = malloc(sizeof(*thread)); if (!thread) { DebugMessage(M64MSG_ERROR, "Could not create workqueue thread management data"); SDL_UnlockMutex(workqueue_mgmt.lock); return -1; } memset(thread, 0, sizeof(*thread)); list_add(&thread->list_mgmt, &workqueue_mgmt.thread_list); INIT_LIST_HEAD(&thread->list); thread->work_avail = SDL_CreateCond(); if (!thread->work_avail) { DebugMessage(M64MSG_ERROR, "Could not create workqueue thread work_avail condition"); SDL_UnlockMutex(workqueue_mgmt.lock); return -1; } #if SDL_VERSION_ATLEAST(2,0,0) thread->thread = SDL_CreateThread(workqueue_thread_handler, "m64pwq", thread); #else thread->thread = SDL_CreateThread(workqueue_thread_handler, thread); #endif if (!thread->thread) { DebugMessage(M64MSG_ERROR, "Could not create workqueue thread handler"); SDL_UnlockMutex(workqueue_mgmt.lock); return -1; } } SDL_UnlockMutex(workqueue_mgmt.lock); return 0; } void workqueue_shutdown(void) { size_t i; int status; struct work_struct *work; struct workqueue_thread *thread, *safe; for (i = 0; i < WORKQUEUE_THREADS; i++) { work = malloc(sizeof(*work)); init_work(work, workqueue_dismiss); queue_work(work); } list_for_each_entry_safe_t(thread, safe, &workqueue_mgmt.thread_list, struct workqueue_thread, list_mgmt) { list_del(&thread->list_mgmt); SDL_WaitThread(thread->thread, &status); SDL_DestroyCond(thread->work_avail); free(thread); } if (!list_empty(&workqueue_mgmt.work_queue)) DebugMessage(M64MSG_WARNING, "Stopped workqueue with work still pending"); SDL_DestroyMutex(workqueue_mgmt.lock); } int queue_work(struct work_struct *work) { struct workqueue_thread *thread; SDL_LockMutex(workqueue_mgmt.lock); list_add_tail(&work->list, &workqueue_mgmt.work_queue); if (!list_empty(&workqueue_mgmt.thread_queue)) { thread = list_first_entry(&workqueue_mgmt.thread_queue, struct workqueue_thread, list); list_del_init(&thread->list); SDL_CondSignal(thread->work_avail); } SDL_UnlockMutex(workqueue_mgmt.lock); return 0; } mupen64plus-core-src-2.6.0/src/main/workqueue.h000066400000000000000000000043571464506436200213720ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - util.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2012 Mupen64plus development team * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __WORKQUEUE_H__ #define __WORKQUEUE_H__ #include "list.h" #include "osal/preproc.h" struct work_struct; typedef void (*work_func_t)(struct work_struct *work); struct work_struct { work_func_t func; struct list_head list; }; static osal_inline void init_work(struct work_struct *work, work_func_t func) { INIT_LIST_HEAD(&work->list); work->func = func; } #ifdef M64P_PARALLEL int workqueue_init(void); void workqueue_shutdown(void); int queue_work(struct work_struct *work); #else static osal_inline int workqueue_init(void) { return 0; } static osal_inline void workqueue_shutdown(void) { } static osal_inline int queue_work(struct work_struct *work) { work->func(work); return 0; } #endif #endif mupen64plus-core-src-2.6.0/src/osal/000077500000000000000000000000001464506436200171735ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/osal/dynamiclib.h000066400000000000000000000033461464506436200214650ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/dynamiclib.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(OSAL_DYNAMICLIB_H) #define OSAL_DYNAMICLIB_H #include "api/m64p_types.h" m64p_function osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName); #endif /* #define OSAL_DYNAMICLIB_H */ mupen64plus-core-src-2.6.0/src/osal/dynamiclib_unix.c000066400000000000000000000040251464506436200225160ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/dynamiclib_unix.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "osal/preproc.h" #include "dynamiclib.h" m64p_function osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) { if (pccProcedureName == NULL) return NULL; /* WARN: assume cast to m64p_function is supported by platform and disable warning accordingly */ OSAL_WARNING_PUSH OSAL_NO_WARNING_FPTR_VOIDP_CAST return (m64p_function)dlsym(LibHandle, pccProcedureName); OSAL_WARNING_POP } mupen64plus-core-src-2.6.0/src/osal/dynamiclib_win32.c000066400000000000000000000040301464506436200224710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-ui-console - osal_dynamiclib_win32.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "api/m64p_types.h" #include "osal/preproc.h" #include "dynamiclib.h" m64p_function osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) { if (pccProcedureName == NULL) return NULL; /* WARN: assume cast to m64p_function is supported by platform and disable warning accordingly */ OSAL_WARNING_PUSH OSAL_NO_WARNING_FPTR_VOIDP_CAST return (m64p_function)GetProcAddress(LibHandle, pccProcedureName); OSAL_WARNING_POP } mupen64plus-core-src-2.6.0/src/osal/files.h000066400000000000000000000056071464506436200204560ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/files.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the declarations for OS-dependent file handling * functions */ #if !defined (OSAL_FILES_H) #define OSAL_FILES_H #include /* some file-related preprocessor definitions */ #if defined(WIN32) #include // For _unlink() #define unlink _unlink #define OSAL_DIR_SEPARATORS "\\/" #define WIDE_OSAL_DIR_SEPARATORS L"\\/" #ifndef PATH_MAX #define PATH_MAX _MAX_PATH #endif #else /* Not WIN32 */ #include // for PATH_MAX #include // for unlink() #define OSAL_DIR_SEPARATORS "/" #define WIDE_OSAL_DIR_SEPARATORS L"/" /* PATH_MAX only may be defined by limits.h */ #ifndef PATH_MAX #define PATH_MAX 4096 #endif #endif /* Create a directory path recursively. * Returns zero on success, nonzero on failure. * Note that, unlike mkdir(), this function succeeds if the path already exists. */ extern int osal_mkdirp(const char *dirpath, int mode); extern const char * osal_get_shared_filepath(const char *filename, const char *firstsearch, const char *secondsearch); extern const char * osal_get_user_configpath(void); extern const char * osal_get_user_datapath(void); extern const char * osal_get_user_cachepath(void); extern FILE * osal_file_open (const char *filename, const char *mode); extern gzFile osal_gzopen(const char *filename, const char *mode); #endif /* OSAL_FILES_H */ mupen64plus-core-src-2.6.0/src/osal/files_macos.c000066400000000000000000000167531464506436200216370ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/files_macos.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2017 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the unix-specific file handling * functions */ #include #include #include #include #include #include #include #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "files.h" /* OS X code for app bundle handling */ #include // dynamic data path detection onmac bool macSetBundlePath(char* buffer) { // the following code will enable mupen to find its data when placed in an app bundle on mac OS X. // returns true if path is set, returns false if path was not set char path[1024] = { 0 }; CFBundleRef main_bundle = CFBundleGetMainBundle(); assert(main_bundle); CFURLRef main_bundle_URL = CFBundleCopyBundleURL(main_bundle); assert(main_bundle_URL); CFStringRef cf_string_ref = CFURLCopyFileSystemPath( main_bundle_URL, kCFURLPOSIXPathStyle); assert(cf_string_ref); CFStringGetCString(cf_string_ref, path, 1024, kCFStringEncodingASCII); CFRelease(main_bundle_URL); CFRelease(cf_string_ref); if (strstr( path, ".app" ) != 0) { DebugMessage(M64MSG_VERBOSE, "checking whether we are using an app bundle: yes"); // executable is inside an app bundle, use app bundle-relative paths sprintf(buffer, "%s/Contents/Resources/", path); return true; } else { DebugMessage(M64MSG_VERBOSE, "checking whether we are using an app bundle: no"); return false; } } /* definitions for system directories to search when looking for shared data files */ #if defined(SHAREDIR) #define XSTR(S) STR(S) /* this wacky preprocessor thing is necessary to generate a quote-enclosed */ #define STR(S) #S /* copy of the SHAREDIR macro, which is defined by the makefile via gcc -DSHAREDIR="..." */ static const int datasearchdirs = 2; static const char *datasearchpath[2] = { XSTR(SHAREDIR), "./" }; #undef STR #undef XSTR #else static const int datasearchdirs = 1; static const char *datasearchpath[1] = { "./" }; #endif /* local functions */ static int search_dir_file(char *destpath, const char *path, const char *filename) { struct stat fileinfo; /* sanity check to start */ if (destpath == NULL || path == NULL || filename == NULL) return 1; /* build the full filepath */ strcpy(destpath, path); /* if the path is empty, don't add / between it and the file name */ if (destpath[0] != '\0' && destpath[strlen(destpath)-1] != '/') strcat(destpath, "/"); strcat(destpath, filename); /* test for a valid file */ if (stat(destpath, &fileinfo) != 0) return 2; if (!S_ISREG(fileinfo.st_mode)) return 3; /* success - file exists and is a regular file */ return 0; } /* global functions */ int osal_mkdirp(const char *dirpath, int mode) { char *mypath, *currpath; struct stat fileinfo; // Terminate quickly if the path already exists if (stat(dirpath, &fileinfo) == 0 && S_ISDIR(fileinfo.st_mode)) return 0; // Create partial paths mypath = currpath = strdup(dirpath); if (mypath == NULL) return 1; while ((currpath = strpbrk(currpath + 1, OSAL_DIR_SEPARATORS)) != NULL) { *currpath = '\0'; if (stat(mypath, &fileinfo) != 0) { if (mkdir(mypath, mode) != 0) break; } else { if (!S_ISDIR(fileinfo.st_mode)) break; } *currpath = OSAL_DIR_SEPARATORS[0]; } free(mypath); if (currpath != NULL) return 1; // Create full path if (stat(dirpath, &fileinfo) != 0 && mkdir(dirpath, mode) != 0) return 1; return 0; } const char * osal_get_shared_filepath(const char *filename, const char *firstsearch, const char *secondsearch) { static char retpath[PATH_MAX]; int i; /* if caller gave us any directories to search, then look there first */ if (firstsearch != NULL && search_dir_file(retpath, firstsearch, filename) == 0) return retpath; if (secondsearch != NULL && search_dir_file(retpath, secondsearch, filename) == 0) return retpath; /* Special case : OS X bundles */ char buf[1024] = { 0 }; if (macSetBundlePath(buf)) { if (search_dir_file(retpath, buf, filename) == 0) return retpath; } /* otherwise check our standard paths */ for (i = 0; i < datasearchdirs; i++) { if (search_dir_file(retpath, datasearchpath[i], filename) == 0) return retpath; } /* we couldn't find the file */ return NULL; } const char * osal_get_user_configpath(void) { static char path[1024] = { 0 }; if (getenv("HOME") != NULL) { strcpy(path, getenv("HOME")); } else { struct passwd* pwd = getpwuid(getuid()); if (pwd) strcpy(path, pwd->pw_dir); } /* append the given sub-directory to the path given by the environment variable */ if (path[strlen(path)-1] != '/') strcat(path, "/"); strcat(path, "Library/Application Support/Mupen64Plus/"); /* try to create the resulting directory tree, or return successfully if it already exists */ if (osal_mkdirp(path, 0700) != 0) { DebugMessage(M64MSG_ERROR, "Couldn't create directory: %s", path); DebugMessage(M64MSG_ERROR, "Failed to get configuration directory; Path is undefined or invalid."); return NULL; } return path; } const char * osal_get_user_datapath(void) { // in macOS, these are all the same return osal_get_user_configpath(); } const char * osal_get_user_cachepath(void) { // in macOS, these are all the same return osal_get_user_configpath(); } FILE * osal_file_open ( const char * filename, const char * mode ) { return fopen (filename, mode); } gzFile osal_gzopen(const char *filename, const char *mode) { return gzopen(filename, mode); } mupen64plus-core-src-2.6.0/src/osal/files_unix.c000066400000000000000000000174061464506436200215140ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/files_unix.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the unix-specific file handling * functions */ #include #include #include #include #include #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "files.h" /* definitions for system directories to search when looking for shared data files */ #if defined(SHAREDIR) #define XSTR(S) STR(S) /* this wacky preprocessor thing is necessary to generate a quote-enclosed */ #define STR(S) #S /* copy of the SHAREDIR macro, which is defined by the makefile via gcc -DSHAREDIR="..." */ static const int datasearchdirs = 4; static const char *datasearchpath[4] = { XSTR(SHAREDIR), "/usr/local/share/mupen64plus", "/usr/share/mupen64plus", "./" }; #undef STR #undef XSTR #else static const int datasearchdirs = 3; static const char *datasearchpath[3] = { "/usr/local/share/mupen64plus", "/usr/share/mupen64plus", "./" }; #endif /* local functions */ static int get_xdg_dir(char *destpath, const char *envvar, const char *subdir) { struct stat fileinfo; const char *envpath = getenv(envvar); /* error if this environment variable doesn't return a good string */ if (envpath == NULL || strlen(envpath) < 1) return 1; /* error if path returned by the environemnt variable isn't a valid path to a directory */ if (stat(envpath, &fileinfo) != 0 || !S_ISDIR(fileinfo.st_mode)) return 2; /* append the given sub-directory to the path given by the environment variable */ strcpy(destpath, envpath); if (destpath[strlen(destpath)-1] != '/') strcat(destpath, "/"); strcat(destpath, subdir); /* try to create the resulting directory tree, or return successfully if it already exists */ if (osal_mkdirp(destpath, 0700) != 0) { DebugMessage(M64MSG_ERROR, "Couldn't create directory: %s", destpath); return 3; } /* Success */ return 0; } static int search_dir_file(char *destpath, const char *path, const char *filename) { struct stat fileinfo; /* sanity check to start */ if (destpath == NULL || path == NULL || filename == NULL) return 1; /* build the full filepath */ strcpy(destpath, path); /* if the path is empty, don't add / between it and the file name */ if (destpath[0] != '\0' && destpath[strlen(destpath)-1] != '/') strcat(destpath, "/"); strcat(destpath, filename); /* test for a valid file */ if (stat(destpath, &fileinfo) != 0) return 2; if (!S_ISREG(fileinfo.st_mode)) return 3; /* success - file exists and is a regular file */ return 0; } /* global functions */ int osal_mkdirp(const char *dirpath, int mode) { char *mypath, *currpath; struct stat fileinfo; // Terminate quickly if the path already exists if (stat(dirpath, &fileinfo) == 0 && S_ISDIR(fileinfo.st_mode)) return 0; // Create partial paths mypath = currpath = strdup(dirpath); if (mypath == NULL) return 1; while ((currpath = strpbrk(currpath + 1, OSAL_DIR_SEPARATORS)) != NULL) { *currpath = '\0'; if (stat(mypath, &fileinfo) != 0) { if (mkdir(mypath, mode) != 0) break; } else { if (!S_ISDIR(fileinfo.st_mode)) break; } *currpath = OSAL_DIR_SEPARATORS[0]; } free(mypath); if (currpath != NULL) return 1; // Create full path if (stat(dirpath, &fileinfo) != 0 && mkdir(dirpath, mode) != 0) return 1; return 0; } const char * osal_get_shared_filepath(const char *filename, const char *firstsearch, const char *secondsearch) { static char retpath[PATH_MAX]; int i; /* if caller gave us any directories to search, then look there first */ if (firstsearch != NULL && search_dir_file(retpath, firstsearch, filename) == 0) return retpath; if (secondsearch != NULL && search_dir_file(retpath, secondsearch, filename) == 0) return retpath; /* otherwise check our standard paths */ for (i = 0; i < datasearchdirs; i++) { if (search_dir_file(retpath, datasearchpath[i], filename) == 0) return retpath; } /* we couldn't find the file */ return NULL; } const char * osal_get_user_configpath(void) { static char retpath[PATH_MAX]; int rval; /* first, try the XDG_CONFIG_HOME environment variable */ rval = get_xdg_dir(retpath, "XDG_CONFIG_HOME", "mupen64plus/"); if (rval == 0) return retpath; /* then try the HOME environment variable */ rval = get_xdg_dir(retpath, "HOME", ".config/mupen64plus/"); if (rval == 0) return retpath; /* otherwise we are in trouble */ if (rval < 3) DebugMessage(M64MSG_ERROR, "Failed to get configuration directory; $HOME is undefined or invalid."); return NULL; } const char * osal_get_user_datapath(void) { static char retpath[PATH_MAX]; int rval; /* first, try the XDG_DATA_HOME environment variable */ rval = get_xdg_dir(retpath, "XDG_DATA_HOME", "mupen64plus/"); if (rval == 0) return retpath; /* then try the HOME environment variable */ rval = get_xdg_dir(retpath, "HOME", ".local/share/mupen64plus/"); if (rval == 0) return retpath; /* otherwise we are in trouble */ if (rval < 3) DebugMessage(M64MSG_ERROR, "Failed to get data directory; $HOME is undefined or invalid."); return NULL; } const char * osal_get_user_cachepath(void) { static char retpath[PATH_MAX]; int rval; /* first, try the XDG_CACHE_HOME environment variable */ rval = get_xdg_dir(retpath, "XDG_CACHE_HOME", "mupen64plus/"); if (rval == 0) return retpath; /* then try the HOME environment variable */ rval = get_xdg_dir(retpath, "HOME", ".cache/mupen64plus/"); if (rval == 0) return retpath; /* otherwise we are in trouble */ if (rval < 3) DebugMessage(M64MSG_ERROR, "Failed to get cache directory; $HOME is undefined or invalid."); return NULL; } FILE * osal_file_open(const char *filename, const char *mode) { return fopen (filename, mode); } gzFile osal_gzopen(const char *filename, const char *mode) { return gzopen(filename, mode); } mupen64plus-core-src-2.6.0/src/osal/files_win32.c000066400000000000000000000170341464506436200214700ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/files_win32.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* This file contains the definitions for the unix-specific file handling * functions */ #include #include #include #include #include #include #include #include "api/callbacks.h" #include "api/m64p_types.h" #include "files.h" /* definitions for system directories to search when looking for shared data files */ #if defined(SHAREDIR) #define XSTR(S) STR(S) /* this wacky preprocessor thing is necessary to generate a quote-enclosed */ #define STR(S) #S /* copy of the SHAREDIR macro, which is defined by the makefile via gcc -DSHAREDIR="..." */ static const int datasearchdirs = 2; static const char *datasearchpath[2] = { XSTR(SHAREDIR), ".\\" }; #undef STR #undef XSTR #else static const int datasearchdirs = 1; static const char *datasearchpath[1] = { ".\\" }; #endif /* local functions */ static int search_dir_file(char *destpath, const char *path, const char *filename) { struct _stat fileinfo; /* sanity check to start */ if (destpath == NULL || path == NULL || filename == NULL) return 1; /* build the full filepath */ strcpy(destpath, path); /* if the path is empty, don't add \ between it and the file name */ if (destpath[0] != '\0' && destpath[strlen(destpath)-1] != '\\') strcat(destpath, "\\"); strcat(destpath, filename); wchar_t w_destpath[PATH_MAX]; MultiByteToWideChar(CP_UTF8, 0, destpath, -1, w_destpath, PATH_MAX); /* test for a valid file */ if (_wstat(w_destpath, &fileinfo) != 0) return 2; if ((fileinfo.st_mode & _S_IFREG) == 0) return 3; /* success - file exists and is a regular file */ return 0; } /* global functions */ int osal_mkdirp(const char *dirpath, int mode) { wchar_t mypath[MAX_PATH]; wchar_t *currpath, *lastchar; struct _stat fileinfo; // Create a copy of the path, so we can modify it if (MultiByteToWideChar(CP_UTF8, 0, dirpath, -1, mypath, MAX_PATH) == 0) return 1; currpath = &mypath[0]; // if the directory path ends with a separator, remove it lastchar = mypath + wcslen(mypath) - 1; if (wcschr(WIDE_OSAL_DIR_SEPARATORS, *lastchar) != NULL) *lastchar = 0; // Terminate quickly if the path already exists if (_wstat(mypath, &fileinfo) == 0 && (fileinfo.st_mode & _S_IFDIR)) return 0; while ((currpath = wcspbrk(currpath + 1, WIDE_OSAL_DIR_SEPARATORS)) != NULL) { // if slash is right after colon, then we are looking at drive name prefix (C:\) and should // just skip it, because _stat and _mkdir will both fail for "C:" if (currpath > mypath && currpath[-1] == L':') continue; *currpath = L'\0'; if (_wstat(mypath, &fileinfo) != 0) { if (_wmkdir(mypath) != 0) return 1; } else if (!(fileinfo.st_mode & _S_IFDIR)) { return 1; } *currpath = WIDE_OSAL_DIR_SEPARATORS[0]; } // Create full path if (_wmkdir(mypath) != 0) return 1; return 0; } const char * osal_get_shared_filepath(const char *filename, const char *firstsearch, const char *secondsearch) { static char retpath[_MAX_PATH]; int i; /* if caller gave us any directories to search, then look there first */ if (firstsearch != NULL && search_dir_file(retpath, firstsearch, filename) == 0) return retpath; if (secondsearch != NULL && search_dir_file(retpath, secondsearch, filename) == 0) return retpath; /* otherwise check our standard paths */ if (search_dir_file(retpath, osal_get_user_configpath(), filename) == 0) return retpath; for (i = 0; i < datasearchdirs; i++) { if (search_dir_file(retpath, datasearchpath[i], filename) == 0) return retpath; } /* we couldn't find the file */ return NULL; } const char * osal_get_user_configpath(void) { static wchar_t chHomePath[MAX_PATH]; static char outString[MAX_PATH]; LPITEMIDLIST pidl; LPMALLOC pMalloc; struct _stat fileinfo; // Get item ID list for the path of user's personal directory SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl); // get the path in a char string SHGetPathFromIDListW(pidl, chHomePath); // do a bunch of crap just to free some memory SHGetMalloc(&pMalloc); pMalloc->lpVtbl->Free(pMalloc, pidl); pMalloc->lpVtbl->Release(pMalloc); // tack on 'mupen64plus' if (chHomePath[wcslen(chHomePath)-1] != L'\\') wcscat(chHomePath, L"\\"); wcscat(chHomePath, L"Mupen64Plus"); // if this directory doesn't exist, then make it if (_wstat(chHomePath, &fileinfo) == 0) { wcscat(chHomePath, L"\\"); WideCharToMultiByte(CP_UTF8, 0, chHomePath, -1, outString, MAX_PATH, NULL, NULL); return outString; } else { WideCharToMultiByte(CP_UTF8, 0, chHomePath, -1, outString, MAX_PATH, NULL, NULL); osal_mkdirp(outString, 0); if (_wstat(chHomePath, &fileinfo) == 0) { strcat(outString, "\\"); return outString; } } /* otherwise we are in trouble */ DebugMessage(M64MSG_ERROR, "Failed to open configuration directory '%ls'.", chHomePath); return NULL; } const char * osal_get_user_datapath(void) { // in windows, these are all the same return osal_get_user_configpath(); } const char * osal_get_user_cachepath(void) { // in windows, these are all the same return osal_get_user_configpath(); } FILE * osal_file_open ( const char * filename, const char * mode ) { wchar_t wstr_filename[PATH_MAX]; wchar_t wstr_mode[64]; MultiByteToWideChar(CP_UTF8, 0, filename, -1, wstr_filename, PATH_MAX); MultiByteToWideChar(CP_UTF8, 0, mode, -1, wstr_mode, 64); return _wfopen (wstr_filename, wstr_mode); } gzFile osal_gzopen(const char *filename, const char *mode) { wchar_t wstr_filename[PATH_MAX]; MultiByteToWideChar(CP_UTF8, 0, filename, -1, wstr_filename, PATH_MAX); return gzopen_w(wstr_filename, mode); } mupen64plus-core-src-2.6.0/src/osal/preproc.h000066400000000000000000000067701464506436200210300ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus-core - osal/preproc.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* this header file is for system-dependent #defines, #includes, and typedefs */ #if !defined (OSAL_PREPROC_H) #define OSAL_PREPROC_H #if _MSC_VER /* macros */ #define OSAL_BREAKPOINT_INTERRUPT __debugbreak(); #define ALIGN(BYTES,DATA) __declspec(align(BYTES)) DATA #define osal_inline __inline #define OSAL_WARNING_PUSH __pragma(warning(push)) #define OSAL_WARNING_POP __pragma(warning(pop)) #define OSAL_NO_WARNING_FPTR_VOIDP_CAST __pragma(warning(disable:4055 4152)) /* string functions */ #define osal_insensitive_strcmp(x, y) _stricmp(x, y) #define strdup _strdup /* for isnan() */ #include #if defined(_M_X64) || (_M_IX86_FP > 0) #include #define OSAL_SSE #endif #else /* Not WIN32 */ /* for strcasecmp */ #include /* macros */ #define OSAL_BREAKPOINT_INTERRUPT __asm__(" int $3; "); #define ALIGN(BYTES,DATA) DATA __attribute__((aligned(BYTES))) #define osal_inline inline #define OSAL_WARNING_PUSH _Pragma("GCC diagnostic push") #define OSAL_WARNING_POP _Pragma("GCC diagnostic pop") #define OSAL_NO_WARNING_FPTR_VOIDP_CAST _Pragma("GCC diagnostic ignored \"-Wpedantic\"") /* string functions */ #define osal_insensitive_strcmp(x, y) strcasecmp(x, y) #ifdef __SSE__ #include #define OSAL_SSE #endif #endif /* sign-extension macros */ #define SE8(a) ((int64_t) ((int8_t) (a))) #define SE16(a) ((int64_t) ((int16_t) (a))) #define SE32(a) ((int64_t) ((int32_t) (a))) #if !defined(M64P_BIG_ENDIAN) #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) #define tohl(x) __builtin_bswap32((x)) #else #define tohl(x) \ ( \ (((x) & 0x000000FF) << 24) | \ (((x) & 0x0000FF00) << 8) | \ (((x) & 0x00FF0000) >> 8) | \ (((x) & 0xFF000000) >> 24) \ ) #endif #define S8 3 #define S16 2 #define Sh16 1 #else #define tohl(x) (x) #define S8 0 #define S16 0 #define Sh16 0 #endif #define fromhl(x) tohl((x)) #endif /* OSAL_PREPROC_H */ mupen64plus-core-src-2.6.0/src/osd/000077500000000000000000000000001464506436200170225ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/osd/oglft_c.cpp000066400000000000000000000114251464506436200211460ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - oglft_c.cpp * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2018 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "oglft_c.h" #include extern "C" bool OGLFT_Init_FT(void) { try { return OGLFT::Init_FT(); } catch(...) { /* swallow error */ } return false; } extern "C" bool OGLFT_Uninit_FT(void) { try { return OGLFT::Uninit_FT(); } catch(...) { /* swallow error */ } return false; } extern "C" bool OGLFT_Face_isValid(const struct OGLFT_Face* face) { try { return reinterpret_cast(face)->isValid(); } catch(...) { /* swallow error */ } return false; } extern "C" void OGLFT_Face_setForegroundColor(struct OGLFT_Face* face, float r, float g, float b, float a) { try { reinterpret_cast(face)->setForegroundColor(r, g, b, a); } catch(...) { /* swallow error */ } } extern "C" void OGLFT_Face_setBackgroundColor(struct OGLFT_Face* face, float r, float g, float b, float a) { try { reinterpret_cast(face)->setBackgroundColor(r, g, b, a); } catch(...) { /* swallow error */ } } extern "C" void OGLFT_Face_setHorizontalJustification(struct OGLFT_Face* face, enum OGLFT_Face_HorizontalJustification justification) { try { reinterpret_cast(face)->setHorizontalJustification(static_cast(justification)); } catch(...) { /* swallow error */ } } extern "C" void OGLFT_Face_setVerticalJustification(struct OGLFT_Face* face, enum OGLFT_Face_VerticalJustification justification) { try { reinterpret_cast(face)->setVerticalJustification(static_cast(justification)); } catch(...) { /* swallow error */ } } extern "C" double OGLFT_Face_height(const struct OGLFT_Face* face) { try { return reinterpret_cast(face)->height(); } catch(...) { /* swallow error */ } return 0.0; } extern "C" void OGLFT_Face_measure(struct OGLFT_Face* face, const char* s, float sizebox[4]) { try { OGLFT::BBox bbox = reinterpret_cast(face)->measure(s); sizebox[0] = bbox.x_min_; sizebox[1] = bbox.y_min_; sizebox[2] = bbox.x_max_; sizebox[3] = bbox.y_max_; } catch(...) { memset(sizebox, 0, 4*sizeof sizebox[0]); } } extern "C" void OGLFT_Face_measure_nominal(struct OGLFT_Face* face, const char* s, float sizebox[4]) { try { OGLFT::BBox bbox = reinterpret_cast(face)->measure_nominal(s); sizebox[0] = bbox.x_min_; sizebox[1] = bbox.y_min_; sizebox[2] = bbox.x_max_; sizebox[3] = bbox.y_max_; } catch(...) { memset(sizebox, 0, 4*sizeof sizebox[0]); } } extern "C" void OGLFT_Face_draw(struct OGLFT_Face* face, float x, float y, const char* s, float sizebox[4]) { try { reinterpret_cast(face)->draw(x, y, s, sizebox); } catch(...) { /* swallow error */ } } extern "C" struct OGLFT_Face* OGLFT_Monochrome_create(const char* filename, float point_size) { try { return reinterpret_cast(new OGLFT::Monochrome(filename, point_size)); } catch(...) { /* swallow error */ } return NULL; } extern "C" void OGLFT_Face_destroy(struct OGLFT_Face* face) { try { delete reinterpret_cast(face); } catch(...) { /* swallow error */ } } mupen64plus-core-src-2.6.0/src/osd/oglft_c.h000066400000000000000000000063351464506436200206170ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - oglft_c.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2018 Bobby Smiles * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Minimal C-API interface to OGLFT * We only expose what we use. */ #ifndef M64P_OSD_OGLFT_C_H #define M64P_OSD_OGLFT_C_H #ifndef __cplusplus #include #endif #ifdef __cplusplus extern "C" { #endif bool OGLFT_Init_FT(void); bool OGLFT_Uninit_FT(void); struct OGLFT_Face; enum OGLFT_Face_HorizontalJustification { OGLFT_FACE_HORIZONTAL_JUSTIFICATION_LEFT, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_ORIGIN, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_CENTER, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_RIGHT }; enum OGLFT_Face_VerticalJustification { OGLFT_FACE_VERTICAL_JUSTIFICATION_BOTTOM, OGLFT_FACE_VERTICAL_JUSTIFICATION_BASELINE, OGLFT_FACE_VERTICAL_JUSTIFICATION_MIDDLE, OGLFT_FACE_VERTICAL_JUSTIFICATION_TOP }; struct OGLFT_Face* OGLFT_Monochrome_create(const char* filename, float point_size); void OGLFT_Face_destroy(struct OGLFT_Face* face); bool OGLFT_Face_isValid(const struct OGLFT_Face* face); void OGLFT_Face_setForegroundColor(struct OGLFT_Face* face, float r, float g, float b, float a); void OGLFT_Face_setBackgroundColor(struct OGLFT_Face* face, float r, float g, float b, float a); void OGLFT_Face_setHorizontalJustification(struct OGLFT_Face* face, enum OGLFT_Face_HorizontalJustification justification); void OGLFT_Face_setVerticalJustification(struct OGLFT_Face* face, enum OGLFT_Face_VerticalJustification justification); double OGLFT_Face_height(const struct OGLFT_Face* face); void OGLFT_Face_measure(struct OGLFT_Face* face, const char* s, float sizebox[4]); void OGLFT_Face_measure_nominal(struct OGLFT_Face* face, const char* s, float sizebox[4]); void OGLFT_Face_draw(struct OGLFT_Face* face, float x, float y, const char* s, float sizebox[4]); #ifdef __cplusplus } #endif #endif mupen64plus-core-src-2.6.0/src/osd/osd.c000066400000000000000000000440511464506436200177570ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - osd.cpp * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Nmn Ebenblues * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "osd.h" #include "oglft_c.h" #include #include #include #include #include #include #include #define M64P_CORE_PROTOTYPES 1 #include "api/m64p_config.h" #include "api/m64p_vidext.h" #include "api/callbacks.h" #define FONT_FILENAME "font.ttf" typedef void (APIENTRYP PTRGLACTIVETEXTURE)(GLenum texture); static PTRGLACTIVETEXTURE pglActiveTexture = NULL; // static variables for OSD static int l_OsdInitialized = 0; static LIST_HEAD(l_messageQueue); static struct OGLFT_Face* l_font; static float l_fLineHeight = -1.0; static void animation_none(osd_message_t *); static void animation_fade(osd_message_t *); static void osd_remove_message(osd_message_t *msg); static osd_message_t * osd_message_valid(osd_message_t *testmsg); static float fCornerScroll[OSD_NUM_CORNERS]; static SDL_mutex *osd_list_lock; // animation handlers static void (*l_animations[OSD_NUM_ANIM_TYPES])(osd_message_t *) = { animation_none, // animation handler for OSD_NONE animation_fade // animation handler for OSD_FADE }; // private functions // draw message on screen static void draw_message(osd_message_t *msg, int width, int height) { float x = 0., y = 0.; if (!l_font || !OGLFT_Face_isValid(l_font)) return; // set color. alpha is hard coded to 1. animation can change this OGLFT_Face_setForegroundColor(l_font, msg->color[R], msg->color[G], msg->color[B], 1.f); OGLFT_Face_setBackgroundColor(l_font, 0.f, 0.f, 0.f, 0.f); // set justification based on corner switch(msg->corner) { case OSD_TOP_LEFT: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_TOP); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_LEFT); x = 0.; y = (float)height; break; case OSD_TOP_CENTER: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_TOP); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_CENTER); x = ((float)width)/2.0f; y = (float)height; break; case OSD_TOP_RIGHT: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_TOP); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_RIGHT); x = (float)width; y = (float)height; break; case OSD_MIDDLE_LEFT: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_MIDDLE); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_LEFT); x = 0.; y = ((float)height)/2.0f; break; case OSD_MIDDLE_CENTER: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_MIDDLE); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_CENTER); x = ((float)width)/2.0f; y = ((float)height)/2.0f; break; case OSD_MIDDLE_RIGHT: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_MIDDLE); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_RIGHT); x = (float)width; y = ((float)height)/2.0f; break; case OSD_BOTTOM_LEFT: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_BOTTOM); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_LEFT); x = 0.; y = 0.; break; case OSD_BOTTOM_CENTER: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_BOTTOM); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_CENTER); x = ((float)width)/2.0f; y = 0.; break; case OSD_BOTTOM_RIGHT: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_BOTTOM); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_RIGHT); x = (float)width; y = 0.; break; default: OGLFT_Face_setVerticalJustification(l_font, OGLFT_FACE_VERTICAL_JUSTIFICATION_BOTTOM); OGLFT_Face_setHorizontalJustification(l_font, OGLFT_FACE_HORIZONTAL_JUSTIFICATION_LEFT); x = 0.; y = 0.; break; } // apply animation for current message state (*l_animations[msg->animation[msg->state]])(msg); // xoffset moves message left x -= msg->xoffset; // yoffset moves message up y += msg->yoffset; // get the bounding box if invalid if (msg->sizebox[0] == 0 && msg->sizebox[2] == 0) // xmin and xmax { OGLFT_Face_measure_nominal(l_font, msg->text, msg->sizebox); } // draw the text line OGLFT_Face_draw(l_font, x, y, msg->text, msg->sizebox); } // null animation handler static void animation_none(osd_message_t *msg) { } // fade in/out animation handler static void animation_fade(osd_message_t *msg) { float alpha = 1.; float elapsed_frames; float total_frames = (float)msg->timeout[msg->state]; switch(msg->state) { case OSD_DISAPPEAR: elapsed_frames = (float)(total_frames - msg->frames); break; case OSD_APPEAR: default: elapsed_frames = (float)msg->frames; break; } if(total_frames != 0.) alpha = elapsed_frames / total_frames; OGLFT_Face_setForegroundColor(l_font, msg->color[R], msg->color[G], msg->color[B], alpha); } // sets message Y offset depending on where they are in the message queue static float get_message_offset(osd_message_t *msg, float fLinePos) { float offset = (float) (OGLFT_Face_height(l_font) * fLinePos); switch(msg->corner) { case OSD_TOP_LEFT: case OSD_TOP_CENTER: case OSD_TOP_RIGHT: return -offset; break; default: return offset; break; } } // public functions void osd_init(int width, int height) { const char *fontpath; int i; osd_list_lock = SDL_CreateMutex(); if (!osd_list_lock) { DebugMessage(M64MSG_ERROR, "Could not create osd list lock"); return; } if (!OGLFT_Init_FT()) { DebugMessage(M64MSG_ERROR, "Could not initialize freetype library."); return; } fontpath = ConfigGetSharedDataFilepath(FONT_FILENAME); l_font = OGLFT_Monochrome_create(fontpath, (float) height / 35.f); // make font size proportional to screen height if (!l_font || !OGLFT_Face_isValid(l_font)) { DebugMessage(M64MSG_ERROR, "Could not construct face from %s", fontpath); return; } #if SDL_VERSION_ATLEAST(2,0,0) int gl_context; VidExt_GL_GetAttribute(M64P_GL_CONTEXT_PROFILE_MASK, &gl_context); if (gl_context == M64P_GL_CONTEXT_PROFILE_CORE) { DebugMessage(M64MSG_WARNING, "OSD not compatible with OpenGL core context. OSD deactivated."); return; } #endif // clear statics for (i = 0; i < OSD_NUM_CORNERS; i++) fCornerScroll[i] = 0.0; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #if defined(GL_RASTER_POSITION_UNCLIPPED_IBM) glEnable(GL_RASTER_POSITION_UNCLIPPED_IBM); #endif pglActiveTexture = (PTRGLACTIVETEXTURE) VidExt_GL_GetProcAddress("glActiveTexture"); if (pglActiveTexture == NULL) { DebugMessage(M64MSG_WARNING, "OpenGL function glActiveTexture() not supported. OSD deactivated."); return; } // set initialized flag l_OsdInitialized = 1; } void osd_exit(void) { osd_message_t *msg, *safe; // delete font renderer if (l_font) { OGLFT_Face_destroy(l_font); l_font = NULL; } // delete message queue SDL_LockMutex(osd_list_lock); list_for_each_entry_safe_t(msg, safe, &l_messageQueue, osd_message_t, list) { osd_remove_message(msg); if (!msg->user_managed) free(msg); } SDL_UnlockMutex(osd_list_lock); // shut down the Freetype library OGLFT_Uninit_FT(); SDL_DestroyMutex(osd_list_lock); // reset initialized flag l_OsdInitialized = 0; } // renders the current osd message queue to the screen void osd_render() { osd_message_t *msg, *safe; int i; // if we're not initialized or list is empty, then just skip it all if (!l_OsdInitialized || list_empty(&l_messageQueue)) return; // get the viewport dimensions GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); // save all the attributes glPushAttrib(GL_ALL_ATTRIB_BITS); bool bFragmentProg = glIsEnabled(GL_FRAGMENT_PROGRAM_ARB) != 0; bool bColorArray = glIsEnabled(GL_COLOR_ARRAY) != 0; bool bTexCoordArray = glIsEnabled(GL_TEXTURE_COORD_ARRAY) != 0; bool bSecColorArray = glIsEnabled(GL_SECONDARY_COLOR_ARRAY) != 0; // deactivate all the texturing units GLint iActiveTex; bool bTexture2D[8]; glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &iActiveTex); for (i = 0; i < 8; i++) { pglActiveTexture(GL_TEXTURE0_ARB + i); bTexture2D[i] = glIsEnabled(GL_TEXTURE_2D) != 0; glDisable(GL_TEXTURE_2D); } // save the matrices and set up new ones glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(viewport[0],viewport[2],viewport[1],viewport[3], -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // setup for drawing text glDisable(GL_FOG); glDisable(GL_LIGHTING); glDisable(GL_ALPHA_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_SCISSOR_TEST); glDisable(GL_STENCIL_TEST); glDisable(GL_FRAGMENT_PROGRAM_ARB); glDisable(GL_COLOR_MATERIAL); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_SECONDARY_COLOR_ARRAY); glShadeModel(GL_FLAT); // get line height if invalid if (l_fLineHeight < 0.0) { float bbox[4]; OGLFT_Face_measure(l_font, "01abjZpqRGB", bbox); l_fLineHeight = (bbox[3] - bbox[1]) / 30.f; // y_max - y_min } // keeps track of next message position for each corner float fCornerPos[OSD_NUM_CORNERS]; for (i = 0; i < OSD_NUM_CORNERS; i++) fCornerPos[i] = 0.5f * l_fLineHeight; SDL_LockMutex(osd_list_lock); list_for_each_entry_safe_t(msg, safe, &l_messageQueue, osd_message_t, list) { // update message state if(msg->timeout[msg->state] != OSD_INFINITE_TIMEOUT && ++msg->frames >= msg->timeout[msg->state]) { // if message is in last state, mark it for deletion and continue to the next message if(msg->state >= OSD_NUM_STATES - 1) { if (msg->user_managed) { osd_remove_message(msg); } else { osd_remove_message(msg); free(msg); } continue; } // go to next state and reset frame count msg->state++; msg->frames = 0; } // offset y depending on how many other messages are in the same corner float fStartOffset; if (msg->corner >= OSD_MIDDLE_LEFT && msg->corner <= OSD_MIDDLE_RIGHT) // don't scroll the middle messages fStartOffset = fCornerPos[msg->corner]; else fStartOffset = fCornerPos[msg->corner] + (fCornerScroll[msg->corner] * l_fLineHeight); msg->yoffset += get_message_offset(msg, fStartOffset); draw_message(msg, viewport[2], viewport[3]); msg->yoffset -= get_message_offset(msg, fStartOffset); fCornerPos[msg->corner] += l_fLineHeight; } SDL_UnlockMutex(osd_list_lock); // do the scrolling for (i = 0; i < OSD_NUM_CORNERS; i++) { fCornerScroll[i] += 0.1f; if (fCornerScroll[i] >= 0.0) fCornerScroll[i] = 0.0; } // restore the matrices glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); // restore the attributes for (i = 0; i < 8; i++) { pglActiveTexture(GL_TEXTURE0_ARB + i); if (bTexture2D[i]) glEnable(GL_TEXTURE_2D); else glDisable(GL_TEXTURE_2D); } pglActiveTexture(iActiveTex); glPopAttrib(); if (bFragmentProg) glEnable(GL_FRAGMENT_PROGRAM_ARB); if (bColorArray) glEnableClientState(GL_COLOR_ARRAY); if (bTexCoordArray) glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (bSecColorArray) glEnableClientState(GL_SECONDARY_COLOR_ARRAY); glFinish(); } // creates a new osd_message_t, adds it to the message queue and returns it in case // the user wants to modify its parameters. Note, if the message can't be created, // NULL is returned. osd_message_t * osd_new_message(enum osd_corner eCorner, const char *fmt, ...) { va_list ap; char buf[1024]; if (!l_OsdInitialized) return NULL; osd_message_t *msg = (osd_message_t *)malloc(sizeof(*msg)); if (!msg) return NULL; va_start(ap, fmt); vsnprintf(buf, 1024, fmt, ap); buf[1023] = 0; va_end(ap); // set default values memset(msg, 0, sizeof(osd_message_t)); msg->text = strdup(buf); msg->user_managed = 0; // default to white msg->color[R] = 1.; msg->color[G] = 1.; msg->color[B] = 1.; msg->sizebox[0] = 0.0; // set a null bounding box msg->sizebox[1] = 0.0; msg->sizebox[2] = 0.0; msg->sizebox[3] = 0.0; msg->corner = eCorner; msg->state = OSD_APPEAR; fCornerScroll[eCorner] -= 1.0; // start this one before the beginning of the list and scroll it in msg->animation[OSD_APPEAR] = OSD_FADE; msg->animation[OSD_DISPLAY] = OSD_NONE; msg->animation[OSD_DISAPPEAR] = OSD_FADE; if (eCorner >= OSD_MIDDLE_LEFT && eCorner <= OSD_MIDDLE_RIGHT) { msg->timeout[OSD_APPEAR] = 20; msg->timeout[OSD_DISPLAY] = 60; msg->timeout[OSD_DISAPPEAR] = 20; } else { msg->timeout[OSD_APPEAR] = 20; msg->timeout[OSD_DISPLAY] = 180; msg->timeout[OSD_DISAPPEAR] = 40; } // add to message queue SDL_LockMutex(osd_list_lock); list_add(&msg->list, &l_messageQueue); SDL_UnlockMutex(osd_list_lock); return msg; } // update message string void osd_update_message(osd_message_t *msg, const char *fmt, ...) { va_list ap; char buf[1024]; if (!l_OsdInitialized || !msg) return; va_start(ap, fmt); vsnprintf(buf, 1024, fmt, ap); buf[1023] = 0; va_end(ap); free(msg->text); msg->text = strdup(buf); // reset bounding box msg->sizebox[0] = 0.0; msg->sizebox[1] = 0.0; msg->sizebox[2] = 0.0; msg->sizebox[3] = 0.0; // reset display time counter if (msg->state >= OSD_DISPLAY) { msg->state = OSD_DISPLAY; msg->frames = 0; } SDL_LockMutex(osd_list_lock); if (!osd_message_valid(msg)) list_add(&msg->list, &l_messageQueue); SDL_UnlockMutex(osd_list_lock); } // remove message from message queue static void osd_remove_message(osd_message_t *msg) { if (!l_OsdInitialized || !msg) return; free(msg->text); msg->text = NULL; list_del(&msg->list); } // remove message from message queue and free it void osd_delete_message(osd_message_t *msg) { if (!l_OsdInitialized || !msg) return; SDL_LockMutex(osd_list_lock); osd_remove_message(msg); free(msg); SDL_UnlockMutex(osd_list_lock); } // set message so it doesn't automatically expire in a certain number of frames. void osd_message_set_static(osd_message_t *msg) { if (!l_OsdInitialized || !msg) return; msg->timeout[OSD_DISPLAY] = OSD_INFINITE_TIMEOUT; msg->state = OSD_DISPLAY; msg->frames = 0; } // set message so it doesn't automatically get freed when finished transition. void osd_message_set_user_managed(osd_message_t *msg) { if (!l_OsdInitialized || !msg) return; msg->user_managed = 1; } // return message pointer if valid (in the OSD list), otherwise return NULL static osd_message_t * osd_message_valid(osd_message_t *testmsg) { osd_message_t *msg; if (!l_OsdInitialized || !testmsg) return NULL; list_for_each_entry_t(msg, &l_messageQueue, osd_message_t, list) { if (msg == testmsg) return testmsg; } return NULL; } mupen64plus-core-src-2.6.0/src/osd/osd.h000066400000000000000000000113601464506436200177610ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - osd.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Nmn, Ebenblues * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef __OSD_H__ #define __OSD_H__ #include "main/list.h" #include "osal/preproc.h" #if defined(__GNUC__) #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) #else #define ATTR_FMT(fmtpos, attrpos) #endif /****************************************************************** osd_corner 0 1 2 | \ __|__/ | Offset always effects the same: | | | +X = Leftward +Y = Upward 3-| 4 |-5 | With no offset, the text will touch the border. |_____| | / | \ | 6 7 8 | *******************************************************************/ enum osd_corner { OSD_TOP_LEFT, // 0 in the picture above OSD_TOP_CENTER, // 1 in the picture above OSD_TOP_RIGHT, // 2 in the picture above OSD_MIDDLE_LEFT, // 3 in the picture above OSD_MIDDLE_CENTER, // 4 in the picture above OSD_MIDDLE_RIGHT, // 5 in the picture above OSD_BOTTOM_LEFT, // 6 in the picture above OSD_BOTTOM_CENTER, // 7 in the picture above OSD_BOTTOM_RIGHT, // 8 in the picture above OSD_NUM_CORNERS }; enum osd_message_state { OSD_APPEAR, // OSD message is appearing on the screen OSD_DISPLAY, // OSD message is being displayed on the screen OSD_DISAPPEAR, // OSD message is disappearing from the screen OSD_NUM_STATES }; enum osd_animation_type { OSD_NONE, OSD_FADE, OSD_NUM_ANIM_TYPES }; typedef struct { char *text; // Text that this object will have when displayed enum osd_corner corner; // One of the 9 corners float xoffset; // Relative X position float yoffset; // Relative Y position float color[3]; // Red, Green, Blue values float sizebox[4]; // bounding box (xmin, ymin, xmax, ymax) int state; // display state of current message enum osd_animation_type animation[OSD_NUM_STATES]; // animations for each display state unsigned int timeout[OSD_NUM_STATES]; // timeouts for each display state #define OSD_INFINITE_TIMEOUT 0xffffffff unsigned int frames; // number of frames in this state int user_managed; // structure managed by caller and not to be freed by us struct list_head list; } osd_message_t; enum { R, G, B }; // for referencing color array #ifdef M64P_OSD void osd_init(int width, int height); void osd_exit(void); void osd_render(void); osd_message_t * osd_new_message(enum osd_corner, const char *, ...) ATTR_FMT(2, 3); void osd_update_message(osd_message_t *, const char *, ...) ATTR_FMT(2, 3); void osd_delete_message(osd_message_t *); void osd_message_set_static(osd_message_t *); void osd_message_set_user_managed(osd_message_t *); #else static osal_inline void osd_init(int width, int height) { } static osal_inline void osd_exit(void) { } static osal_inline void osd_render(void) { } static osal_inline osd_message_t * osd_new_message(enum osd_corner eCorner, const char *fmt, ...) { return NULL; } static osal_inline void osd_update_message(osd_message_t *msg, const char *fmt, ...) { } static osal_inline void osd_delete_message(osd_message_t *msg) { } static osal_inline void osd_message_set_static(osd_message_t *msg) { } static osal_inline void osd_message_set_user_managed(osd_message_t *msg) { } #endif #endif // __OSD_H__ mupen64plus-core-src-2.6.0/src/plugin/000077500000000000000000000000001464506436200175335ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/src/plugin/dummy_audio.c000066400000000000000000000055731464506436200222250ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_audio.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008-2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "api/m64p_types.h" #include "dummy_audio.h" #include "plugin.h" m64p_error dummyaudio_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { if (PluginType != NULL) *PluginType = M64PLUGIN_AUDIO; if (PluginVersion != NULL) *PluginVersion = 0x00010000; if (APIVersion != NULL) *APIVersion = AUDIO_API_VERSION; if (PluginNamePtr != NULL) *PluginNamePtr = "Mupen64Plus-NoAudio"; if (Capabilities != NULL) *Capabilities = 0; return M64ERR_SUCCESS; } void dummyaudio_AiDacrateChanged(int SystemType) { return; } void dummyaudio_AiLenChanged(void) { return; } int dummyaudio_InitiateAudio(AUDIO_INFO Audio_Info) { return 1; } int dummyaudio_RomOpen(void) { return 1; } void dummyaudio_RomClosed(void) { return; } void dummyaudio_ProcessAList(void) { return; } void dummyaudio_SetSpeedFactor(int percent) { return; } void dummyaudio_VolumeUp(void) { return; } void dummyaudio_VolumeDown(void) { return; } int dummyaudio_VolumeGetLevel(void) { return 0; } void dummyaudio_VolumeSetLevel(int level) { return; } void dummyaudio_VolumeMute(void) { return; } const char *dummyaudio_VolumeGetString(void) { return "disabled"; } mupen64plus-core-src-2.6.0/src/plugin/dummy_audio.h000066400000000000000000000046731464506436200222320ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_audio.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008-2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(DUMMY_AUDIO_H) #define DUMMY_AUDIO_H #include "api/m64p_plugin.h" #include "api/m64p_types.h" extern m64p_error dummyaudio_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities); extern void dummyaudio_AiDacrateChanged(int SystemType); extern void dummyaudio_AiLenChanged(void); extern int dummyaudio_InitiateAudio(AUDIO_INFO Audio_Info); extern void dummyaudio_ProcessAList(void); extern int dummyaudio_RomOpen(void); extern void dummyaudio_RomClosed(void); extern void dummyaudio_SetSpeedFactor(int percent); extern void dummyaudio_VolumeUp(void); extern void dummyaudio_VolumeDown(void); extern int dummyaudio_VolumeGetLevel(void); extern void dummyaudio_VolumeSetLevel(int level); extern void dummyaudio_VolumeMute(void); extern const char * dummyaudio_VolumeGetString(void); #endif /* DUMMY_AUDIO_H */ mupen64plus-core-src-2.6.0/src/plugin/dummy_input.c000066400000000000000000000054601464506436200222560ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_input.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Scott Gorman (okaygo) * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "api/m64p_types.h" #include "dummy_input.h" #include "plugin.h" m64p_error dummyinput_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { if (PluginType != NULL) *PluginType = M64PLUGIN_INPUT; if (PluginVersion != NULL) *PluginVersion = 0x00010000; if (APIVersion != NULL) *APIVersion = INPUT_API_VERSION; if (PluginNamePtr != NULL) *PluginNamePtr = "Mupen64Plus-NoInput"; if (Capabilities != NULL) *Capabilities = 0; return M64ERR_SUCCESS; } void dummyinput_InitiateControllers (CONTROL_INFO ControlInfo) { ControlInfo.Controls[0].Present = 1; } void dummyinput_GetKeys(int Control, BUTTONS * Keys ) { Keys->Value = 0x0000; } void dummyinput_ControllerCommand(int Control, unsigned char *Command) { } void dummyinput_ReadController(int Control, unsigned char *Command) { } int dummyinput_RomOpen(void) { return 1; } void dummyinput_RomClosed(void) { } void dummyinput_SDL_KeyDown(int keymod, int keysym) { } void dummyinput_SDL_KeyUp(int keymod, int keysym) { } void dummyinput_RenderCallback(void) { } mupen64plus-core-src-2.6.0/src/plugin/dummy_input.h000066400000000000000000000047641464506436200222710ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_input.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(DUMMY_INPUT_H) #define DUMMY_INPUT_H #include "api/m64p_plugin.h" #include "api/m64p_types.h" extern m64p_error dummyinput_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities); extern void dummyinput_InitiateControllers (CONTROL_INFO ControlInfo); extern void dummyinput_GetKeys(int Control, BUTTONS * Keys ); extern void dummyinput_ControllerCommand(int Control, unsigned char *Command); extern void dummyinput_GetKeys(int Control, BUTTONS * Keys); extern void dummyinput_InitiateControllers(CONTROL_INFO ControlInfo); extern void dummyinput_ReadController(int Control, unsigned char *Command); extern int dummyinput_RomOpen(void); extern void dummyinput_RomClosed(void); extern void dummyinput_SDL_KeyDown(int keymod, int keysym); extern void dummyinput_SDL_KeyUp(int keymod, int keysym); extern void dummyinput_RenderCallback(void); #endif /* DUMMY_INPUT_H */ mupen64plus-core-src-2.6.0/src/plugin/dummy_rsp.c000066400000000000000000000045211464506436200217200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_rsp.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "api/m64p_types.h" #include "dummy_rsp.h" #include "plugin.h" m64p_error dummyrsp_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { if (PluginType != NULL) *PluginType = M64PLUGIN_RSP; if (PluginVersion != NULL) *PluginVersion = 0x00010000; if (APIVersion != NULL) *APIVersion = RSP_API_VERSION; if (PluginNamePtr != NULL) *PluginNamePtr = "Mupen64Plus-NoRSP"; if (Capabilities != NULL) *Capabilities = 0; return M64ERR_SUCCESS; } unsigned int dummyrsp_DoRspCycles(unsigned int Cycles) { return Cycles; } void dummyrsp_InitiateRSP(RSP_INFO Rsp_Info, unsigned int * CycleCount) { } void dummyrsp_RomClosed(void) { } mupen64plus-core-src-2.6.0/src/plugin/dummy_rsp.h000066400000000000000000000040121464506436200217200ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_rsp.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard42 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(DUMMY_RSP_H) #define DUMMY_RSP_H #include "api/m64p_plugin.h" #include "api/m64p_types.h" extern m64p_error dummyrsp_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities); extern unsigned int dummyrsp_DoRspCycles(unsigned int Cycles); extern void dummyrsp_InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount); extern void dummyrsp_RomClosed(void); #endif /* DUMMY_RSP_H */ mupen64plus-core-src-2.6.0/src/plugin/dummy_video.c000066400000000000000000000061251464506436200222240ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_video.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 John Chadwick (NMN) * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include "api/m64p_types.h" #include "dummy_video.h" #include "plugin.h" m64p_error dummyvideo_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) { if (PluginType != NULL) *PluginType = M64PLUGIN_GFX; if (PluginVersion != NULL) *PluginVersion = 0x00010000; if (APIVersion != NULL) *APIVersion = GFX_API_VERSION; if (PluginNamePtr != NULL) *PluginNamePtr = "Mupen64Plus-NoVideo"; if (Capabilities != NULL) *Capabilities = 0; return M64ERR_SUCCESS; } void dummyvideo_ChangeWindow (void) { } int dummyvideo_InitiateGFX (GFX_INFO Gfx_Info) { return 1; } void dummyvideo_MoveScreen (int xpos, int ypos) { } void dummyvideo_ProcessDList(void) { } void dummyvideo_ProcessRDPList(void) { } void dummyvideo_RomClosed (void) { } int dummyvideo_RomOpen (void) { return 1; } void dummyvideo_ShowCFB (void) { } void dummyvideo_UpdateScreen (void) { } void dummyvideo_ViStatusChanged (void) { } void dummyvideo_ViWidthChanged (void) { } void dummyvideo_ReadScreen2 (void *dest, int *width, int *height, int front) { } void dummyvideo_SetRenderingCallback(void (*callback)(int)) { } void dummyvideo_FBRead(unsigned int addr) { } void dummyvideo_FBWrite(unsigned int addr, unsigned int size) { } void dummyvideo_FBGetFrameBufferInfo(void *p) { } void dummyvideo_ResizeVideoOutput(int width, int height) { } mupen64plus-core-src-2.6.0/src/plugin/dummy_video.h000066400000000000000000000053221464506436200222270ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - dummy_video.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if !defined(DUMMY_VIDEO_H) #define DUMMY_VIDEO_H #include "api/m64p_plugin.h" #include "api/m64p_types.h" extern m64p_error dummyvideo_PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities); extern void dummyvideo_ChangeWindow(void); extern int dummyvideo_InitiateGFX(GFX_INFO Gfx_Info); extern void dummyvideo_MoveScreen(int xpos, int ypos); extern void dummyvideo_ProcessDList(void); extern void dummyvideo_ProcessRDPList(void); extern void dummyvideo_RomClosed(void); extern int dummyvideo_RomOpen(void); extern void dummyvideo_ShowCFB(void); extern void dummyvideo_UpdateScreen(void); extern void dummyvideo_ViStatusChanged(void); extern void dummyvideo_ViWidthChanged(void); extern void dummyvideo_ReadScreen2(void *dest, int *width, int *height, int front); extern void dummyvideo_SetRenderingCallback(void (*callback)(int)); extern void dummyvideo_ResizeVideoOutput(int width, int height); extern void dummyvideo_FBRead(unsigned int addr); extern void dummyvideo_FBWrite(unsigned int addr, unsigned int size); extern void dummyvideo_FBGetFrameBufferInfo(void *p); #endif /* DUMMY_VIDEO_H */ mupen64plus-core-src-2.6.0/src/plugin/plugin.c000066400000000000000000000557611464506436200212130ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - plugin.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "api/callbacks.h" #include "api/m64p_common.h" #include "api/m64p_plugin.h" #include "api/m64p_types.h" #include "device/memory/memory.h" #include "device/rcp/ai/ai_controller.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/rdp/rdp_core.h" #include "device/rcp/rsp/rsp_core.h" #include "device/rcp/vi/vi_controller.h" #include "dummy_audio.h" #include "dummy_input.h" #include "dummy_rsp.h" #include "dummy_video.h" #include "main/main.h" #include "main/rom.h" #include "main/version.h" #include "osal/dynamiclib.h" #include "plugin.h" CONTROL Controls[4]; /* global function pointers - initialized on core startup */ gfx_plugin_functions gfx; audio_plugin_functions audio; input_plugin_functions input; rsp_plugin_functions rsp; /* local data structures and functions */ static const gfx_plugin_functions dummy_gfx = { dummyvideo_PluginGetVersion, dummyvideo_ChangeWindow, dummyvideo_InitiateGFX, dummyvideo_MoveScreen, dummyvideo_ProcessDList, dummyvideo_ProcessRDPList, dummyvideo_RomClosed, dummyvideo_RomOpen, dummyvideo_ShowCFB, dummyvideo_UpdateScreen, dummyvideo_ViStatusChanged, dummyvideo_ViWidthChanged, dummyvideo_ReadScreen2, dummyvideo_SetRenderingCallback, dummyvideo_ResizeVideoOutput, dummyvideo_FBRead, dummyvideo_FBWrite, dummyvideo_FBGetFrameBufferInfo }; static const audio_plugin_functions dummy_audio = { dummyaudio_PluginGetVersion, dummyaudio_AiDacrateChanged, dummyaudio_AiLenChanged, dummyaudio_InitiateAudio, dummyaudio_ProcessAList, dummyaudio_RomClosed, dummyaudio_RomOpen, dummyaudio_SetSpeedFactor, dummyaudio_VolumeUp, dummyaudio_VolumeDown, dummyaudio_VolumeGetLevel, dummyaudio_VolumeSetLevel, dummyaudio_VolumeMute, dummyaudio_VolumeGetString }; static const input_plugin_functions dummy_input = { dummyinput_PluginGetVersion, dummyinput_ControllerCommand, dummyinput_GetKeys, dummyinput_InitiateControllers, dummyinput_ReadController, dummyinput_RomClosed, dummyinput_RomOpen, dummyinput_SDL_KeyDown, dummyinput_SDL_KeyUp, dummyinput_RenderCallback }; static const rsp_plugin_functions dummy_rsp = { dummyrsp_PluginGetVersion, dummyrsp_DoRspCycles, dummyrsp_InitiateRSP, dummyrsp_RomClosed }; static GFX_INFO gfx_info; static AUDIO_INFO audio_info; static CONTROL_INFO control_info; static RSP_INFO rsp_info; static int l_RspAttached = 0; static int l_InputAttached = 0; static int l_AudioAttached = 0; static int l_GfxAttached = 0; static unsigned int dummy; /* local functions */ static void EmptyFunc(void) { } // Handy macro to avoid code bloat when loading symbols #define GET_FUNC(type, field, name) \ ((field = (type)osal_dynlib_getproc(plugin_handle, name)) != NULL) // code to handle backwards-compatibility to video plugins with API_VERSION < 02.1.0. This API version introduced a boolean // flag in the rendering callback, which told the core whether or not the current screen has been freshly redrawn since the // last time the callback was called. static void (*l_mainRenderCallback)(int) = NULL; static ptr_SetRenderingCallback l_old1SetRenderingCallback = NULL; static void backcompat_videoRenderCallback(int unused) // this function will be called by the video plugin as the render callback { if (l_mainRenderCallback != NULL) l_mainRenderCallback(1); // assume screen is always freshly redrawn (otherwise screenshots won't work w/ OSD enabled) } static void backcompat_setRenderCallbackIntercept(void (*callback)(int)) { l_mainRenderCallback = callback; } static void plugin_disconnect_gfx(void) { gfx = dummy_gfx; l_GfxAttached = 0; l_mainRenderCallback = NULL; } static m64p_error plugin_connect_gfx(m64p_dynlib_handle plugin_handle) { /* attach the Video plugin function pointers */ if (plugin_handle != NULL) { m64p_plugin_type PluginType; int PluginVersion, APIVersion; if (l_GfxAttached) return M64ERR_INVALID_STATE; /* set function pointers for required functions */ if (!GET_FUNC(ptr_PluginGetVersion, gfx.getVersion, "PluginGetVersion") || !GET_FUNC(ptr_ChangeWindow, gfx.changeWindow, "ChangeWindow") || !GET_FUNC(ptr_InitiateGFX, gfx.initiateGFX, "InitiateGFX") || !GET_FUNC(ptr_MoveScreen, gfx.moveScreen, "MoveScreen") || !GET_FUNC(ptr_ProcessDList, gfx.processDList, "ProcessDList") || !GET_FUNC(ptr_ProcessRDPList, gfx.processRDPList, "ProcessRDPList") || !GET_FUNC(ptr_RomClosed, gfx.romClosed, "RomClosed") || !GET_FUNC(ptr_RomOpen, gfx.romOpen, "RomOpen") || !GET_FUNC(ptr_ShowCFB, gfx.showCFB, "ShowCFB") || !GET_FUNC(ptr_UpdateScreen, gfx.updateScreen, "UpdateScreen") || !GET_FUNC(ptr_ViStatusChanged, gfx.viStatusChanged, "ViStatusChanged") || !GET_FUNC(ptr_ViWidthChanged, gfx.viWidthChanged, "ViWidthChanged") || !GET_FUNC(ptr_ReadScreen2, gfx.readScreen, "ReadScreen2") || !GET_FUNC(ptr_SetRenderingCallback, gfx.setRenderingCallback, "SetRenderingCallback") || !GET_FUNC(ptr_FBRead, gfx.fBRead, "FBRead") || !GET_FUNC(ptr_FBWrite, gfx.fBWrite, "FBWrite") || !GET_FUNC(ptr_FBGetFrameBufferInfo, gfx.fBGetFrameBufferInfo, "FBGetFrameBufferInfo")) { DebugMessage(M64MSG_ERROR, "broken Video plugin; function(s) not found."); plugin_disconnect_gfx(); return M64ERR_INPUT_INVALID; } /* set function pointers for optional functions */ gfx.resizeVideoOutput = (ptr_ResizeVideoOutput)osal_dynlib_getproc(plugin_handle, "ResizeVideoOutput"); /* check the version info */ (*gfx.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); if (PluginType != M64PLUGIN_GFX || (APIVersion & 0xffff0000) != (GFX_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "incompatible Video plugin"); plugin_disconnect_gfx(); return M64ERR_INCOMPATIBLE; } /* handle backwards-compatibility */ if (APIVersion < 0x020100) { DebugMessage(M64MSG_WARNING, "Fallback for Video plugin API (%02i.%02i.%02i) < 2.1.0. Screenshots may contain On Screen Display text", VERSION_PRINTF_SPLIT(APIVersion)); // tell the video plugin to make its rendering callback to me (it's old, and doesn't have the bScreenRedrawn flag) gfx.setRenderingCallback(backcompat_videoRenderCallback); l_old1SetRenderingCallback = gfx.setRenderingCallback; // save this just for future use gfx.setRenderingCallback = (ptr_SetRenderingCallback) backcompat_setRenderCallbackIntercept; } if (APIVersion < 0x20200 || gfx.resizeVideoOutput == NULL) { DebugMessage(M64MSG_WARNING, "Fallback for Video plugin API (%02i.%02i.%02i) < 2.2.0. Resizable video will not work", VERSION_PRINTF_SPLIT(APIVersion)); gfx.resizeVideoOutput = dummyvideo_ResizeVideoOutput; } l_GfxAttached = 1; } else plugin_disconnect_gfx(); return M64ERR_SUCCESS; } static m64p_error plugin_start_gfx(void) { uint8_t media = *((uint8_t*)mem_base_u32(g_mem_base, MM_CART_ROM) + (0x3b ^ S8)); /* Here we feed 64DD IPL ROM header to GFX plugin if 64DD is present. * We use g_media_loader.get_dd_rom to detect 64DD presence * instead of g_dev because the latter is not yet initialized at plugin_start time */ /* XXX: Not sure it is the best way to convey which game is being played to the GFX plugin * as 64DD IPL is the same for all 64DD games... */ char* dd_ipl_rom_filename = (g_media_loader.get_dd_rom == NULL) ? NULL : g_media_loader.get_dd_rom(g_media_loader.cb_data); uint32_t rom_base = (g_rom_size == 0 || (dd_ipl_rom_filename != NULL && strlen(dd_ipl_rom_filename) != 0 && media != 'C')) ? MM_DD_ROM : MM_CART_ROM; free(dd_ipl_rom_filename); /* fill in the GFX_INFO data structure */ gfx_info.HEADER = (unsigned char *)mem_base_u32(g_mem_base, rom_base); gfx_info.RDRAM = (unsigned char *)mem_base_u32(g_mem_base, MM_RDRAM_DRAM); gfx_info.DMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM); gfx_info.IMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM + 0x1000); gfx_info.MI_INTR_REG = &(g_dev.mi.regs[MI_INTR_REG]); gfx_info.DPC_START_REG = &(g_dev.dp.dpc_regs[DPC_START_REG]); gfx_info.DPC_END_REG = &(g_dev.dp.dpc_regs[DPC_END_REG]); gfx_info.DPC_CURRENT_REG = &(g_dev.dp.dpc_regs[DPC_CURRENT_REG]); gfx_info.DPC_STATUS_REG = &(g_dev.dp.dpc_regs[DPC_STATUS_REG]); gfx_info.DPC_CLOCK_REG = &(g_dev.dp.dpc_regs[DPC_CLOCK_REG]); gfx_info.DPC_BUFBUSY_REG = &(g_dev.dp.dpc_regs[DPC_BUFBUSY_REG]); gfx_info.DPC_PIPEBUSY_REG = &(g_dev.dp.dpc_regs[DPC_PIPEBUSY_REG]); gfx_info.DPC_TMEM_REG = &(g_dev.dp.dpc_regs[DPC_TMEM_REG]); gfx_info.VI_STATUS_REG = &(g_dev.vi.regs[VI_STATUS_REG]); gfx_info.VI_ORIGIN_REG = &(g_dev.vi.regs[VI_ORIGIN_REG]); gfx_info.VI_WIDTH_REG = &(g_dev.vi.regs[VI_WIDTH_REG]); gfx_info.VI_INTR_REG = &(g_dev.vi.regs[VI_V_INTR_REG]); gfx_info.VI_V_CURRENT_LINE_REG = &(g_dev.vi.regs[VI_CURRENT_REG]); gfx_info.VI_TIMING_REG = &(g_dev.vi.regs[VI_BURST_REG]); gfx_info.VI_V_SYNC_REG = &(g_dev.vi.regs[VI_V_SYNC_REG]); gfx_info.VI_H_SYNC_REG = &(g_dev.vi.regs[VI_H_SYNC_REG]); gfx_info.VI_LEAP_REG = &(g_dev.vi.regs[VI_LEAP_REG]); gfx_info.VI_H_START_REG = &(g_dev.vi.regs[VI_H_START_REG]); gfx_info.VI_V_START_REG = &(g_dev.vi.regs[VI_V_START_REG]); gfx_info.VI_V_BURST_REG = &(g_dev.vi.regs[VI_V_BURST_REG]); gfx_info.VI_X_SCALE_REG = &(g_dev.vi.regs[VI_X_SCALE_REG]); gfx_info.VI_Y_SCALE_REG = &(g_dev.vi.regs[VI_Y_SCALE_REG]); gfx_info.CheckInterrupts = EmptyFunc; gfx_info.version = 2; //Version 2 added SP_STATUS_REG and RDRAM_SIZE gfx_info.SP_STATUS_REG = &g_dev.sp.regs[SP_STATUS_REG]; gfx_info.RDRAM_SIZE = (unsigned int*) &g_dev.rdram.dram_size; /* call the audio plugin */ if (!gfx.initiateGFX(gfx_info)) return M64ERR_PLUGIN_FAIL; return M64ERR_SUCCESS; } static void plugin_disconnect_audio(void) { audio = dummy_audio; l_AudioAttached = 0; } static m64p_error plugin_connect_audio(m64p_dynlib_handle plugin_handle) { /* attach the Audio plugin function pointers */ if (plugin_handle != NULL) { m64p_plugin_type PluginType; int PluginVersion, APIVersion; if (l_AudioAttached) return M64ERR_INVALID_STATE; if (!GET_FUNC(ptr_PluginGetVersion, audio.getVersion, "PluginGetVersion") || !GET_FUNC(ptr_AiDacrateChanged, audio.aiDacrateChanged, "AiDacrateChanged") || !GET_FUNC(ptr_AiLenChanged, audio.aiLenChanged, "AiLenChanged") || !GET_FUNC(ptr_InitiateAudio, audio.initiateAudio, "InitiateAudio") || !GET_FUNC(ptr_ProcessAList, audio.processAList, "ProcessAList") || !GET_FUNC(ptr_RomOpen, audio.romOpen, "RomOpen") || !GET_FUNC(ptr_RomClosed, audio.romClosed, "RomClosed") || !GET_FUNC(ptr_SetSpeedFactor, audio.setSpeedFactor, "SetSpeedFactor") || !GET_FUNC(ptr_VolumeUp, audio.volumeUp, "VolumeUp") || !GET_FUNC(ptr_VolumeDown, audio.volumeDown, "VolumeDown") || !GET_FUNC(ptr_VolumeGetLevel, audio.volumeGetLevel, "VolumeGetLevel") || !GET_FUNC(ptr_VolumeSetLevel, audio.volumeSetLevel, "VolumeSetLevel") || !GET_FUNC(ptr_VolumeMute, audio.volumeMute, "VolumeMute") || !GET_FUNC(ptr_VolumeGetString, audio.volumeGetString, "VolumeGetString")) { DebugMessage(M64MSG_ERROR, "broken Audio plugin; function(s) not found."); plugin_disconnect_audio(); return M64ERR_INPUT_INVALID; } /* check the version info */ (*audio.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); if (PluginType != M64PLUGIN_AUDIO || (APIVersion & 0xffff0000) != (AUDIO_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "incompatible Audio plugin"); plugin_disconnect_audio(); return M64ERR_INCOMPATIBLE; } l_AudioAttached = 1; } else plugin_disconnect_audio(); return M64ERR_SUCCESS; } static m64p_error plugin_start_audio(void) { /* fill in the AUDIO_INFO data structure */ audio_info.RDRAM = (unsigned char *)mem_base_u32(g_mem_base, MM_RDRAM_DRAM); audio_info.DMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM); audio_info.IMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM + 0x1000); audio_info.MI_INTR_REG = &(g_dev.mi.regs[MI_INTR_REG]); audio_info.AI_DRAM_ADDR_REG = &(g_dev.ai.regs[AI_DRAM_ADDR_REG]); audio_info.AI_LEN_REG = &(g_dev.ai.regs[AI_LEN_REG]); audio_info.AI_CONTROL_REG = &(g_dev.ai.regs[AI_CONTROL_REG]); audio_info.AI_STATUS_REG = &dummy; audio_info.AI_DACRATE_REG = &(g_dev.ai.regs[AI_DACRATE_REG]); audio_info.AI_BITRATE_REG = &(g_dev.ai.regs[AI_BITRATE_REG]); audio_info.CheckInterrupts = EmptyFunc; /* call the audio plugin */ if (!audio.initiateAudio(audio_info)) return M64ERR_PLUGIN_FAIL; return M64ERR_SUCCESS; } static void plugin_disconnect_input(void) { input = dummy_input; l_InputAttached = 0; } static m64p_error plugin_connect_input(m64p_dynlib_handle plugin_handle) { /* attach the Input plugin function pointers */ if (plugin_handle != NULL) { m64p_plugin_type PluginType; int PluginVersion, APIVersion; if (l_InputAttached) return M64ERR_INVALID_STATE; if (!GET_FUNC(ptr_PluginGetVersion, input.getVersion, "PluginGetVersion") || !GET_FUNC(ptr_ControllerCommand, input.controllerCommand, "ControllerCommand") || !GET_FUNC(ptr_GetKeys, input.getKeys, "GetKeys") || !GET_FUNC(ptr_InitiateControllers, input.initiateControllers, "InitiateControllers") || !GET_FUNC(ptr_ReadController, input.readController, "ReadController") || !GET_FUNC(ptr_RomOpen, input.romOpen, "RomOpen") || !GET_FUNC(ptr_RomClosed, input.romClosed, "RomClosed") || !GET_FUNC(ptr_SDL_KeyDown, input.keyDown, "SDL_KeyDown") || !GET_FUNC(ptr_SDL_KeyUp, input.keyUp, "SDL_KeyUp")) { DebugMessage(M64MSG_ERROR, "broken Input plugin; function(s) not found."); plugin_disconnect_input(); return M64ERR_INPUT_INVALID; } if (!GET_FUNC(ptr_SendVRUWord, input.sendVRUWord, "SendVRUWord") || !GET_FUNC(ptr_SetMicState, input.setMicState, "SetMicState") || !GET_FUNC(ptr_ReadVRUResults, input.readVRUResults, "ReadVRUResults") || !GET_FUNC(ptr_ClearVRUWords, input.clearVRUWords, "ClearVRUWords") || !GET_FUNC(ptr_SetVRUWordMask, input.setVRUWordMask, "SetVRUWordMask")) { DebugMessage(M64MSG_WARNING, "Input plugin does not contain VRU support."); } /* check the version info */ (*input.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); if (PluginType != M64PLUGIN_INPUT || (APIVersion & 0xffff0000) != (INPUT_API_VERSION & 0xffff0000) || APIVersion < 0x020100) { DebugMessage(M64MSG_ERROR, "incompatible Input plugin"); plugin_disconnect_input(); return M64ERR_INCOMPATIBLE; } if (!GET_FUNC(ptr_RenderCallback, input.renderCallback, "RenderCallback")) { DebugMessage(M64MSG_INFO, "input plugin did not specify a render callback; there will be no on screen display by the input plugin."); } l_InputAttached = 1; } else plugin_disconnect_input(); return M64ERR_SUCCESS; } static m64p_error plugin_start_input(void) { int i; /* fill in the CONTROL_INFO data structure */ control_info.Controls = Controls; for (i=0; i<4; i++) { Controls[i].Present = 0; Controls[i].RawData = 0; Controls[i].Plugin = PLUGIN_NONE; Controls[i].Type = CONT_TYPE_STANDARD; } /* call the input plugin */ input.initiateControllers(control_info); return M64ERR_SUCCESS; } static void plugin_disconnect_rsp(void) { rsp = dummy_rsp; l_RspAttached = 0; } static m64p_error plugin_connect_rsp(m64p_dynlib_handle plugin_handle) { /* attach the RSP plugin function pointers */ if (plugin_handle != NULL) { m64p_plugin_type PluginType; int PluginVersion, APIVersion; if (l_RspAttached) return M64ERR_INVALID_STATE; if (!GET_FUNC(ptr_PluginGetVersion, rsp.getVersion, "PluginGetVersion") || !GET_FUNC(ptr_DoRspCycles, rsp.doRspCycles, "DoRspCycles") || !GET_FUNC(ptr_InitiateRSP, rsp.initiateRSP, "InitiateRSP") || !GET_FUNC(ptr_RomClosed, rsp.romClosed, "RomClosed")) { DebugMessage(M64MSG_ERROR, "broken RSP plugin; function(s) not found."); plugin_disconnect_rsp(); return M64ERR_INPUT_INVALID; } /* check the version info */ (*rsp.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); if (PluginType != M64PLUGIN_RSP || (APIVersion & 0xffff0000) != (RSP_API_VERSION & 0xffff0000)) { DebugMessage(M64MSG_ERROR, "incompatible RSP plugin"); plugin_disconnect_rsp(); return M64ERR_INCOMPATIBLE; } l_RspAttached = 1; } else plugin_disconnect_rsp(); return M64ERR_SUCCESS; } static m64p_error plugin_start_rsp(void) { /* fill in the RSP_INFO data structure */ rsp_info.RDRAM = (unsigned char *)mem_base_u32(g_mem_base, MM_RDRAM_DRAM); rsp_info.DMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM); rsp_info.IMEM = (unsigned char *)mem_base_u32(g_mem_base, MM_RSP_MEM + 0x1000); rsp_info.MI_INTR_REG = &g_dev.mi.regs[MI_INTR_REG]; rsp_info.SP_MEM_ADDR_REG = &g_dev.sp.regs[SP_MEM_ADDR_REG]; rsp_info.SP_DRAM_ADDR_REG = &g_dev.sp.regs[SP_DRAM_ADDR_REG]; rsp_info.SP_RD_LEN_REG = &g_dev.sp.regs[SP_RD_LEN_REG]; rsp_info.SP_WR_LEN_REG = &g_dev.sp.regs[SP_WR_LEN_REG]; rsp_info.SP_STATUS_REG = &g_dev.sp.regs[SP_STATUS_REG]; rsp_info.SP_DMA_FULL_REG = &g_dev.sp.regs[SP_DMA_FULL_REG]; rsp_info.SP_DMA_BUSY_REG = &g_dev.sp.regs[SP_DMA_BUSY_REG]; rsp_info.SP_PC_REG = &g_dev.sp.regs2[SP_PC_REG]; rsp_info.SP_SEMAPHORE_REG = &g_dev.sp.regs[SP_SEMAPHORE_REG]; rsp_info.DPC_START_REG = &g_dev.dp.dpc_regs[DPC_START_REG]; rsp_info.DPC_END_REG = &g_dev.dp.dpc_regs[DPC_END_REG]; rsp_info.DPC_CURRENT_REG = &g_dev.dp.dpc_regs[DPC_CURRENT_REG]; rsp_info.DPC_STATUS_REG = &g_dev.dp.dpc_regs[DPC_STATUS_REG]; rsp_info.DPC_CLOCK_REG = &g_dev.dp.dpc_regs[DPC_CLOCK_REG]; rsp_info.DPC_BUFBUSY_REG = &g_dev.dp.dpc_regs[DPC_BUFBUSY_REG]; rsp_info.DPC_PIPEBUSY_REG = &g_dev.dp.dpc_regs[DPC_PIPEBUSY_REG]; rsp_info.DPC_TMEM_REG = &g_dev.dp.dpc_regs[DPC_TMEM_REG]; rsp_info.CheckInterrupts = EmptyFunc; rsp_info.ProcessDlistList = gfx.processDList; rsp_info.ProcessAlistList = audio.processAList; rsp_info.ProcessRdpList = gfx.processRDPList; rsp_info.ShowCFB = gfx.showCFB; /* call the RSP plugin */ rsp.initiateRSP(rsp_info, NULL); return M64ERR_SUCCESS; } /* global functions */ m64p_error plugin_connect(m64p_plugin_type type, m64p_dynlib_handle plugin_handle) { switch(type) { case M64PLUGIN_GFX: if (plugin_handle != NULL && (l_AudioAttached || l_InputAttached || l_RspAttached)) DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); return plugin_connect_gfx(plugin_handle); case M64PLUGIN_AUDIO: if (plugin_handle != NULL && (l_InputAttached || l_RspAttached)) DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); return plugin_connect_audio(plugin_handle); case M64PLUGIN_INPUT: if (plugin_handle != NULL && (l_RspAttached)) DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); return plugin_connect_input(plugin_handle); case M64PLUGIN_RSP: return plugin_connect_rsp(plugin_handle); default: return M64ERR_INPUT_INVALID; } return M64ERR_INTERNAL; } m64p_error plugin_start(m64p_plugin_type type) { switch(type) { case M64PLUGIN_RSP: return plugin_start_rsp(); case M64PLUGIN_GFX: return plugin_start_gfx(); case M64PLUGIN_AUDIO: return plugin_start_audio(); case M64PLUGIN_INPUT: return plugin_start_input(); default: return M64ERR_INPUT_INVALID; } return M64ERR_INTERNAL; } m64p_error plugin_check(void) { if (!l_GfxAttached) DebugMessage(M64MSG_WARNING, "No video plugin attached. There will be no video output."); if (!l_RspAttached) DebugMessage(M64MSG_WARNING, "No RSP plugin attached. The video output will be corrupted."); if (!l_AudioAttached) DebugMessage(M64MSG_WARNING, "No audio plugin attached. There will be no sound output."); if (!l_InputAttached) DebugMessage(M64MSG_WARNING, "No input plugin attached. You won't be able to control the game."); return M64ERR_SUCCESS; } mupen64plus-core-src-2.6.0/src/plugin/plugin.h000066400000000000000000000110751464506436200212060ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - plugin.h * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2002 Hacktarux * * Copyright (C) 2009 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef PLUGIN_H #define PLUGIN_H #include "api/m64p_common.h" #include "api/m64p_plugin.h" #include "api/m64p_types.h" extern m64p_error plugin_connect(m64p_plugin_type, m64p_dynlib_handle plugin_handle); extern m64p_error plugin_start(m64p_plugin_type); extern m64p_error plugin_check(void); enum { NUM_CONTROLLER = 4 }; extern CONTROL Controls[NUM_CONTROLLER]; /*** Version requirement information ***/ #define RSP_API_VERSION 0x20000 #define GFX_API_VERSION 0x20200 #define AUDIO_API_VERSION 0x20000 #define INPUT_API_VERSION 0x20101 /* video plugin function pointers */ typedef struct _gfx_plugin_functions { ptr_PluginGetVersion getVersion; ptr_ChangeWindow changeWindow; ptr_InitiateGFX initiateGFX; ptr_MoveScreen moveScreen; ptr_ProcessDList processDList; ptr_ProcessRDPList processRDPList; ptr_RomClosed romClosed; ptr_RomOpen romOpen; ptr_ShowCFB showCFB; ptr_UpdateScreen updateScreen; ptr_ViStatusChanged viStatusChanged; ptr_ViWidthChanged viWidthChanged; ptr_ReadScreen2 readScreen; ptr_SetRenderingCallback setRenderingCallback; ptr_ResizeVideoOutput resizeVideoOutput; /* frame buffer plugin spec extension */ ptr_FBRead fBRead; ptr_FBWrite fBWrite; ptr_FBGetFrameBufferInfo fBGetFrameBufferInfo; } gfx_plugin_functions; extern gfx_plugin_functions gfx; /* audio plugin function pointers */ typedef struct _audio_plugin_functions { ptr_PluginGetVersion getVersion; ptr_AiDacrateChanged aiDacrateChanged; ptr_AiLenChanged aiLenChanged; ptr_InitiateAudio initiateAudio; ptr_ProcessAList processAList; ptr_RomClosed romClosed; ptr_RomOpen romOpen; ptr_SetSpeedFactor setSpeedFactor; ptr_VolumeUp volumeUp; ptr_VolumeDown volumeDown; ptr_VolumeGetLevel volumeGetLevel; ptr_VolumeSetLevel volumeSetLevel; ptr_VolumeMute volumeMute; ptr_VolumeGetString volumeGetString; } audio_plugin_functions; extern audio_plugin_functions audio; /* input plugin function pointers */ typedef struct _input_plugin_functions { ptr_PluginGetVersion getVersion; ptr_ControllerCommand controllerCommand; ptr_GetKeys getKeys; ptr_InitiateControllers initiateControllers; ptr_ReadController readController; ptr_RomClosed romClosed; ptr_RomOpen romOpen; ptr_SDL_KeyDown keyDown; ptr_SDL_KeyUp keyUp; ptr_RenderCallback renderCallback; ptr_SendVRUWord sendVRUWord; ptr_SetMicState setMicState; ptr_ReadVRUResults readVRUResults; ptr_ClearVRUWords clearVRUWords; ptr_SetVRUWordMask setVRUWordMask; } input_plugin_functions; extern input_plugin_functions input; /* RSP plugin function pointers */ typedef struct _rsp_plugin_functions { ptr_PluginGetVersion getVersion; ptr_DoRspCycles doRspCycles; ptr_InitiateRSP initiateRSP; ptr_RomClosed romClosed; } rsp_plugin_functions; extern rsp_plugin_functions rsp; #endif mupen64plus-core-src-2.6.0/subprojects/000077500000000000000000000000001464506436200200115ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/subprojects/md5/000077500000000000000000000000001464506436200204765ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/subprojects/md5/md5.c000066400000000000000000000320361464506436200213330ustar00rootroot00000000000000/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, unsigned int nbytes) { const md5_byte_t *p = data; unsigned int left = nbytes; unsigned int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* this special case is handled recursively */ if (nbytes > INT_MAX - offset) { unsigned int overlap; /* handle the append in two steps to prevent overflow */ overlap = 64 - offset; md5_append(pms, data, overlap); md5_append(pms, data + overlap, nbytes - overlap); return; } /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { unsigned int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } mupen64plus-core-src-2.6.0/subprojects/md5/md5.h000066400000000000000000000064371464506436200213460ustar00rootroot00000000000000/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id$ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ void md5_init(md5_state_t *pms); /* Append a string to the message. */ void md5_append(md5_state_t *pms, const md5_byte_t *data, unsigned int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ mupen64plus-core-src-2.6.0/subprojects/minizip/000077500000000000000000000000001464506436200214705ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/subprojects/minizip/crypt.h000066400000000000000000000113011464506436200227760ustar00rootroot00000000000000/* crypt.h -- base code for crypt/uncrypt ZIPfile Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This code is a modified version of crypting code in Infozip distribution The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). If you don't need crypting in your application, just define symbols NOCRYPT and NOUNCRYPT. This code support the "Traditional PKWARE Encryption". The new AES encryption added on Zip format by Winzip (see the page http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong Encryption is not supported. */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ (void)pcrc_32_tab; temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys, const z_crc_t* pcrc_32_tab, int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys+1)) >> 24); (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd, unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; while (*passwd != '\0') { update_keys(pkeys,pcrc_32_tab,(int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), (Byte)t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static unsigned crypthead(const char* passwd, /* password string */ unsigned char* buf, /* where to write header */ int bufSize, unsigned long* pkeys, const z_crc_t* pcrc_32_tab, unsigned long crcForCrypting) { unsigned n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if (bufSize> 7) & 0xff; header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); } /* Encrypt random header (last two bytes is high word of crc) */ init_keys(passwd, pkeys, pcrc_32_tab); for (n = 0; n < RAND_HEAD_LEN-2; n++) { buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); } buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); return n; } #endif mupen64plus-core-src-2.6.0/subprojects/minizip/ioapi.c000066400000000000000000000170741464506436200227460ustar00rootroot00000000000000/* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt */ #if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) #define _CRT_SECURE_NO_WARNINGS #endif #if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) // In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions #define FOPEN_FUNC(filename, mode) fopen(filename, mode) #define FTELLO_FUNC(stream) ftello(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) #else #define FOPEN_FUNC(filename, mode) fopen64(filename, mode) #define FTELLO_FUNC(stream) ftello64(stream) #define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) #endif #include "ioapi.h" voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc, const void*filename, int mode) { if (pfilefunc->zfile_func64.zopen64_file != NULL) return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); else { return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); } } long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); else { uLong offsetTruncated = (uLong)offset; if (offsetTruncated != offset) return -1; else return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); } } ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc, voidpf filestream) { if (pfilefunc->zfile_func64.zseek64_file != NULL) return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); else { uLong tell_uLong = (uLong)(*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); if ((tell_uLong) == MAXU32) return (ZPOS64_T)-1; else return tell_uLong; } } void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32, const zlib_filefunc_def* p_filefunc32) { p_filefunc64_32->zfile_func64.zopen64_file = NULL; p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; p_filefunc64_32->zfile_func64.ztell64_file = NULL; p_filefunc64_32->zfile_func64.zseek64_file = NULL; p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; } static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; (void)opaque; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = fopen(filename, mode_fopen); return file; } static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; (void)opaque; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = FOPEN_FUNC((const char*)filename, mode_fopen); return file; } static uLong ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) { uLong ret; (void)opaque; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } static uLong ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) { uLong ret; (void)opaque; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream) { long ret; (void)opaque; ret = ftell((FILE *)stream); return ret; } static ZPOS64_T ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream) { ZPOS64_T ret; (void)opaque; ret = (ZPOS64_T)FTELLO_FUNC((FILE *)stream); return ret; } static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) { int fseek_origin=0; long ret; (void)opaque; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if (fseek((FILE *)stream, (long)offset, fseek_origin) != 0) ret = -1; return ret; } static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) { int fseek_origin=0; long ret; (void)opaque; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; if(FSEEKO_FUNC((FILE *)stream, (z_off64_t)offset, fseek_origin) != 0) ret = -1; return ret; } static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream) { int ret; (void)opaque; ret = fclose((FILE *)stream); return ret; } static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream) { int ret; (void)opaque; ret = ferror((FILE *)stream); return ret; } void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell_file = ftell_file_func; pzlib_filefunc_def->zseek_file = fseek_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen64_file = fopen64_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell64_file = ftell64_file_func; pzlib_filefunc_def->zseek64_file = fseek64_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } mupen64plus-core-src-2.6.0/subprojects/minizip/ioapi.h000066400000000000000000000156741464506436200227570ustar00rootroot00000000000000/* ioapi.h -- IO base function header for compress/uncompress .zip part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt Changes Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. More if/def section may be needed to support other platforms Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. (but you should use iowin32.c for windows instead) */ #ifndef _ZLIBIOAPI64_H #define _ZLIBIOAPI64_H #if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) // Linux needs this to support file operation on files larger then 4+GB // But might need better if/def to select just the platforms that needs them. #ifndef __USE_FILE_OFFSET64 #define __USE_FILE_OFFSET64 #endif #ifndef __USE_LARGEFILE64 #define __USE_LARGEFILE64 #endif #ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #endif #ifndef _FILE_OFFSET_BIT #define _FILE_OFFSET_BIT 64 #endif #endif #include #include #include "zlib.h" #if defined(USE_FILE32API) #define fopen64 fopen #define ftello64 ftell #define fseeko64 fseek #else #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64) #define fopen64 fopen #define ftello64 ftello #define fseeko64 fseeko #endif #ifdef _MSC_VER #define fopen64 fopen #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) #define ftello64 _ftelli64 #define fseeko64 _fseeki64 #else // old MSC #define ftello64 ftell #define fseeko64 fseek #endif #endif #endif /* #ifndef ZPOS64_T #ifdef _WIN32 #define ZPOS64_T fpos_t #else #include #define ZPOS64_T uint64_t #endif #endif */ #ifdef HAVE_MINIZIP64_CONF_H #include "mz64conf.h" #endif /* a type chosen by DEFINE */ #ifdef HAVE_64BIT_INT_CUSTOM typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; #else #ifdef HAS_STDINT_H #include "stdint.h" typedef uint64_t ZPOS64_T; #else #if defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 ZPOS64_T; #else typedef unsigned long long int ZPOS64_T; #endif #endif #endif /* Maximum unsigned 32-bit value used as placeholder for zip64 */ #ifndef MAXU32 #define MAXU32 (0xffffffff) #endif #ifdef __cplusplus extern "C" { #endif #define ZLIB_FILEFUNC_SEEK_CUR (1) #define ZLIB_FILEFUNC_SEEK_END (2) #define ZLIB_FILEFUNC_SEEK_SET (0) #define ZLIB_FILEFUNC_MODE_READ (1) #define ZLIB_FILEFUNC_MODE_WRITE (2) #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) #define ZLIB_FILEFUNC_MODE_EXISTING (4) #define ZLIB_FILEFUNC_MODE_CREATE (8) #ifndef ZCALLBACK #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) #define ZCALLBACK CALLBACK #else #define ZCALLBACK #endif #endif typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode); typedef uLong (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size); typedef uLong (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void* buf, uLong size); typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream); typedef int (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream); typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream); typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin); /* here is the "old" 32 bits structure */ typedef struct zlib_filefunc_def_s { open_file_func zopen_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; typedef ZPOS64_T (ZCALLBACK *tell64_file_func) (voidpf opaque, voidpf stream); typedef long (ZCALLBACK *seek64_file_func) (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin); typedef voidpf (ZCALLBACK *open64_file_func) (voidpf opaque, const void* filename, int mode); typedef struct zlib_filefunc64_def_s { open64_file_func zopen64_file; read_file_func zread_file; write_file_func zwrite_file; tell64_file_func ztell64_file; seek64_file_func zseek64_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc64_def; void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def); void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def); /* now internal definition, only for zip.c and unzip.h */ typedef struct zlib_filefunc64_32_def_s { zlib_filefunc64_def zfile_func64; open_file_func zopen32_file; tell_file_func ztell32_file; seek_file_func zseek32_file; } zlib_filefunc64_32_def; #define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) #define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) #define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) #define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) voidpf call_zopen64(const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode); long call_zseek64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin); ZPOS64_T call_ztell64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream); void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); #define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) #define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) #define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) #ifdef __cplusplus } #endif #endif mupen64plus-core-src-2.6.0/subprojects/minizip/unzip.c000066400000000000000000002040701464506436200230040ustar00rootroot00000000000000/* unzip.c -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt ------------------------------------------------------------------------------------ Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of compatibility with older software. The following is from the original crypt.c. Code woven in by Terry Thorsen 1/2003. Copyright (c) 1990-2000 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in zip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). ------------------------------------------------------------------------------------ Changes in unzip.c 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* 2007-2008 - Even Rouault - Remove old C style function prototypes 2007-2008 - Even Rouault - Add unzip support for ZIP64 Copyright (C) 2007-2008 Even Rouault Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G should only read the compressed/uncompressed size from the Zip64 format if the size from normal header was 0xFFFFFFFF Oct-2009 - Mathias Svensson - Applied some bug fixes from patches received from Gilles Vollant Oct-2009 - Mathias Svensson - Applied support to unzip files with compression method BZIP2 (bzip2 lib is required) Patch created by Daniel Borca Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson */ #include #include #include #ifndef NOUNCRYPT #define NOUNCRYPT #endif #include "zlib.h" #include "unzip.h" #ifdef STDC # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef CASESENSITIVITYDEFAULT_NO # if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) # define CASESENSITIVITYDEFAULT_NO # endif #endif #ifndef UNZ_BUFSIZE #define UNZ_BUFSIZE (16384) #endif #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info64_internal contain internal info about a file in zipfile*/ typedef struct unz_file_info64_internal_s { ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ } unz_file_info64_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, when reading and decompress it */ typedef struct { char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ ZPOS64_T total_out_64; uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structure of the zipfile */ uLong compression_method; /* compression method (0==store) */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; } file_in_zip64_read_info_s; /* unz64_s contain internal information about the zipfile */ typedef struct { zlib_filefunc64_32_def z_filefunc; int is64bitOpenFunction; voidpf filestream; /* io structure of the zipfile */ unz_global_info64 gi; /* public global information */ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T num_file; /* number of the current file in the zipfile*/ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ ZPOS64_T central_pos; /* position of the beginning of the central dir*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info64 cur_file_info; /* public info about the current file in zip*/ unz_file_info64_internal cur_file_info_internal; /* private info about it*/ file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current file if we are decompressing it */ int encrypted; int isZip64; # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const z_crc_t* pcrc_32_tab; # endif } unz64_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unz64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { unsigned char c[2]; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,2); if (err==2) { *pX = c[0] | ((uLong)c[1] << 8); return UNZ_OK; } else { *pX = 0; if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } local int unz64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { unsigned char c[4]; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,4); if (err==4) { *pX = c[0] | ((uLong)c[1] << 8) | ((uLong)c[2] << 16) | ((uLong)c[3] << 24); return UNZ_OK; } else { *pX = 0; if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } local int unz64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { unsigned char c[8]; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,8); if (err==8) { *pX = c[0] | ((ZPOS64_T)c[1] << 8) | ((ZPOS64_T)c[2] << 16) | ((ZPOS64_T)c[3] << 24) | ((ZPOS64_T)c[4] << 32) | ((ZPOS64_T)c[5] << 40) | ((ZPOS64_T)c[6] << 48) | ((ZPOS64_T)c[7] << 56); return UNZ_OK; } else { *pX = 0; if (ZERROR64(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal(const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) c2 -= 0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } #ifdef CASESENSITIVITYDEFAULT_NO #define CASESENSITIVITYDEFAULTVALUE 2 #else #define CASESENSITIVITYDEFAULTVALUE 1 #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filenames (fileName1,fileName2). If iCaseSensitivity = 1, comparison is case sensitive (like strcmp) If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi or strcasecmp) If iCaseSensitivity = 0, case sensitivity is default of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif #ifndef CENTRALDIRINVALID #define CENTRALDIRINVALID ((ZPOS64_T)(-1)) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=CENTRALDIRINVALID; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return CENTRALDIRINVALID; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return CENTRALDIRINVALID; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+(unsigned)i; break; } if (uPosFound!=CENTRALDIRINVALID) break; } free(buf); return uPosFound; } /* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=CENTRALDIRINVALID; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return CENTRALDIRINVALID; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return CENTRALDIRINVALID; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+(unsigned)i; break; } if (uPosFound!=CENTRALDIRINVALID) break; } free(buf); if (uPosFound == CENTRALDIRINVALID) return CENTRALDIRINVALID; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return CENTRALDIRINVALID; /* the signature, already checked */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return CENTRALDIRINVALID; /* number of the disk with the start of the zip64 end of central directory */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return CENTRALDIRINVALID; if (uL != 0) return CENTRALDIRINVALID; /* relative offset of the zip64 end of central directory record */ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) return CENTRALDIRINVALID; /* total number of disks */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return CENTRALDIRINVALID; if (uL != 1) return CENTRALDIRINVALID; /* Goto end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return CENTRALDIRINVALID; /* the signature */ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) return CENTRALDIRINVALID; if (uL != 0x06064b50) return CENTRALDIRINVALID; return relativeOffset; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer "zlib/zlib114.zip". If the zipfile cannot be opened (file doesn't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ local unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def* pzlib_filefunc64_32_def, int is64bitOpenFunction) { unz64_s us; unz64_s *s; ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current disk, used for spanning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the disk with central dir, used for spanning ZIP, unsupported, always 0*/ ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') return NULL; us.z_filefunc.zseek32_file = NULL; us.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); else us.z_filefunc = *pzlib_filefunc64_32_def; us.is64bitOpenFunction = is64bitOpenFunction; us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); if (central_pos!=CENTRALDIRINVALID) { uLong uS; ZPOS64_T uL64; us.isZip64 = 1; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* size of zip64 end of central directory record */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) err=UNZ_ERRNO; /* version made by */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* version needed to extract */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory on this disk */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; us.gi.size_comment = 0; } else { central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); if (central_pos==CENTRALDIRINVALID) err=UNZ_ERRNO; us.isZip64 = 0; if (ZSEEK64(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir on this disk */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.gi.number_entry = uL; /* total number of entries in the central dir */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; number_entry_CD = uL; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; us.offset_central_dir = uL; /* zipfile comment length */ if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; } if ((central_pospfile_in_zip_read!=NULL) unzCloseCurrentFile(file); ZCLOSE64(s->z_filefunc, s->filestream); free(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; *pglobal_info=s->gi; return UNZ_OK; } extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) { unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* to do : check if number_entry is not truncated */ pglobal_info32->number_entry = (uLong)s->gi.number_entry; pglobal_info32->size_comment = s->gi.size_comment; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easily) */ local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz* ptm) { ZPOS64_T uDate; uDate = (ZPOS64_T)(ulDosDate>>16); ptm->tm_mday = (int)(uDate&0x1f) ; ptm->tm_mon = (int)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (int)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (int) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (int) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (int) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unz64local_GetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info, unz_file_info64_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz64_s* s; unz_file_info64 file_info; unz_file_info64_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; uLong uL; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (ZSEEK64(s->z_filefunc, s->filestream, s->pos_in_central_dir+s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* we check the magic */ if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.compressed_size = uL; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info.uncompressed_size = uL; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; // relative offset of local header if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) err=UNZ_ERRNO; file_info_internal.offset_curfile = uL; lSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek -= uSizeRead; } // Read extrafield if ((err==UNZ_OK) && (extraField!=NULL)) { ZPOS64_T uSizeRead ; if (file_info.size_file_extraz_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek += file_info.size_file_extra - (uLong)uSizeRead; } else lSeek += file_info.size_file_extra; if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) { uLong acc = 0; // since lSeek now points to after the extra field we need to move back lSeek -= file_info.size_file_extra; if (lSeek!=0) { if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } while(acc < file_info.size_file_extra) { uLong headerId; uLong dataSize; if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) err=UNZ_ERRNO; /* ZIP64 extra fields */ if (headerId == 0x0001) { if(file_info.uncompressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.compressed_size == MAXU32) { if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; } if(file_info_internal.offset_curfile == MAXU32) { /* Relative Header offset */ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; } if(file_info.disk_num_start == 0xffff) { /* Disk Start Number */ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; } } else { if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) err=UNZ_ERRNO; } acc += 2 + 2 + dataSize; } } if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentz_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek+=file_info.size_file_comment - uSizeRead; } else lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info * pfile_info, char * szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char* szComment, uLong commentBufferSize) { int err; unz_file_info64 file_info64; err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); if ((err==UNZ_OK) && (pfile_info != NULL)) { pfile_info->version = file_info64.version; pfile_info->version_needed = file_info64.version_needed; pfile_info->flag = file_info64.flag; pfile_info->compression_method = file_info64.compression_method; pfile_info->dosDate = file_info64.dosDate; pfile_info->crc = file_info64.crc; pfile_info->size_filename = file_info64.size_filename; pfile_info->size_file_extra = file_info64.size_file_extra; pfile_info->size_file_comment = file_info64.size_file_comment; pfile_info->disk_num_start = file_info64.disk_num_start; pfile_info->internal_fa = file_info64.internal_fa; pfile_info->external_fa = file_info64.external_fa; pfile_info->tmu_date = file_info64.tmu_date; pfile_info->compressed_size = (uLong)file_info64.compressed_size; pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; } return err; } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile(unzFile file) { int err=UNZ_OK; unz64_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile(unzFile file) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) { unz64_s* s; int err; /* We remember the 'current' position in the file so that we can jump * back there if we fail. */ unz_file_info64 cur_file_infoSaved; unz_file_info64_internal cur_file_info_internalSaved; ZPOS64_T num_fileSaved; ZPOS64_T pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; /* Save the current state */ num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; cur_file_infoSaved = s->cur_file_info; cur_file_info_internalSaved = s->cur_file_info_internal; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; err = unzGetCurrentFileInfo64(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (err == UNZ_OK) { if (unzStringFileNameCompare(szCurrentFileName, szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } } /* We failed, so restore the state of the 'current file' to where we * were. */ s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; s->cur_file_info = cur_file_infoSaved; s->cur_file_info_internal = cur_file_info_internalSaved; return err; } /* /////////////////////////////////////////// // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) // I need random access // // Further optimization could be realized by adding an ability // to cache the directory in memory. The goal being a single // comprehensive file read to put the file I need in a memory. */ /* typedef struct unz_file_pos_s { ZPOS64_T pos_in_zip_directory; // offset in file ZPOS64_T num_of_file; // # of file } unz_file_pos; */ extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) { unz64_s* s; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; int err = unzGetFilePos64(file,&file_pos64); if (err==UNZ_OK) { file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; file_pos->num_of_file = (uLong)file_pos64.num_of_file; } return err; } extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) { unz64_s* s; int err; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) { unz64_file_pos file_pos64; if (file_pos == NULL) return UNZ_PARAMERROR; file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; file_pos64.num_of_file = file_pos->num_of_file; return unzGoToFilePos64(file,&file_pos64); } /* // Unzip Helper Functions - should be here? /////////////////////////////////////////// */ /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar, ZPOS64_T * poffset_local_extrafield, uInt * psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; /* else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) err=UNZ_BADZIPFILE; */ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ err=UNZ_ERRNO; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ err=UNZ_ERRNO; else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ # ifndef NOUNCRYPT char source[12]; # else if (password != NULL) return UNZ_PARAMERROR; # endif if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { free(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if (method!=NULL) *method = (int)s->cur_file_info.compression_method; if (level!=NULL) { *level = 6; switch (s->cur_file_info.flag & 0x06) { case 6 : *level = 1; break; case 4 : *level = 2; break; case 2 : *level = 9; break; } } if ((s->cur_file_info.compression_method!=0) && /* #ifdef HAVE_BZIP2 */ (s->cur_file_info.compression_method!=Z_BZIP2ED) && /* #endif */ (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->total_out_64=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->filestream=s->filestream; pfile_in_zip_read_info->z_filefunc=s->z_filefunc; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) { #ifdef HAVE_BZIP2 pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; pfile_in_zip_read_info->bstream.bzfree = (free_func)0; pfile_in_zip_read_info->bstream.opaque = (voidpf)0; pfile_in_zip_read_info->bstream.state = (voidpf)0; pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; else { free(pfile_in_zip_read_info->read_buffer); free(pfile_in_zip_read_info); return err; } #else pfile_in_zip_read_info->raw=1; #endif } else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = 0; pfile_in_zip_read_info->stream.avail_in = 0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; else { free(pfile_in_zip_read_info->read_buffer); free(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; s->encrypted = 0; # ifndef NOUNCRYPT if (password != NULL) { int i; s->pcrc_32_tab = get_crc_table(); init_keys(password,s->keys,s->pcrc_32_tab); if (ZSEEK64(s->z_filefunc, s->filestream, s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, SEEK_SET)!=0) return UNZ_INTERNALERROR; if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) return UNZ_INTERNALERROR; for (i = 0; i<12; i++) zdecode(s->keys,s->pcrc_32_tab,source[i]); s->pfile_in_zip_read->pos_in_zipfile+=12; s->encrypted=1; } # endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile(unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; s=(unz64_s*)file; if (file==NULL) return 0; //UNZ_PARAMERROR; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return 0; //UNZ_PARAMERROR; return pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile; } /** Addition for GDAL : END */ /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if some bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; if ((len>pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in) && (pfile_in_zip_read_info->raw)) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in; while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->read_buffer, uReadThis)!=uReadThis) return UNZ_ERRNO; # ifndef NOUNCRYPT if(s->encrypted) { uInt i; for(i=0;iread_buffer[i] = zdecode(s->keys,s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); } # endif pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead==0) ? UNZ_EOF : (int)iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) { #ifdef HAVE_BZIP2 uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; pfile_in_zip_read_info->bstream.total_in_hi32 = 0; pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; pfile_in_zip_read_info->bstream.total_out_hi32 = 0; uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; if (err==BZ_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=BZ_OK) break; #endif } // end Z_BZIP2ED else { ZPOS64_T uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; ZPOS64_T uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; /* Detect overflow, because z_stream.total_out is uLong (32 bits) */ if (uTotalOutAftertotal_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : (int)iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return (int)iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } extern ZPOS64_T ZEXPORT unztell64(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return (ZPOS64_T)-1; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return (ZPOS64_T)-1; return pfile_in_zip_read_info->total_out_64; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof(unzFile file) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) { unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; uInt read_now; ZPOS64_T size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD64(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf,read_now)!=read_now) return UNZ_ERRNO; return (int)read_now; } /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile(unzFile file) { int err=UNZ_OK; unz64_s* s; file_in_zip64_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } free(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) inflateEnd(&pfile_in_zip_read_info->stream); #ifdef HAVE_BZIP2 else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); #endif pfile_in_zip_read_info->stream_initialised = 0; free(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment(unzFile file, char * szComment, uLong uSizeBuf) { unz64_s* s; uLong uReadThis ; if (file==NULL) return (int)UNZ_PARAMERROR; s=(unz64_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) { unz64_s* s; if (file==NULL) return 0; //UNZ_PARAMERROR; s=(unz64_s*)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file==s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern uLong ZEXPORT unzGetOffset(unzFile file) { ZPOS64_T offset64; if (file==NULL) return 0; //UNZ_PARAMERROR; offset64 = unzGetOffset64(file); return (uLong)offset64; } extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) { unz64_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz64_s*)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) { return unzSetOffset64(file,pos); } mupen64plus-core-src-2.6.0/subprojects/minizip/unzip.h000066400000000000000000000401001464506436200230010ustar00rootroot00000000000000/* unzip.h -- IO for uncompress .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications of Unzip for Zip64 Copyright (C) 2007-2008 Even Rouault Modifications for Zip64 support on both zip and unzip Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt --------------------------------------------------------------------------------- Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --------------------------------------------------------------------------------- Changes See header of unzip64.c */ #ifndef _unz64_H #define _unz64_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info64_s { ZPOS64_T number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info64; typedef struct unz_global_info_s { uLong number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info64_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ ZPOS64_T compressed_size; /* compressed size 8 bytes */ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info64; typedef struct unz_file_info_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ uLong compressed_size; /* compressed size 4 bytes */ uLong uncompressed_size; /* uncompressed size 4 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare(const char* fileName1, const char* fileName2, int iCaseSensitivity); /* Compare two filenames (fileName1,fileName2). If iCaseSensitivity = 1, comparison is case sensitive (like strcmp) If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi or strcasecmp) If iCaseSensitivity = 0, case sensitivity is default of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen(const char *path); extern unzFile ZEXPORT unzOpen64(const void *path); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. the "64" function take a const void* pointer, because the path is just the value passed to the open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* does not describe the reality */ extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def* pzlib_filefunc_def); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def* pzlib_filefunc_def); /* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern int ZEXPORT unzClose(unzFile file); /* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzCloseCurrentFile before call unzClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info); extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile(unzFile file); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile(unzFile file); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ /* ****************************************** */ /* Ryan supplied functions */ /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_pos_s { uLong pos_in_zip_directory; /* offset in zip file directory */ uLong num_of_file; /* # of file */ } unz_file_pos; extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos); typedef struct unz64_file_pos_s { ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ ZPOS64_T num_of_file; /* # of file */ } unz64_file_pos; extern int ZEXPORT unzGetFilePos64( unzFile file, unz64_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos64( unzFile file, const unz64_file_pos* file_pos); /* ****************************************** */ extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize); extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain some info about the current file if szFileName!=NULL, the filename string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /** Addition for GDAL : START */ extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file); /** Addition for GDAL : END */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile(unzFile file); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method, int* level, int raw, const char* password); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzCloseCurrentFile(unzFile file); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if some bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell(unzFile file); extern ZPOS64_T ZEXPORT unztell64(unzFile file); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof(unzFile file); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ /***************************************************************************/ /* Get the current file offset */ extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); extern uLong ZEXPORT unzGetOffset (unzFile file); /* Set the current file offset */ extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); #ifdef __cplusplus } #endif #endif /* _unz64_H */ mupen64plus-core-src-2.6.0/subprojects/minizip/zip.c000066400000000000000000001776121464506436200224540ustar00rootroot00000000000000/* zip.c -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt Changes Oct-2009 - Mathias Svensson - Remove old C style function prototypes Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data It is used when recreating zip archive with RAW when deleting items from a zip. ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed. Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer */ #include #include #include #include #include #include "zlib.h" #include "zip.h" #ifdef STDC # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x0) /* platform dependent */ #endif #ifndef Z_BUFSIZE #define Z_BUFSIZE (64*1024) //(16384) #endif #ifndef Z_MAXFILENAMEINZIP #define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif /* #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) */ /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ // NOT sure that this work on ALL platform #define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef DEF_MEM_LEVEL #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif #endif const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; #define SIZEDATA_INDATABLOCK (4096-(4*4)) #define LOCALHEADERMAGIC (0x04034b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define ZIP64ENDHEADERMAGIC (0x6064b50) #define ZIP64ENDLOCHEADERMAGIC (0x7064b50) #define FLAG_LOCALHEADER_OFFSET (0x06) #define CRC_LOCALHEADER_OFFSET (0x0e) #define SIZECENTRALHEADER (0x2e) /* 46 */ typedef struct linkedlist_datablock_internal_s { struct linkedlist_datablock_internal_s* next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; uLong unused; /* for future use and alignment */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; typedef struct linkedlist_data_s { linkedlist_datablock_internal* first_block; linkedlist_datablock_internal* last_block; } linkedlist_data; typedef struct { z_stream stream; /* zLib stream structure for inflate */ #ifdef HAVE_BZIP2 bz_stream bstream; /* bzLib stream structure for bziped */ #endif int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ ZPOS64_T pos_local_header; /* offset of the local header of the file currently writing */ char* central_header; /* central header data for the current file */ uLong size_centralExtra; uLong size_centralheader; /* size of the central header for cur file */ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ uLong flag; /* flag of the file currently writing */ int method; /* compression method of file currently wr.*/ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int encrypt; int zip64; /* Add ZIP64 extended information in the extra field */ ZPOS64_T pos_zip64extrainfo; ZPOS64_T totalCompressedData; ZPOS64_T totalUncompressedData; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const z_crc_t* pcrc_32_tab; unsigned crypt_header_size; #endif } curfile64_info; typedef struct { zlib_filefunc64_32_def z_filefunc; voidpf filestream; /* io structure of the zipfile */ linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ curfile64_info ci; /* info on the file currently writing */ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ ZPOS64_T add_position_when_writing_offset; ZPOS64_T number_entry; #ifndef NO_ADDFILEINEXISTINGZIP char *globalcomment; #endif } zip64_internal; #ifndef NOCRYPT #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED #include "crypt.h" #endif local linkedlist_datablock_internal* allocate_new_datablock(void) { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi!=NULL) { ldi->next_datablock = NULL ; ldi->filled_in_this_block = 0 ; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; } return ldi; } local void free_datablock(linkedlist_datablock_internal* ldi) { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; free(ldi); ldi = ldinext; } } local void init_linkedlist(linkedlist_data* ll) { ll->first_block = ll->last_block = NULL; } local void free_linkedlist(linkedlist_data* ll) { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; if (ll==NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (const unsigned char*)buf; while (len>0) { uInt copy_this; uInt i; unsigned char* to_copy; if (ldi->avail_in_this_block==0) { ldi->next_datablock = allocate_new_datablock(); if (ldi->next_datablock == NULL) return ZIP_INTERNALERROR; ldi = ldi->next_datablock ; ll->last_block = ldi; } if (ldi->avail_in_this_block < len) copy_this = (uInt)ldi->avail_in_this_block; else copy_this = (uInt)len; to_copy = &(ldi->data[ldi->filled_in_this_block]); for (i=0;ifilled_in_this_block += copy_this; ldi->avail_in_this_block -= copy_this; from_copy += copy_this ; len -= copy_this; } return ZIP_OK; } /****************************************************************************/ #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) */ local int zip64local_putValue(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) { unsigned char buf[8]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 (X Roche) */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,(uLong)nbByte)!=(uLong)nbByte) return ZIP_ERRNO; else return ZIP_OK; } local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } } /****************************************************************************/ local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) { uLong year = (uLong)ptm->tm_year; if (year>=1980) year-=1980; else if (year>=80) year-=80; return (uLong) (((uLong)(ptm->tm_mday) + (32 * (uLong)(ptm->tm_mon+1)) + (512 * year)) << 16) | (((uLong)ptm->tm_sec/2) + (32 * (uLong)ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int* pi) { unsigned char c; int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return ZIP_OK; } else { if (ZERROR64(*pzlib_filefunc_def,filestream)) return ZIP_ERRNO; else return ZIP_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int zip64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) { uLong x ; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<16; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int zip64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) { ZPOS64_T x; int i = 0; int err; err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x = (ZPOS64_T)i; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<8; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<16; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<24; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<32; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<40; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<48; if (err==ZIP_OK) err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); x += ((ZPOS64_T)i)<<56; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+(unsigned)i; break; } if (uPosFound!=0) break; } free(buf); return uPosFound; } /* Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before the global comment) */ local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; ZPOS64_T uSizeFile; ZPOS64_T uBackRead; ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ ZPOS64_T uPosFound=0; uLong uL; ZPOS64_T relativeOffset; if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) { // Signature "0x07064b50" Zip64 end of central directory locater if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) { uPosFound = uReadPos+(unsigned)i; break; } } if (uPosFound!=0) break; } free(buf); if (uPosFound == 0) return 0; /* Zip64 end of central directory locator */ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature, already checked */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; /* number of the disk with the start of the zip64 end of central directory */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 0) return 0; /* relative offset of the zip64 end of central directory record */ if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) return 0; /* total number of disks */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 1) return 0; /* Goto Zip64 end of central directory record */ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) return 0; /* the signature */ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) return 0; if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' return 0; return relativeOffset; } local int LoadCentralDirectoryRecord(zip64_internal* pziinit) { int err=ZIP_OK; ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ ZPOS64_T size_central_dir; /* size of the central directory */ ZPOS64_T offset_central_dir; /* offset of start of central directory */ ZPOS64_T central_pos; uLong uL; uLong number_disk; /* number of the current disk, used for spanning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number of the disk with central dir, used for spanning ZIP, unsupported, always 0*/ ZPOS64_T number_entry; ZPOS64_T number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ uLong VersionMadeBy; uLong VersionNeeded; uLong size_comment; int hasZIP64Record = 0; // check first if we find a ZIP64 record central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); if(central_pos > 0) { hasZIP64Record = 1; } else if(central_pos == 0) { central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); } /* disable to allow appending to empty ZIP archive if (central_pos==0) err=ZIP_ERRNO; */ if(hasZIP64Record) { ZPOS64_T sizeEndOfCentralDirectory; if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* size of zip64 end of central directory record */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) err=ZIP_ERRNO; /* version made by */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) err=ZIP_ERRNO; /* version needed to extract */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central directory on this disk */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central directory */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) err=ZIP_ERRNO; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) err=ZIP_ERRNO; // TODO.. // read the comment from the standard central header. size_comment = 0; } else { // Read End of central Directory info if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=ZIP_ERRNO; /* the signature, already checked */ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central dir on this disk */ number_entry = 0; if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else number_entry = uL; /* total number of entries in the central dir */ number_entry_CD = 0; if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else number_entry_CD = uL; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ size_central_dir = 0; if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else size_central_dir = uL; /* offset of start of central directory with respect to the starting disk number */ offset_central_dir = 0; if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) err=ZIP_ERRNO; else offset_central_dir = uL; /* zipfile global comment length */ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) err=ZIP_ERRNO; } if ((central_posz_filefunc, pziinit->filestream); return ZIP_ERRNO; } if (size_comment>0) { pziinit->globalcomment = (char*)ALLOC(size_comment+1); if (pziinit->globalcomment) { size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); pziinit->globalcomment[size_comment]=0; } } byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); pziinit->add_position_when_writing_offset = byte_before_the_zipfile; { ZPOS64_T size_central_dir_to_read = size_central_dir; size_t buf_size = SIZEDATA_INDATABLOCK; void* buf_read = (void*)ALLOC(buf_size); if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; while ((size_central_dir_to_read>0) && (err==ZIP_OK)) { ZPOS64_T read_this = SIZEDATA_INDATABLOCK; if (read_this > size_central_dir_to_read) read_this = size_central_dir_to_read; if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) err=ZIP_ERRNO; if (err==ZIP_OK) err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); size_central_dir_to_read-=read_this; } free(buf_read); } pziinit->begin_pos = byte_before_the_zipfile; pziinit->number_entry = number_entry_CD; if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; return err; } #endif /* !NO_ADDFILEINEXISTINGZIP*/ /************************************************************/ extern zipFile ZEXPORT zipOpen3(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) { zip64_internal ziinit; zip64_internal* zi; int err=ZIP_OK; ziinit.z_filefunc.zseek32_file = NULL; ziinit.z_filefunc.ztell32_file = NULL; if (pzlib_filefunc64_32_def==NULL) fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); else ziinit.z_filefunc = *pzlib_filefunc64_32_def; ziinit.filestream = ZOPEN64(ziinit.z_filefunc, pathname, (append == APPEND_STATUS_CREATE) ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); if (ziinit.filestream == NULL) return NULL; if (append == APPEND_STATUS_CREATEAFTER) ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; ziinit.add_position_when_writing_offset = 0; init_linkedlist(&(ziinit.central_dir)); zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); if (zi==NULL) { ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); return NULL; } /* now we add file in a zipfile */ # ifndef NO_ADDFILEINEXISTINGZIP ziinit.globalcomment = NULL; if (append == APPEND_STATUS_ADDINZIP) { // Read and Cache Central Directory Records err = LoadCentralDirectoryRecord(&ziinit); } if (globalcomment) { *globalcomment = ziinit.globalcomment; } # endif /* !NO_ADDFILEINEXISTINGZIP*/ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP free(ziinit.globalcomment); # endif /* !NO_ADDFILEINEXISTINGZIP*/ free(zi); return NULL; } else { *zi = ziinit; return (zipFile)zi; } } extern zipFile ZEXPORT zipOpen2(const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) { if (pzlib_filefunc32_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(pathname, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) { if (pzlib_filefunc_def != NULL) { zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; zlib_filefunc64_32_def_fill.ztell32_file = NULL; zlib_filefunc64_32_def_fill.zseek32_file = NULL; return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); } else return zipOpen3(pathname, append, globalcomment, NULL); } extern zipFile ZEXPORT zipOpen(const char* pathname, int append) { return zipOpen3((const void*)pathname,append,NULL,NULL); } extern zipFile ZEXPORT zipOpen64(const void* pathname, int append) { return zipOpen3(pathname,append,NULL,NULL); } local int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) { /* write the local header */ int err; uInt size_filename = (uInt)strlen(filename); uInt size_extrafield = size_extrafield_local; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ } if (err==ZIP_OK) { if(zi->ci.zip64) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); if(zi->ci.zip64) { size_extrafield += 20; } if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); if ((err==ZIP_OK) && (size_filename > 0)) { if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) err = ZIP_ERRNO; } if ((err==ZIP_OK) && (size_extrafield_local > 0)) { if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) err = ZIP_ERRNO; } if ((err==ZIP_OK) && (zi->ci.zip64)) { // write the Zip64 extended info short HeaderID = 1; short DataSize = 16; ZPOS64_T CompressedSize = 0; ZPOS64_T UncompressedSize = 0; // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)HeaderID,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)DataSize,2); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); } return err; } /* NOTE. When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped before calling this function it can be done with zipRemoveExtraInfoBlock It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize unnecessary allocations. */ extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64) { zip64_internal* zi; uInt size_filename; uInt size_comment; uInt i; int err = ZIP_OK; # ifdef NOCRYPT (crcForCrypting); if (password != NULL) return ZIP_PARAMERROR; # endif if (file == NULL) return ZIP_PARAMERROR; #ifdef HAVE_BZIP2 if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) return ZIP_PARAMERROR; #else if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; #endif // The filename and comment length must fit in 16 bits. if ((filename!=NULL) && (strlen(filename)>0xffff)) return ZIP_PARAMERROR; if ((comment!=NULL) && (strlen(comment)>0xffff)) return ZIP_PARAMERROR; // The extra field length must fit in 16 bits. If the member also requires // a Zip64 extra block, that will also need to fit within that 16-bit // length, but that will be checked for later. if ((size_extrafield_local>0xffff) || (size_extrafield_global>0xffff)) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); if (err != ZIP_OK) return err; } if (filename==NULL) filename="-"; if (comment==NULL) size_comment = 0; else size_comment = (uInt)strlen(comment); size_filename = (uInt)strlen(filename); if (zipfi == NULL) zi->ci.dosDate = 0; else { if (zipfi->dosDate != 0) zi->ci.dosDate = zipfi->dosDate; else zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); } zi->ci.flag = flagBase; if ((level==8) || (level==9)) zi->ci.flag |= 2; if (level==2) zi->ci.flag |= 4; if (level==1) zi->ci.flag |= 6; if (password != NULL) zi->ci.flag |= 1; zi->ci.crc32 = 0; zi->ci.method = method; zi->ci.encrypt = 0; zi->ci.stream_initialised = 0; zi->ci.pos_in_buffered_data = 0; zi->ci.raw = raw; zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); zi->ci.size_centralExtra = size_extrafield_global; zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); /* version info */ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ if (zipfi==NULL) zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); else zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); if (zipfi==NULL) zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); else zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); if(zi->ci.pos_local_header >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); else zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writing_offset,4); for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = *(((const char*)extrafield_global)+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ size_extrafield_global+i) = *(comment+i); if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; zi->ci.zip64 = zip64; zi->ci.totalCompressedData = 0; zi->ci.totalUncompressedData = 0; zi->ci.pos_zip64extrainfo = 0; err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); #ifdef HAVE_BZIP2 zi->ci.bstream.avail_in = (uInt)0; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; zi->ci.bstream.total_in_hi32 = 0; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_out_hi32 = 0; zi->ci.bstream.total_out_lo32 = 0; #endif zi->ci.stream.avail_in = (uInt)0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; zi->ci.stream.total_in = 0; zi->ci.stream.total_out = 0; zi->ci.stream.data_type = Z_BINARY; #ifdef HAVE_BZIP2 if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) #else if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) #endif { if(zi->ci.method == Z_DEFLATED) { zi->ci.stream.zalloc = (alloc_func)0; zi->ci.stream.zfree = (free_func)0; zi->ci.stream.opaque = (voidpf)0; if (windowBits>0) windowBits = -windowBits; err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); if (err==Z_OK) zi->ci.stream_initialised = Z_DEFLATED; } else if(zi->ci.method == Z_BZIP2ED) { #ifdef HAVE_BZIP2 // Init BZip stuff here zi->ci.bstream.bzalloc = 0; zi->ci.bstream.bzfree = 0; zi->ci.bstream.opaque = (voidpf)0; err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); if(err == BZ_OK) zi->ci.stream_initialised = Z_BZIP2ED; #endif } } # ifndef NOCRYPT zi->ci.crypt_header_size = 0; if ((err==Z_OK) && (password != NULL)) { unsigned char bufHead[RAND_HEAD_LEN]; unsigned int sizeHead; zi->ci.encrypt = 1; zi->ci.pcrc_32_tab = get_crc_table(); /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); zi->ci.crypt_header_size = sizeHead; if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) err = ZIP_ERRNO; } # endif if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, versionMadeBy, flagBase, 0); } extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits,int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, windowBits, memLevel, strategy, password, crcForCrypting, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, zip64); } extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void*extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level) { return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0, VERSIONMADEBY, 0, 0); } local int zip64FlushWriteBuffer(zip64_internal* zi) { int err=ZIP_OK; if (zi->ci.encrypt != 0) { #ifndef NOCRYPT uInt i; int t; for (i=0;ici.pos_in_buffered_data;i++) zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); #endif } if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) err = ZIP_ERRNO; zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; #ifdef HAVE_BZIP2 if(zi->ci.method == Z_BZIP2ED) { zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; zi->ci.bstream.total_in_lo32 = 0; zi->ci.bstream.total_in_hi32 = 0; } else #endif { zi->ci.totalUncompressedData += zi->ci.stream.total_in; zi->ci.stream.total_in = 0; } zi->ci.pos_in_buffered_data = 0; return err; } extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void* buf, unsigned int len) { zip64_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); #ifdef HAVE_BZIP2 if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) { zi->ci.bstream.next_in = (void*)buf; zi->ci.bstream.avail_in = len; err = BZ_RUN_OK; while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) { if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; } if(err != BZ_RUN_OK) break; if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; // uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; } } if(err == BZ_RUN_OK) err = ZIP_OK; } else #endif { zi->ci.stream.next_in = (Bytef*)(uintptr_t)buf; zi->ci.stream.avail_in = len; while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) { if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if(err != ZIP_OK) break; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } else { uInt copy_this,i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) copy_this = zi->ci.stream.avail_in; else copy_this = zi->ci.stream.avail_out; for (i = 0; i < copy_this; i++) *(((char*)zi->ci.stream.next_out)+i) = *(((const char*)zi->ci.stream.next_in)+i); { zi->ci.stream.avail_in -= copy_this; zi->ci.stream.avail_out-= copy_this; zi->ci.stream.next_in+= copy_this; zi->ci.stream.next_out+= copy_this; zi->ci.stream.total_in+= copy_this; zi->ci.stream.total_out+= copy_this; zi->ci.pos_in_buffered_data += copy_this; } } }// while(...) } return err; } extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32) { return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); } extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32) { zip64_internal* zi; ZPOS64_T compressed_size; uLong invalidValue = 0xffffffff; unsigned datasize = 0; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.avail_in = 0; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { while (err==ZIP_OK) { uLong uTotalOutBefore; if (zi->ci.stream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_FINISH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } } else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { #ifdef HAVE_BZIP2 err = BZ_FINISH_OK; while (err==BZ_FINISH_OK) { uLong uTotalOutBefore; if (zi->ci.bstream.avail_out == 0) { if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; } uTotalOutBefore = zi->ci.bstream.total_out_lo32; err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); if(err == BZ_STREAM_END) err = Z_STREAM_END; zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); } if(err == BZ_FINISH_OK) err = ZIP_OK; #endif } if (err==Z_STREAM_END) err=ZIP_OK; /* this is normal */ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) { if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) err = ZIP_ERRNO; } if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { int tmp_err = deflateEnd(&zi->ci.stream); if (err == ZIP_OK) err = tmp_err; zi->ci.stream_initialised = 0; } #ifdef HAVE_BZIP2 else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) { int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); if (err==ZIP_OK) err = tmperr; zi->ci.stream_initialised = 0; } #endif if (!zi->ci.raw) { crc32 = (uLong)zi->ci.crc32; uncompressed_size = zi->ci.totalUncompressedData; } compressed_size = zi->ci.totalCompressedData; # ifndef NOCRYPT compressed_size += zi->ci.crypt_header_size; # endif // update Current Item crc and sizes, if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) { /*version Made by*/ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); /*version needed*/ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); } zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ if(compressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ else zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ /// set internal file attributes field if (zi->ci.stream.data_type == Z_ASCII) zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); if(uncompressed_size >= 0xffffffff) zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ else zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ // Add ZIP64 extra info field for uncompressed size if(uncompressed_size >= 0xffffffff) datasize += 8; // Add ZIP64 extra info field for compressed size if(compressed_size >= 0xffffffff) datasize += 8; // Add ZIP64 extra info field for relative offset to local file header of current file if(zi->ci.pos_local_header >= 0xffffffff) datasize += 8; if(datasize > 0) { char* p = NULL; if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) { // we cannot write more data to the buffer that we have room for. return ZIP_BADZIPFILE; } p = zi->ci.central_header + zi->ci.size_centralheader; // Add Extra Information Header for 'ZIP64 information' zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID p += 2; zip64local_putValue_inmemory(p, datasize, 2); // DataSize p += 2; if(uncompressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, uncompressed_size, 8); p += 8; } if(compressed_size >= 0xffffffff) { zip64local_putValue_inmemory(p, compressed_size, 8); p += 8; } if(zi->ci.pos_local_header >= 0xffffffff) { zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); p += 8; } // Update how much extra free space we got in the memory buffer // and increase the centralheader size so the new ZIP64 fields are included // ( 4 below is the size of HeaderID and DataSize field ) zi->ci.size_centralExtraFree -= datasize + 4; zi->ci.size_centralheader += datasize + 4; // Update the extra info size field zi->ci.size_centralExtra += datasize + 4; zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); } if (err==ZIP_OK) err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); free(zi->ci.central_header); if (err==ZIP_OK) { // Update the LocalFileHeader with the new values. ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff ) { if(zi->ci.pos_zip64extrainfo > 0) { // Update the size in the ZIP64 extended field. if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); } else err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal } else { if (err==ZIP_OK) /* compressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); } if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; } zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipCloseFileInZip(zipFile file) { return zipCloseFileInZipRaw (file,0,0); } local int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) { int err = ZIP_OK; ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); /*num disks*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /*relative offset*/ if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); return err; } local int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; uLong Zip64DataSize = 44; err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? if (err==ZIP_OK) /* version made by */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); if (err==ZIP_OK) /* version needed */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); if (err==ZIP_OK) /* number of this disk */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); if (err==ZIP_OK) /* total number of entries in the central dir */ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); if (err==ZIP_OK) /* size of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); } return err; } local int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) { int err = ZIP_OK; /*signature*/ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); if (err==ZIP_OK) /* number of this disk */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ { { if(zi->number_entry >= 0xFFFF) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); } } if (err==ZIP_OK) /* total number of entries in the central dir */ { if(zi->number_entry >= 0xFFFF) err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record else err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); } if (err==ZIP_OK) /* size of the central directory */ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ { ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; if(pos >= 0xffffffff) { err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); } else err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4); } return err; } local int Write_GlobalComment(zip64_internal* zi, const char* global_comment) { int err = ZIP_OK; uInt size_global_comment = 0; if(global_comment != NULL) size_global_comment = (uInt)strlen(global_comment); err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); if (err == ZIP_OK && size_global_comment > 0) { if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) err = ZIP_ERRNO; } return err; } extern int ZEXPORT zipClose(zipFile file, const char* global_comment) { zip64_internal* zi; int err = 0; uLong size_centraldir = 0; ZPOS64_T centraldir_pos_inzip; ZPOS64_T pos; if (file == NULL) return ZIP_PARAMERROR; zi = (zip64_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); } #ifndef NO_ADDFILEINEXISTINGZIP if (global_comment==NULL) global_comment = zi->globalcomment; #endif centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); if (err==ZIP_OK) { linkedlist_datablock_internal* ldi = zi->central_dir.first_block; while (ldi!=NULL) { if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) { if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) err = ZIP_ERRNO; } size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_linkedlist(&(zi->central_dir)); pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; if(pos >= 0xffffffff || zi->number_entry >= 0xFFFF) { ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); } if (err==ZIP_OK) err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); if(err == ZIP_OK) err = Write_GlobalComment(zi, global_comment); if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) if (err == ZIP_OK) err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP free(zi->globalcomment); #endif free(zi); return err; } extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader) { char* p = pData; int size = 0; char* pNewHeader; char* pTmp; short header; short dataSize; int retVal = ZIP_OK; if(pData == NULL || dataLen == NULL || *dataLen < 4) return ZIP_PARAMERROR; pNewHeader = (char*)ALLOC((unsigned)*dataLen); pTmp = pNewHeader; while(p < (pData + *dataLen)) { header = *(short*)p; dataSize = *(((short*)p)+1); if( header == sHeader ) // Header found. { p += dataSize + 4; // skip it. do not copy to temp buffer } else { // Extra Info block should not be removed, So copy it to the temp buffer. memcpy(pTmp, p, dataSize + 4); p += dataSize + 4; size += dataSize + 4; } } if(size < *dataLen) { // clean old extra info block. memset(pData,0, *dataLen); // copy the new extra info block over the old if(size > 0) memcpy(pData, pNewHeader, size); // set the new extra info size *dataLen = size; retVal = ZIP_OK; } else retVal = ZIP_ERRNO; free(pNewHeader); return retVal; } mupen64plus-core-src-2.6.0/subprojects/minizip/zip.h000066400000000000000000000362351464506436200224540ustar00rootroot00000000000000/* zip.h -- IO on .zip files using zlib Version 1.1, February 14h, 2010 part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) Modifications for Zip64 support Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) For more info read MiniZip_info.txt --------------------------------------------------------------------------- Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. --------------------------------------------------------------------------- Changes See header of zip.h */ #ifndef _zip12_H #define _zip12_H #ifdef __cplusplus extern "C" { #endif //#define HAVE_BZIP2 #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #ifdef HAVE_BZIP2 #include "bzlib.h" #endif #define Z_BZIP2ED 12 #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagzipFile__ { int unused; } zipFile__; typedef zipFile__ *zipFile; #else typedef voidp zipFile; #endif #define ZIP_OK (0) #define ZIP_EOF (0) #define ZIP_ERRNO (Z_ERRNO) #define ZIP_PARAMERROR (-102) #define ZIP_BADZIPFILE (-103) #define ZIP_INTERNALERROR (-104) #ifndef DEF_MEM_LEVEL # if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 # else # define DEF_MEM_LEVEL MAX_MEM_LEVEL # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ /* uLong flag; */ /* general purpose bit flag 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) extern zipFile ZEXPORT zipOpen(const char *pathname, int append); extern zipFile ZEXPORT zipOpen64(const void *pathname, int append); /* Create a zipfile. pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip will be created at the end of the file. (useful if the file contain a self extractor code) if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will add files in existing zip (be sure you don't add file that doesn't exist) If the zipfile cannot be opened, the return value is NULL. Else, the return value is a zipFile Handle, usable with other function of this zip package. */ /* Note : there is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another Of course, you can use RAW reading and writing to copy the file you did not want delete */ extern zipFile ZEXPORT zipOpen2(const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def); extern zipFile ZEXPORT zipOpen2_64(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def); extern zipFile ZEXPORT zipOpen3(const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def); extern int ZEXPORT zipOpenNewFileInZip(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level); extern int ZEXPORT zipOpenNewFileInZip64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int zip64); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data for the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data for the global header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) zip64 is set to 1 if a zip64 extended information block should be added to the local file header. this MUST be '1' if the uncompressed size is >= 0xffffffff. */ extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw); extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int zip64); /* Same than zipOpenNewFileInZip, except if raw=1, we write raw file */ extern int ZEXPORT zipOpenNewFileInZip3(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting); extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, int zip64); /* Same than zipOpenNewFileInZip2, except windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 password : crypting password (NULL for no crypting) crcForCrypting : crc of file to compress (needed for crypting) */ extern int ZEXPORT zipOpenNewFileInZip4(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase); extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting, uLong versionMadeBy, uLong flagBase, int zip64); /* Same than zipOpenNewFileInZip4, except versionMadeBy : value for Version made by field flag : value for flag field (compression level info will be added) */ extern int ZEXPORT zipWriteInFileInZip(zipFile file, const void* buf, unsigned len); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip(zipFile file); /* Close the current file in the zipfile */ extern int ZEXPORT zipCloseFileInZipRaw(zipFile file, uLong uncompressed_size, uLong crc32); extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file, ZPOS64_T uncompressed_size, uLong crc32); /* Close the current file in the zipfile, for file opened with parameter raw=1 in zipOpenNewFileInZip2 uncompressed_size and crc32 are value for the uncompressed size */ extern int ZEXPORT zipClose(zipFile file, const char* global_comment); /* Close the zipfile */ extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader); /* zipRemoveExtraInfoBlock - Added by Mathias Svensson Remove extra information block from a extra information data for the local file header or central directory header It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. 0x0001 is the signature header for the ZIP64 extra information blocks usage. Remove ZIP64 Extra information from a central director extra field data zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); Remove ZIP64 Extra information from a Local File Header extra field data zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); */ #ifdef __cplusplus } #endif #endif /* _zip64_H */ mupen64plus-core-src-2.6.0/subprojects/oglft/000077500000000000000000000000001464506436200211245ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/subprojects/oglft/OGLFT.cpp000066400000000000000000001152571464506436200225160ustar00rootroot00000000000000/* * OGLFT: A library for drawing text with OpenGL using the FreeType library * Copyright (C) 2002 lignum Computing, Inc. * $Id: OGLFT.cpp,v 1.11 2003/10/01 14:21:18 allen Exp $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include "OGLFT.h" int wstrlen(const wchar_t * s) { int r = 0; while (*s++) r++; return r; } namespace OGLFT { FT_Library ft_library; bool Init_FT(void) { FT_Error error = FT_Init_FreeType(&ft_library); if(error != 0) std::cerr << "[OGLFT] Could not initialize the FreeType library." << std::endl; return (error == 0); } bool Uninit_FT(void) { FT_Error error = FT_Done_FreeType(ft_library); if(error != 0) std::cerr << "[OGLFT] Could not terminate the FreeType library." << std::endl; return (error == 0); } // Load a new face Face::Face (const char* filename, float point_size, FT_UInt resolution) : point_size_(point_size), resolution_(resolution) { valid_ = true; FT_Face ft_face; FT_Error error = FT_New_Face(ft_library, filename, 0, &ft_face); if(error != 0) { valid_ = false; return; } // As of FreeType 2.1: only a UNICODE charmap is automatically activated. // If no charmap is activated automatically, just use the first one. if(ft_face->charmap == 0 && ft_face->num_charmaps > 0) FT_Select_Charmap(ft_face, ft_face->charmaps[0]->encoding); faces_.push_back(FaceData(ft_face)); init(); } // Go with a face that the user has already opened. Face::Face (FT_Face face, float point_size, FT_UInt resolution) : point_size_(point_size), resolution_(resolution) { valid_ = true; // As of FreeType 2.1: only a UNICODE charmap is automatically activated. // If no charmap is activated automatically, just use the first one. if(face->charmap == 0 && face->num_charmaps > 0) FT_Select_Charmap(face, face->charmaps[0]->encoding); faces_.push_back(FaceData(face, false)); init(); } // Standard initialization behavior once the font file is opened. void Face::init (void) { // By default, each glyph is compiled into a display list the first // time it is encountered compile_mode_ = COMPILE; // By default, all drawing is wrapped with push/pop matrix so that the // MODELVIEW matrix is not modified. If advance_ is set, then subsequent // drawings follow from the advance of the last glyph rendered. advance_ = false; // Initialize the default colors foreground_color_[R] = 0.; foreground_color_[G] = 0.; foreground_color_[B] = 0.; foreground_color_[A] = 1.; background_color_[R] = 1.; background_color_[G] = 1.; background_color_[B] = 1.; background_color_[A] = 0.; // The default positioning of the text is at the origin of the first glyph horizontal_justification_ = ORIGIN; vertical_justification_ = BASELINE; // By default, strings are rendered in their nominal direction string_rotation_ = 0; // setCharacterRotationReference calls the virtual function clearCaches() // so it is up to a subclass to set the real default rotation_reference_glyph_ = 0; rotation_reference_face_ = 0; rotation_offset_y_ = 0.; } Face::~Face (void) { for(unsigned int i=0; iglyph, &glyph); if(error != 0) continue; FT_BBox ft_bbox; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox); FT_Done_Glyph(glyph); char_bbox = ft_bbox; char_bbox.advance_ = faces_[f].face_->glyph->advance; bbox += char_bbox; } return bbox; } BBox Face::measure (const wchar_t* s) { BBox bbox; int i; if(wstrlen(s) > 0) { bbox = measure(s[0]); for(i = 1; i < wstrlen(s); i++) { BBox char_bbox = measure(s[i]); bbox += char_bbox; } } // make sure the origin is at 0,0 if (bbox.x_min_ != 0) { bbox.x_max_ -= bbox.x_min_; bbox.x_min_ = 0; } if (bbox.y_min_ != 0) { bbox.y_max_ -= bbox.y_min_; bbox.y_min_ = 0; } return bbox; } BBox Face::measureRaw (const wchar_t* s) { BBox bbox; int i; for(i = 0; i < wstrlen(s); i++) { BBox char_bbox; unsigned int f; FT_UInt glyph_index = 0; for(f=0; fglyph, &glyph); if(error != 0) continue; FT_BBox ft_bbox; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox); FT_Done_Glyph(glyph); char_bbox = ft_bbox; char_bbox.advance_ = faces_[f].face_->glyph->advance; bbox += char_bbox; } return bbox; } // Measure the bounding box as if the (latin1) string were not rotated BBox Face::measure_nominal (const char* s) { if(string_rotation_ == 0.) return measure(s); for(unsigned int f=0; fsecond; unsigned int f; FT_UInt glyph_index = 0; for(f=0; fsecond; unsigned int f; FT_UInt glyph_index = 0; for(f=0; fsecond); return; } unsigned int f; FT_UInt glyph_index = 0; for(f=0; fsecond); return; } unsigned int f; FT_UInt glyph_index = 0; for(f=0; fheight > 0) return faces_[0].face_->height / 64.; else return faces_[0].face_->size->metrics.y_ppem; } BBox Raster::measure (unsigned char c) { BBox bbox; // For starters, just get the unscaled glyph bounding box unsigned int f; FT_UInt glyph_index = 0; for(f=0; fglyph, &glyph); if(error != 0) return bbox; FT_BBox ft_bbox; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox); FT_Done_Glyph(glyph); bbox = ft_bbox; bbox.advance_ = faces_[f].face_->glyph->advance; // In order to be accurate regarding the placement of text not // aligned at the glyph's origin (CENTER/MIDDLE), the bounding box // of the raster format has to be projected back into the // view's coordinates GLint viewport[4]; GLdouble modelview[16], projection[16]; glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); // Well, first we have to get the Origin, since that is the basis // of the bounding box GLdouble x0, y0, z0; gluUnProject(0., 0., 0., modelview, projection, viewport, &x0, &y0, &z0); GLdouble x, y, z; gluUnProject(bbox.x_min_, bbox.y_min_, 0., modelview, projection, viewport, &x, &y, &z); bbox.x_min_ = (float) (x - x0); bbox.y_min_ = (float) (y - y0); gluUnProject(bbox.x_max_, bbox.y_max_, 0., modelview, projection, viewport, &x, &y, &z); bbox.x_max_ = (float) (x - x0); bbox.y_max_ = (float) (y - y0); gluUnProject(bbox.advance_.dx_, bbox.advance_.dy_, 0., modelview, projection, viewport, &x, &y, &z); bbox.advance_.dx_ = (float) (x - x0); bbox.advance_.dy_ = (float) (y - y0); return bbox; } BBox Raster::measure (wchar_t c) { BBox bbox; // For starters, just get the unscaled glyph bounding box unsigned int f; FT_UInt glyph_index = 0; for(f=0; fglyph, &glyph); if(error != 0) return bbox; FT_BBox ft_bbox; FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &ft_bbox); FT_Done_Glyph(glyph); bbox = ft_bbox; bbox.advance_ = faces_[f].face_->glyph->advance; // In order to be accurate regarding the placement of text not // aligned at the glyph's origin (CENTER/MIDDLE), the bounding box // of the raster format has to be projected back into the // view's coordinates GLint viewport[4]; GLdouble modelview[16], projection[16]; glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); // Well, first we have to get the Origin, since that is the basis // of the bounding box GLdouble x0, y0, z0; gluUnProject(0., 0., 0., modelview, projection, viewport, &x0, &y0, &z0); GLdouble x, y, z; gluUnProject(bbox.x_min_, bbox.y_min_, 0., modelview, projection, viewport, &x, &y, &z); bbox.x_min_ = (float) (x - x0); bbox.y_min_ = (float) (y - y0); gluUnProject(bbox.x_max_, bbox.y_max_, 0., modelview, projection, viewport, &x, &y, &z); bbox.x_max_ = (float) (x - x0); bbox.y_max_ = (float) (y - y0); gluUnProject(bbox.advance_.dx_, bbox.advance_.dy_, 0., modelview, projection, viewport, &x, &y, &z); bbox.advance_.dx_ = (float) (x - x0); bbox.advance_.dy_ = (float) (y - y0); return bbox; } GLuint Raster::compileGlyph (FT_Face face, FT_UInt glyph_index) { GLuint dlist = glGenLists(1); glNewList(dlist, GL_COMPILE); renderGlyph(face, glyph_index); glEndList(); return dlist; } void Raster::setCharSize (void) { FT_Error error; for(unsigned int i=0; iglyph->bitmap.rows / 2.0f; } void Raster::clearCaches (void) { GDLI fgi = glyph_dlists_.begin(); for(; fgi != glyph_dlists_.end(); ++fgi) { glDeleteLists(fgi->second, 1); } glyph_dlists_.clear(); } Monochrome::Monochrome (const char* filename, float point_size, FT_UInt resolution) : Raster(filename, point_size, resolution) { return; } Monochrome::Monochrome (FT_Face face, float point_size, FT_UInt resolution) : Raster(face, point_size, resolution) { return; } Monochrome::~Monochrome (void) { return; } GLubyte* Monochrome::invertBitmap (const FT_Bitmap& bitmap) { // In FreeType 2.0.9, the pitch of bitmaps was rounded up to an // even number. In general, this disagrees with what we had been // using for OpenGL. int width = bitmap.width / 8 + ((bitmap.width & 7)> 0 ? 1 : 0); GLubyte* inverse = new GLubyte[ bitmap.rows * width ]; GLubyte* inverse_ptr = inverse; for(unsigned int r=0; rglyph, &original_glyph); if(error != 0) return; error = FT_Glyph_Copy(original_glyph, &glyph); FT_Done_Glyph(original_glyph); if(error != 0) return; // If the individual characters are rotated (as distinct from string // rotation), then apply that extra rotation here. This is equivalent // to the sequence // glTranslate(x_center,y_center); // glRotate(angle); // glTranslate(-x_center,-y_center); // which is used for the polygonal styles. The deal with the raster // styles is that you must retain the advance from the string rotation // so that the glyphs are laid out properly. So, we make a copy of // the string rotated glyph, and then rotate that and add back an // additional offset to (in effect) restore the proper origin and // advance of the glyph. if(character_rotation_z_ != 0.) { FT_Matrix rotation_matrix; FT_Vector sinus; FT_Vector_Unit(&sinus, (FT_Angle)(character_rotation_z_ * 0x10000L)); rotation_matrix.xx = sinus.x; rotation_matrix.xy = -sinus.y; rotation_matrix.yx = sinus.y; rotation_matrix.yy = sinus.x; FT_Vector original_offset, rotation_offset; original_offset.x = (face->glyph->metrics.width / 2 + face->glyph->metrics.horiBearingX)/ 64 * 0x10000L; original_offset.y = (FT_Pos)(rotation_offset_y_ * 0x10000L); rotation_offset = original_offset; FT_Vector_Rotate(&rotation_offset, (FT_Angle)(character_rotation_z_ * 0x10000L)); rotation_offset.x = original_offset.x - rotation_offset.x; rotation_offset.y = original_offset.y - rotation_offset.y; rotation_offset.x /= 1024; rotation_offset.y /= 1024; error = FT_Glyph_Transform(glyph, &rotation_matrix, &rotation_offset); } error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_MONO, 0, 1); if(error != 0) { FT_Done_Glyph(glyph); return; } FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph) glyph; // Evidently, in FreeType2, you can only get "upside-down" bitmaps and // OpenGL won't invert a bitmap with PixelZoom, so we have to invert the // glyph's bitmap ourselves. GLubyte* inverted_bitmap = invertBitmap(bitmap_glyph->bitmap); glBitmap(bitmap_glyph->bitmap.width, bitmap_glyph->bitmap.rows, (GLfloat) -bitmap_glyph->left, (GLfloat) (bitmap_glyph->bitmap.rows - bitmap_glyph->top), face->glyph->advance.x / 64.0f, face->glyph->advance.y / 64.0f, inverted_bitmap); FT_Done_Glyph(glyph); delete[] inverted_bitmap; } } // close OGLFT namespace mupen64plus-core-src-2.6.0/subprojects/oglft/OGLFT.h000066400000000000000000000271731464506436200221620ustar00rootroot00000000000000// -*- c++ -*- /* * OGLFT: A library for drawing text with OpenGL using the FreeType library * Copyright (C) 2002 lignum Computing, Inc. * $Id: OGLFT.h,v 1.15 2003/10/01 14:41:09 allen Exp $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef OGLFT_H #define OGLFT_H #include #include #include #include #include #define GL_GLEXT_PROTOTYPES #include #if defined(__MACOSX__) #include #elif defined(__MACOS__) #include #else #include #endif #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_OUTLINE_H #include FT_TRIGONOMETRY_H namespace OGLFT { enum Coordinates { X, Y, Z, W }; enum ColorSpace { R, G, B, A }; // global library functions bool Init_FT(void); bool Uninit_FT(void); struct Advance { float dx_; float dy_; Advance ( float dx = 0, float dy = 0 ) : dx_( dx ), dy_( dy ) { return; } Advance ( FT_Vector v ) { dx_ = (float) (v.x / 64.); dy_ = (float) (v.y / 64.); } Advance& operator+= ( const FT_Vector v ) { dx_ += (float) (v.x / 64.); dy_ += (float) (v.y / 64.); return *this; } }; struct BBox { float x_min_; float y_min_; float x_max_; float y_max_; Advance advance_; BBox () : x_min_( 0 ), y_min_( 0 ), x_max_( 0 ), y_max_( 0 ) { return; } BBox ( FT_BBox ft_bbox ) { x_min_ = (float) (ft_bbox.xMin / 64.); y_min_ = (float) (ft_bbox.yMin / 64.); x_max_ = (float) (ft_bbox.xMax / 64.); y_max_ = (float) (ft_bbox.yMax / 64.); } BBox& operator*= ( double k ) { x_min_ *= (float) k; y_min_ *= (float) k; x_max_ *= (float) k; y_max_ *= (float) k; advance_.dx_ *= (float) k; advance_.dy_ *= (float) k; return *this; } BBox& operator+= ( const BBox& b ) { float new_value; new_value = b.x_min_ + advance_.dx_; if ( new_value < x_min_ ) x_min_ = new_value; new_value = b.y_min_ + advance_.dy_; if ( new_value < y_min_ ) y_min_ = new_value; new_value = b.x_max_ + advance_.dx_; if ( new_value > x_max_ ) x_max_ = new_value; new_value = b.y_max_ + advance_.dy_; if ( new_value > y_max_ ) y_max_ = new_value; advance_.dx_ += b.advance_.dx_; advance_.dy_ += b.advance_.dy_; return *this; } }; typedef std::vector DisplayLists; typedef DisplayLists::const_iterator DLCI; typedef DisplayLists::iterator DLI; class Face { public: enum HorizontalJustification { LEFT, ORIGIN, CENTER, RIGHT }; enum VerticalJustification { BOTTOM, BASELINE, MIDDLE, TOP }; enum GlyphCompileMode { COMPILE, IMMEDIATE }; private: struct FaceData { FT_Face face_; bool free_on_exit_; FaceData ( FT_Face face, bool free_on_exit = true ) : face_( face ), free_on_exit_( free_on_exit ) { return; } }; protected: std::vector< FaceData > faces_; bool valid_; enum GlyphCompileMode compile_mode_; float point_size_; FT_UInt resolution_; bool advance_; GLfloat foreground_color_[4]; GLfloat background_color_[4]; enum HorizontalJustification horizontal_justification_; enum VerticalJustification vertical_justification_; GLfloat string_rotation_; FT_UInt rotation_reference_glyph_; FT_Face rotation_reference_face_; GLfloat rotation_offset_y_; typedef std::map< FT_UInt, GLuint > GlyphDLists; typedef GlyphDLists::const_iterator GDLCI; typedef GlyphDLists::iterator GDLI; GlyphDLists glyph_dlists_; DisplayLists character_display_lists_; public: Face ( const char* filename, float point_size = 12, FT_UInt resolution = 100 ); Face ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); virtual ~Face ( void ); bool isValid ( void ) const { return valid_; } bool addAuxiliaryFace ( const char* filename ); bool addAuxiliaryFace ( FT_Face face ); void setCompileMode ( enum GlyphCompileMode compile_mode ) { compile_mode_ = compile_mode; } enum GlyphCompileMode compileMode ( void ) const { return compile_mode_; } void setPointSize ( float point_size ); float pointSize ( void ) { return point_size_; } void setResolution ( FT_UInt resolution ); FT_UInt resolution ( void ) { return resolution_; } void setAdvance ( bool advance ) { advance_ = advance; } bool advance ( void ) const { return advance_; } void setForegroundColor ( GLfloat red = 0.0, GLfloat green = 0.0, GLfloat blue = 0.0, GLfloat alpha = 1.0 ); void setForegroundColor ( const GLfloat foreground_color[4] ); GLfloat foregroundRed ( void ) const { return foreground_color_[R]; } GLfloat foregroundGreen ( void ) const { return foreground_color_[G]; } GLfloat foregroundBlue ( void ) const { return foreground_color_[B]; } GLfloat foregroundAlpha ( void ) const { return foreground_color_[A]; } void setBackgroundColor ( GLfloat red = 1.0, GLfloat green = 1.0, GLfloat blue = 1.0, GLfloat alpha = 0.0 ); void setBackgroundColor ( const GLfloat background_color[4] ); GLfloat backgroundRed ( void ) const { return background_color_[R]; } GLfloat backgroundGreen ( void ) const { return background_color_[G]; } GLfloat backgroundBlue ( void ) const { return background_color_[B]; } GLfloat backgroundAlpha ( void ) const { return background_color_[A]; } virtual void setCharacterRotationZ ( GLfloat character_rotation_z ) = 0; virtual GLfloat characterRotationZ ( void ) const = 0; void setCharacterRotationReference ( unsigned char c ); void setStringRotation ( GLfloat string_rotation ); GLfloat stringRotation ( void ) const { return string_rotation_; } void setHorizontalJustification ( enum HorizontalJustification horizontal_justification ) { horizontal_justification_ = horizontal_justification; } enum HorizontalJustification horizontalJustification ( void ) const { return horizontal_justification_; } void setVerticalJustification ( enum VerticalJustification vertical_justification ) { vertical_justification_ = vertical_justification; } enum VerticalJustification verticaljustification ( void ) const { return vertical_justification_; } void setCharacterDisplayLists ( const DisplayLists& character_display_lists ) { character_display_lists_ = character_display_lists; } DisplayLists& characterDisplayLists ( void ) { return character_display_lists_; } virtual double height ( void ) const = 0; virtual BBox measure ( unsigned char c ) = 0; virtual BBox measure ( wchar_t c ) = 0; virtual BBox measure ( const char* s ); virtual BBox measureRaw ( const char* s ); virtual BBox measure ( const wchar_t* s ); virtual BBox measureRaw ( const wchar_t* s ); GLuint compile ( unsigned char c ); GLuint compile ( const wchar_t c ); void draw ( const char* s ); void draw ( const wchar_t* s ); void draw ( unsigned char c ); void draw ( const wchar_t c ); void draw ( GLfloat x, GLfloat y, unsigned char c ); void draw ( GLfloat x, GLfloat y, GLfloat z, unsigned char c ); void draw ( GLfloat x, GLfloat y, wchar_t c ); void draw ( GLfloat x, GLfloat y, GLfloat z, wchar_t c ); void draw ( GLfloat x, GLfloat y, const char* s, float *sizebox ); void draw ( GLfloat x, GLfloat y, GLfloat z, const char* s ); void draw ( GLfloat x, GLfloat y, const wchar_t* s ); void draw ( GLfloat x, GLfloat y, GLfloat z, const wchar_t* s ); int ascender ( void ) { return faces_.front().face_->ascender; } int descender ( void ) { return faces_.front().face_->descender; } BBox measure_nominal ( const char* s ); BBox measure_nominal ( const wchar_t* s ); protected: virtual GLuint compileGlyph ( FT_Face face, FT_UInt glyph_index ) = 0; virtual void renderGlyph ( FT_Face face, FT_UInt glyph_index ) = 0; virtual void setCharSize ( void ) = 0; virtual void clearCaches ( void ) = 0; virtual void setRotationOffset ( void ) = 0; private: void init ( void ); }; class Raster : public Face { protected: GLfloat character_rotation_z_; public: Raster ( const char* filename, float point_size = 12, FT_UInt resolution = 100 ); Raster ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); virtual ~Raster ( void ); void setCharacterRotationZ ( GLfloat character_rotation_z ); GLfloat characterRotationZ ( void ) const { return character_rotation_z_; } double height ( void ) const; BBox measure ( unsigned char c ); BBox measure ( wchar_t c ); BBox measure ( const char* s ) { return Face::measure( s ); } private: void init ( void ); GLuint compileGlyph ( FT_Face face, FT_UInt glyph_index ); void setCharSize ( void ); void setRotationOffset ( void ); void clearCaches ( void ); }; class Monochrome : public Raster { public: Monochrome ( const char* filename, float point_size = 12, FT_UInt resolution = 100 ); Monochrome ( FT_Face face, float point_size = 12, FT_UInt resolution = 100 ); ~Monochrome ( void ); private: GLubyte* invertBitmap ( const FT_Bitmap& bitmap ); void renderGlyph ( FT_Face face, FT_UInt glyph_index ); }; } #endif /* OGLFT_H */ mupen64plus-core-src-2.6.0/subprojects/xxhash/000077500000000000000000000000001464506436200213145ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/subprojects/xxhash/xxhash.h000066400000000000000000007562501464506436200230070ustar00rootroot00000000000000/* * xxHash - Extremely Fast Hash algorithm * Header File * Copyright (C) 2012-2021 Yann Collet * * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at: * - xxHash homepage: https://www.xxhash.com * - xxHash source repository: https://github.com/Cyan4973/xxHash */ /*! * @mainpage xxHash * * xxHash is an extremely fast non-cryptographic hash algorithm, working at RAM speed * limits. * * It is proposed in four flavors, in three families: * 1. @ref XXH32_family * - Classic 32-bit hash function. Simple, compact, and runs on almost all * 32-bit and 64-bit systems. * 2. @ref XXH64_family * - Classic 64-bit adaptation of XXH32. Just as simple, and runs well on most * 64-bit systems (but _not_ 32-bit systems). * 3. @ref XXH3_family * - Modern 64-bit and 128-bit hash function family which features improved * strength and performance across the board, especially on smaller data. * It benefits greatly from SIMD and 64-bit without requiring it. * * Benchmarks * --- * The reference system uses an Intel i7-9700K CPU, and runs Ubuntu x64 20.04. * The open source benchmark program is compiled with clang v10.0 using -O3 flag. * * | Hash Name | ISA ext | Width | Large Data Speed | Small Data Velocity | * | -------------------- | ------- | ----: | ---------------: | ------------------: | * | XXH3_64bits() | @b AVX2 | 64 | 59.4 GB/s | 133.1 | * | MeowHash | AES-NI | 128 | 58.2 GB/s | 52.5 | * | XXH3_128bits() | @b AVX2 | 128 | 57.9 GB/s | 118.1 | * | CLHash | PCLMUL | 64 | 37.1 GB/s | 58.1 | * | XXH3_64bits() | @b SSE2 | 64 | 31.5 GB/s | 133.1 | * | XXH3_128bits() | @b SSE2 | 128 | 29.6 GB/s | 118.1 | * | RAM sequential read | | N/A | 28.0 GB/s | N/A | * | ahash | AES-NI | 64 | 22.5 GB/s | 107.2 | * | City64 | | 64 | 22.0 GB/s | 76.6 | * | T1ha2 | | 64 | 22.0 GB/s | 99.0 | * | City128 | | 128 | 21.7 GB/s | 57.7 | * | FarmHash | AES-NI | 64 | 21.3 GB/s | 71.9 | * | XXH64() | | 64 | 19.4 GB/s | 71.0 | * | SpookyHash | | 64 | 19.3 GB/s | 53.2 | * | Mum | | 64 | 18.0 GB/s | 67.0 | * | CRC32C | SSE4.2 | 32 | 13.0 GB/s | 57.9 | * | XXH32() | | 32 | 9.7 GB/s | 71.9 | * | City32 | | 32 | 9.1 GB/s | 66.0 | * | Blake3* | @b AVX2 | 256 | 4.4 GB/s | 8.1 | * | Murmur3 | | 32 | 3.9 GB/s | 56.1 | * | SipHash* | | 64 | 3.0 GB/s | 43.2 | * | Blake3* | @b SSE2 | 256 | 2.4 GB/s | 8.1 | * | HighwayHash | | 64 | 1.4 GB/s | 6.0 | * | FNV64 | | 64 | 1.2 GB/s | 62.7 | * | Blake2* | | 256 | 1.1 GB/s | 5.1 | * | SHA1* | | 160 | 0.8 GB/s | 5.6 | * | MD5* | | 128 | 0.6 GB/s | 7.8 | * @note * - Hashes which require a specific ISA extension are noted. SSE2 is also noted, * even though it is mandatory on x64. * - Hashes with an asterisk are cryptographic. Note that MD5 is non-cryptographic * by modern standards. * - Small data velocity is a rough average of algorithm's efficiency for small * data. For more accurate information, see the wiki. * - More benchmarks and strength tests are found on the wiki: * https://github.com/Cyan4973/xxHash/wiki * * Usage * ------ * All xxHash variants use a similar API. Changing the algorithm is a trivial * substitution. * * @pre * For functions which take an input and length parameter, the following * requirements are assumed: * - The range from [`input`, `input + length`) is valid, readable memory. * - The only exception is if the `length` is `0`, `input` may be `NULL`. * - For C++, the objects must have the *TriviallyCopyable* property, as the * functions access bytes directly as if it was an array of `unsigned char`. * * @anchor single_shot_example * **Single Shot** * * These functions are stateless functions which hash a contiguous block of memory, * immediately returning the result. They are the easiest and usually the fastest * option. * * XXH32(), XXH64(), XXH3_64bits(), XXH3_128bits() * * @code{.c} * #include * #include "xxhash.h" * * // Example for a function which hashes a null terminated string with XXH32(). * XXH32_hash_t hash_string(const char* string, XXH32_hash_t seed) * { * // NULL pointers are only valid if the length is zero * size_t length = (string == NULL) ? 0 : strlen(string); * return XXH32(string, length, seed); * } * @endcode * * @anchor streaming_example * **Streaming** * * These groups of functions allow incremental hashing of unknown size, even * more than what would fit in a size_t. * * XXH32_reset(), XXH64_reset(), XXH3_64bits_reset(), XXH3_128bits_reset() * * @code{.c} * #include * #include * #include "xxhash.h" * // Example for a function which hashes a FILE incrementally with XXH3_64bits(). * XXH64_hash_t hashFile(FILE* f) * { * // Allocate a state struct. Do not just use malloc() or new. * XXH3_state_t* state = XXH3_createState(); * assert(state != NULL && "Out of memory!"); * // Reset the state to start a new hashing session. * XXH3_64bits_reset(state); * char buffer[4096]; * size_t count; * // Read the file in chunks * while ((count = fread(buffer, 1, sizeof(buffer), f)) != 0) { * // Run update() as many times as necessary to process the data * XXH3_64bits_update(state, buffer, count); * } * // Retrieve the finalized hash. This will not change the state. * XXH64_hash_t result = XXH3_64bits_digest(state); * // Free the state. Do not use free(). * XXH3_freeState(state); * return result; * } * @endcode * * @file xxhash.h * xxHash prototypes and implementation */ #if defined (__cplusplus) extern "C" { #endif /* **************************** * INLINE mode ******************************/ /*! * @defgroup public Public API * Contains details on the public xxHash functions. * @{ */ #ifdef XXH_DOXYGEN /*! * @brief Gives access to internal state declaration, required for static allocation. * * Incompatible with dynamic linking, due to risks of ABI changes. * * Usage: * @code{.c} * #define XXH_STATIC_LINKING_ONLY * #include "xxhash.h" * @endcode */ # define XXH_STATIC_LINKING_ONLY /* Do not undef XXH_STATIC_LINKING_ONLY for Doxygen */ /*! * @brief Gives access to internal definitions. * * Usage: * @code{.c} * #define XXH_STATIC_LINKING_ONLY * #define XXH_IMPLEMENTATION * #include "xxhash.h" * @endcode */ # define XXH_IMPLEMENTATION /* Do not undef XXH_IMPLEMENTATION for Doxygen */ /*! * @brief Exposes the implementation and marks all functions as `inline`. * * Use these build macros to inline xxhash into the target unit. * Inlining improves performance on small inputs, especially when the length is * expressed as a compile-time constant: * * https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html * * It also keeps xxHash symbols private to the unit, so they are not exported. * * Usage: * @code{.c} * #define XXH_INLINE_ALL * #include "xxhash.h" * @endcode * Do not compile and link xxhash.o as a separate object, as it is not useful. */ # define XXH_INLINE_ALL # undef XXH_INLINE_ALL /*! * @brief Exposes the implementation without marking functions as inline. */ # define XXH_PRIVATE_API # undef XXH_PRIVATE_API /*! * @brief Emulate a namespace by transparently prefixing all symbols. * * If you want to include _and expose_ xxHash functions from within your own * library, but also want to avoid symbol collisions with other libraries which * may also include xxHash, you can use @ref XXH_NAMESPACE to automatically prefix * any public symbol from xxhash library with the value of @ref XXH_NAMESPACE * (therefore, avoid empty or numeric values). * * Note that no change is required within the calling program as long as it * includes `xxhash.h`: Regular symbol names will be automatically translated * by this header. */ # define XXH_NAMESPACE /* YOUR NAME HERE */ # undef XXH_NAMESPACE #endif #if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \ && !defined(XXH_INLINE_ALL_31684351384) /* this section should be traversed only once */ # define XXH_INLINE_ALL_31684351384 /* give access to the advanced API, required to compile implementations */ # undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */ # define XXH_STATIC_LINKING_ONLY /* make all functions private */ # undef XXH_PUBLIC_API # if defined(__GNUC__) # define XXH_PUBLIC_API static __inline __attribute__((unused)) # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # define XXH_PUBLIC_API static inline # elif defined(_MSC_VER) # define XXH_PUBLIC_API static __inline # else /* note: this version may generate warnings for unused static functions */ # define XXH_PUBLIC_API static # endif /* * This part deals with the special case where a unit wants to inline xxHash, * but "xxhash.h" has previously been included without XXH_INLINE_ALL, * such as part of some previously included *.h header file. * Without further action, the new include would just be ignored, * and functions would effectively _not_ be inlined (silent failure). * The following macros solve this situation by prefixing all inlined names, * avoiding naming collision with previous inclusions. */ /* Before that, we unconditionally #undef all symbols, * in case they were already defined with XXH_NAMESPACE. * They will then be redefined for XXH_INLINE_ALL */ # undef XXH_versionNumber /* XXH32 */ # undef XXH32 # undef XXH32_createState # undef XXH32_freeState # undef XXH32_reset # undef XXH32_update # undef XXH32_digest # undef XXH32_copyState # undef XXH32_canonicalFromHash # undef XXH32_hashFromCanonical /* XXH64 */ # undef XXH64 # undef XXH64_createState # undef XXH64_freeState # undef XXH64_reset # undef XXH64_update # undef XXH64_digest # undef XXH64_copyState # undef XXH64_canonicalFromHash # undef XXH64_hashFromCanonical /* XXH3_64bits */ # undef XXH3_64bits # undef XXH3_64bits_withSecret # undef XXH3_64bits_withSeed # undef XXH3_64bits_withSecretandSeed # undef XXH3_createState # undef XXH3_freeState # undef XXH3_copyState # undef XXH3_64bits_reset # undef XXH3_64bits_reset_withSeed # undef XXH3_64bits_reset_withSecret # undef XXH3_64bits_update # undef XXH3_64bits_digest # undef XXH3_generateSecret /* XXH3_128bits */ # undef XXH128 # undef XXH3_128bits # undef XXH3_128bits_withSeed # undef XXH3_128bits_withSecret # undef XXH3_128bits_reset # undef XXH3_128bits_reset_withSeed # undef XXH3_128bits_reset_withSecret # undef XXH3_128bits_reset_withSecretandSeed # undef XXH3_128bits_update # undef XXH3_128bits_digest # undef XXH128_isEqual # undef XXH128_cmp # undef XXH128_canonicalFromHash # undef XXH128_hashFromCanonical /* Finally, free the namespace itself */ # undef XXH_NAMESPACE /* employ the namespace for XXH_INLINE_ALL */ # define XXH_NAMESPACE XXH_INLINE_ /* * Some identifiers (enums, type names) are not symbols, * but they must nonetheless be renamed to avoid redeclaration. * Alternative solution: do not redeclare them. * However, this requires some #ifdefs, and has a more dispersed impact. * Meanwhile, renaming can be achieved in a single place. */ # define XXH_IPREF(Id) XXH_NAMESPACE ## Id # define XXH_OK XXH_IPREF(XXH_OK) # define XXH_ERROR XXH_IPREF(XXH_ERROR) # define XXH_errorcode XXH_IPREF(XXH_errorcode) # define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t) # define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t) # define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t) # define XXH32_state_s XXH_IPREF(XXH32_state_s) # define XXH32_state_t XXH_IPREF(XXH32_state_t) # define XXH64_state_s XXH_IPREF(XXH64_state_s) # define XXH64_state_t XXH_IPREF(XXH64_state_t) # define XXH3_state_s XXH_IPREF(XXH3_state_s) # define XXH3_state_t XXH_IPREF(XXH3_state_t) # define XXH128_hash_t XXH_IPREF(XXH128_hash_t) /* Ensure the header is parsed again, even if it was previously included */ # undef XXHASH_H_5627135585666179 # undef XXHASH_H_STATIC_13879238742 #endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ /* **************************************************************** * Stable API *****************************************************************/ #ifndef XXHASH_H_5627135585666179 #define XXHASH_H_5627135585666179 1 /*! @brief Marks a global symbol. */ #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) # if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) # ifdef XXH_EXPORT # define XXH_PUBLIC_API __declspec(dllexport) # elif XXH_IMPORT # define XXH_PUBLIC_API __declspec(dllimport) # endif # else # define XXH_PUBLIC_API /* do nothing */ # endif #endif #ifdef XXH_NAMESPACE # define XXH_CAT(A,B) A##B # define XXH_NAME2(A,B) XXH_CAT(A,B) # define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) /* XXH32 */ # define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) # define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) # define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) # define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) # define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) # define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) # define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) # define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) # define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) /* XXH64 */ # define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) # define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) # define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) # define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) # define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) /* XXH3_64bits */ # define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits) # define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret) # define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed) # define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed) # define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState) # define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState) # define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState) # define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset) # define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed) # define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret) # define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed) # define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update) # define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest) # define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret) # define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed) /* XXH3_128bits */ # define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) # define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits) # define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed) # define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) # define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed) # define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) # define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed) # define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret) # define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed) # define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) # define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) # define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual) # define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp) # define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash) # define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical) #endif /* ************************************* * Compiler specifics ***************************************/ /* specific declaration modes for Windows */ #if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API) # if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT)) # ifdef XXH_EXPORT # define XXH_PUBLIC_API __declspec(dllexport) # elif XXH_IMPORT # define XXH_PUBLIC_API __declspec(dllimport) # endif # else # define XXH_PUBLIC_API /* do nothing */ # endif #endif #if defined (__GNUC__) # define XXH_CONSTF __attribute__((const)) # define XXH_PUREF __attribute__((pure)) # define XXH_MALLOCF __attribute__((malloc)) #else # define XXH_CONSTF /* disable */ # define XXH_PUREF # define XXH_MALLOCF #endif /* ************************************* * Version ***************************************/ #define XXH_VERSION_MAJOR 0 #define XXH_VERSION_MINOR 8 #define XXH_VERSION_RELEASE 2 /*! @brief Version number, encoded as two digits each */ #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) /*! * @brief Obtains the xxHash version. * * This is mostly useful when xxHash is compiled as a shared library, * since the returned value comes from the library, as opposed to header file. * * @return @ref XXH_VERSION_NUMBER of the invoked library. */ XXH_PUBLIC_API XXH_CONSTF unsigned XXH_versionNumber (void); /* **************************** * Common basic types ******************************/ #include /* size_t */ /*! * @brief Exit code for the streaming API. */ typedef enum { XXH_OK = 0, /*!< OK */ XXH_ERROR /*!< Error */ } XXH_errorcode; /*-********************************************************************** * 32-bit hash ************************************************************************/ #if defined(XXH_DOXYGEN) /* Don't show include */ /*! * @brief An unsigned 32-bit integer. * * Not necessarily defined to `uint32_t` but functionally equivalent. */ typedef uint32_t XXH32_hash_t; #elif !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint32_t XXH32_hash_t; #else # include # if UINT_MAX == 0xFFFFFFFFUL typedef unsigned int XXH32_hash_t; # elif ULONG_MAX == 0xFFFFFFFFUL typedef unsigned long XXH32_hash_t; # else # error "unsupported platform: need a 32-bit type" # endif #endif /*! * @} * * @defgroup XXH32_family XXH32 family * @ingroup public * Contains functions used in the classic 32-bit xxHash algorithm. * * @note * XXH32 is useful for older platforms, with no or poor 64-bit performance. * Note that the @ref XXH3_family provides competitive speed for both 32-bit * and 64-bit systems, and offers true 64/128 bit hash results. * * @see @ref XXH64_family, @ref XXH3_family : Other xxHash families * @see @ref XXH32_impl for implementation details * @{ */ /*! * @brief Calculates the 32-bit hash of @p input using xxHash32. * * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s * * See @ref single_shot_example "Single Shot Example" for an example. * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * @param seed The 32-bit seed to alter the hash's output predictably. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 32-bit hash value. * * @see * XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): * Direct equivalents for the other variants of xxHash. * @see * XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed); #ifndef XXH_NO_STREAM /*! * Streaming functions generate the xxHash value from an incremental input. * This method is slower than single-call functions, due to state management. * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. * * An XXH state must first be allocated using `XXH*_createState()`. * * Start a new hash by initializing the state with a seed using `XXH*_reset()`. * * Then, feed the hash state by calling `XXH*_update()` as many times as necessary. * * The function returns an error code, with 0 meaning OK, and any other value * meaning there is an error. * * Finally, a hash value can be produced anytime, by using `XXH*_digest()`. * This function returns the nn-bits hash as an int or long long. * * It's still possible to continue inserting input into the hash state after a * digest, and generate new hash values later on by invoking `XXH*_digest()`. * * When done, release the state using `XXH*_freeState()`. * * @see streaming_example at the top of @ref xxhash.h for an example. */ /*! * @typedef struct XXH32_state_s XXH32_state_t * @brief The opaque state struct for the XXH32 streaming API. * * @see XXH32_state_s for details. */ typedef struct XXH32_state_s XXH32_state_t; /*! * @brief Allocates an @ref XXH32_state_t. * * Must be freed with XXH32_freeState(). * @return An allocated XXH32_state_t on success, `NULL` on failure. */ XXH_PUBLIC_API XXH_MALLOCF XXH32_state_t* XXH32_createState(void); /*! * @brief Frees an @ref XXH32_state_t. * * Must be allocated with XXH32_createState(). * @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState(). * @return XXH_OK. */ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); /*! * @brief Copies one @ref XXH32_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); /*! * @brief Resets an @ref XXH32_state_t to begin a new hash. * * This function resets and seeds a state. Call it before @ref XXH32_update(). * * @param statePtr The state struct to reset. * @param seed The 32-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed); /*! * @brief Consumes a block of @p input to an @ref XXH32_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); /*! * @brief Returns the calculated hash value from an @ref XXH32_state_t. * * @note * Calling XXH32_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated xxHash32 value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /* * The default return values from XXH functions are unsigned 32 and 64 bit * integers. * This the simplest and fastest format for further post-processing. * * However, this leaves open the question of what is the order on the byte level, * since little and big endian conventions will store the same number differently. * * The canonical representation settles this issue by mandating big-endian * convention, the same convention as human-readable numbers (large digits first). * * When writing hash values to storage, sending them over a network, or printing * them, it's highly recommended to use the canonical representation to ensure * portability across a wider range of systems, present and future. * * The following functions allow transformation of hash values to and from * canonical format. */ /*! * @brief Canonical (big endian) representation of @ref XXH32_hash_t. */ typedef struct { unsigned char digest[4]; /*!< Hash bytes, big endian */ } XXH32_canonical_t; /*! * @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t. * * @param dst The @ref XXH32_canonical_t pointer to be stored to. * @param hash The @ref XXH32_hash_t to be converted. * * @pre * @p dst must not be `NULL`. */ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); /*! * @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t. * * @param src The @ref XXH32_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. */ XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); /*! @cond Doxygen ignores this part */ #ifdef __has_attribute # define XXH_HAS_ATTRIBUTE(x) __has_attribute(x) #else # define XXH_HAS_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * C23 __STDC_VERSION__ number hasn't been specified yet. For now * leave as `201711L` (C17 + 1). * TODO: Update to correct value when its been specified. */ #define XXH_C23_VN 201711L /*! @endcond */ /*! @cond Doxygen ignores this part */ /* C-language Attributes are added in C23. */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) && defined(__has_c_attribute) # define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) #else # define XXH_HAS_C_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ #if defined(__cplusplus) && defined(__has_cpp_attribute) # define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) #else # define XXH_HAS_CPP_ATTRIBUTE(x) 0 #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute * introduced in CPP17 and C23. * CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough * C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough */ #if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough) # define XXH_FALLTHROUGH [[fallthrough]] #elif XXH_HAS_ATTRIBUTE(__fallthrough__) # define XXH_FALLTHROUGH __attribute__ ((__fallthrough__)) #else # define XXH_FALLTHROUGH /* fallthrough */ #endif /*! @endcond */ /*! @cond Doxygen ignores this part */ /* * Define XXH_NOESCAPE for annotated pointers in public API. * https://clang.llvm.org/docs/AttributeReference.html#noescape * As of writing this, only supported by clang. */ #if XXH_HAS_ATTRIBUTE(noescape) # define XXH_NOESCAPE __attribute__((noescape)) #else # define XXH_NOESCAPE #endif /*! @endcond */ /*! * @} * @ingroup public * @{ */ #ifndef XXH_NO_LONG_LONG /*-********************************************************************** * 64-bit hash ************************************************************************/ #if defined(XXH_DOXYGEN) /* don't include */ /*! * @brief An unsigned 64-bit integer. * * Not necessarily defined to `uint64_t` but functionally equivalent. */ typedef uint64_t XXH64_hash_t; #elif !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint64_t XXH64_hash_t; #else # include # if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL /* LP64 ABI says uint64_t is unsigned long */ typedef unsigned long XXH64_hash_t; # else /* the following type must have a width of 64-bit */ typedef unsigned long long XXH64_hash_t; # endif #endif /*! * @} * * @defgroup XXH64_family XXH64 family * @ingroup public * @{ * Contains functions used in the classic 64-bit xxHash algorithm. * * @note * XXH3 provides competitive speed for both 32-bit and 64-bit systems, * and offers true 64/128 bit hash results. * It provides better speed for systems with vector processing capabilities. */ /*! * @brief Calculates the 64-bit hash of @p input using xxHash64. * * This function usually runs faster on 64-bit systems, but slower on 32-bit * systems (see benchmark). * * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * @param seed The 64-bit seed to alter the hash's output predictably. * * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return The calculated 64-bit hash. * * @see * XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128(): * Direct equivalents for the other variants of xxHash. * @see * XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); /******* Streaming *******/ #ifndef XXH_NO_STREAM /*! * @brief The opaque state struct for the XXH64 streaming API. * * @see XXH64_state_s for details. */ typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ /*! * @brief Allocates an @ref XXH64_state_t. * * Must be freed with XXH64_freeState(). * @return An allocated XXH64_state_t on success, `NULL` on failure. */ XXH_PUBLIC_API XXH_MALLOCF XXH64_state_t* XXH64_createState(void); /*! * @brief Frees an @ref XXH64_state_t. * * Must be allocated with XXH64_createState(). * @param statePtr A pointer to an @ref XXH64_state_t allocated with @ref XXH64_createState(). * @return XXH_OK. */ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); /*! * @brief Copies one @ref XXH64_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dst_state, const XXH64_state_t* src_state); /*! * @brief Resets an @ref XXH64_state_t to begin a new hash. * * This function resets and seeds a state. Call it before @ref XXH64_update(). * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the hash result predictably. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed); /*! * @brief Consumes a block of @p input to an @ref XXH64_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated hash value from an @ref XXH64_state_t. * * @note * Calling XXH64_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated xxHash64 value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_digest (XXH_NOESCAPE const XXH64_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! * @brief Canonical (big endian) representation of @ref XXH64_hash_t. */ typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t; /*! * @brief Converts an @ref XXH64_hash_t to a big endian @ref XXH64_canonical_t. * * @param dst The @ref XXH64_canonical_t pointer to be stored to. * @param hash The @ref XXH64_hash_t to be converted. * * @pre * @p dst must not be `NULL`. */ XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash); /*! * @brief Converts an @ref XXH64_canonical_t to a native @ref XXH64_hash_t. * * @param src The @ref XXH64_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src); #ifndef XXH_NO_XXH3 /*! * @} * ************************************************************************ * @defgroup XXH3_family XXH3 family * @ingroup public * @{ * * XXH3 is a more recent hash algorithm featuring: * - Improved speed for both small and large inputs * - True 64-bit and 128-bit outputs * - SIMD acceleration * - Improved 32-bit viability * * Speed analysis methodology is explained here: * * https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html * * Compared to XXH64, expect XXH3 to run approximately * ~2x faster on large inputs and >3x faster on small ones, * exact differences vary depending on platform. * * XXH3's speed benefits greatly from SIMD and 64-bit arithmetic, * but does not require it. * Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3 * at competitive speeds, even without vector support. Further details are * explained in the implementation. * * XXH3 has a fast scalar implementation, but it also includes accelerated SIMD * implementations for many common platforms: * - AVX512 * - AVX2 * - SSE2 * - ARM NEON * - WebAssembly SIMD128 * - POWER8 VSX * - s390x ZVector * This can be controlled via the @ref XXH_VECTOR macro, but it automatically * selects the best version according to predefined macros. For the x86 family, an * automatic runtime dispatcher is included separately in @ref xxh_x86dispatch.c. * * XXH3 implementation is portable: * it has a generic C90 formulation that can be compiled on any platform, * all implementations generate exactly the same hash value on all platforms. * Starting from v0.8.0, it's also labelled "stable", meaning that * any future version will also generate the same hash value. * * XXH3 offers 2 variants, _64bits and _128bits. * * When only 64 bits are needed, prefer invoking the _64bits variant, as it * reduces the amount of mixing, resulting in faster speed on small inputs. * It's also generally simpler to manipulate a scalar return type than a struct. * * The API supports one-shot hashing, streaming mode, and custom secrets. */ /*-********************************************************************** * XXH3 64-bit variant ************************************************************************/ /*! * @brief 64-bit unseeded variant of XXH3. * * This is equivalent to @ref XXH3_64bits_withSeed() with a seed of 0, however * it may have slightly better performance due to constant propagation of the * defaults. * * @see * XXH32(), XXH64(), XXH3_128bits(): equivalent for the other xxHash algorithms * @see * XXH3_64bits_withSeed(), XXH3_64bits_withSecret(): other seeding variants * @see * XXH3_64bits_reset(), XXH3_64bits_update(), XXH3_64bits_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length); /*! * @brief 64-bit seeded variant of XXH3 * * This variant generates a custom secret on the fly based on default secret * altered using the `seed` value. * * While this operation is decently fast, note that it's not completely free. * * @note * seed == 0 produces the same results as @ref XXH3_64bits(). * * @param input The data to hash * @param length The length * @param seed The 64-bit seed to alter the state. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed); /*! * The bare minimum size for a custom secret. * * @see * XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(), * XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret(). */ #define XXH3_SECRET_SIZE_MIN 136 /*! * @brief 64-bit variant of XXH3 with a custom "secret". * * It's possible to provide any blob of bytes as a "secret" to generate the hash. * This makes it more difficult for an external actor to prepare an intentional collision. * The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN). * However, the quality of the secret impacts the dispersion of the hash algorithm. * Therefore, the secret _must_ look like a bunch of random bytes. * Avoid "trivial" or structured data such as repeated sequences or a text document. * Whenever in doubt about the "randomness" of the blob of bytes, * consider employing "XXH3_generateSecret()" instead (see below). * It will generate a proper high entropy secret derived from the blob of bytes. * Another advantage of using XXH3_generateSecret() is that * it guarantees that all bits within the initial blob of bytes * will impact every bit of the output. * This is not necessarily the case when using the blob of bytes directly * because, when hashing _small_ inputs, only a portion of the secret is employed. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); /******* Streaming *******/ #ifndef XXH_NO_STREAM /* * Streaming requires state maintenance. * This operation costs memory and CPU. * As a consequence, streaming is slower than one-shot hashing. * For better performance, prefer one-shot functions whenever applicable. */ /*! * @brief The state struct for the XXH3 streaming API. * * @see XXH3_state_s for details. */ typedef struct XXH3_state_s XXH3_state_t; XXH_PUBLIC_API XXH_MALLOCF XXH3_state_t* XXH3_createState(void); XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr); /*! * @brief Copies one @ref XXH3_state_t to another. * * @param dst_state The state to copy to. * @param src_state The state to copy from. * @pre * @p dst_state and @p src_state must not be `NULL` and must not overlap. */ XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state); /*! * @brief Resets an @ref XXH3_state_t to begin a new hash. * * This function resets `statePtr` and generate a secret with default parameters. Call it before @ref XXH3_64bits_update(). * Digest will be equivalent to `XXH3_64bits()`. * * @param statePtr The state struct to reset. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); /*! * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. * * This function resets `statePtr` and generate a secret from `seed`. Call it before @ref XXH3_64bits_update(). * Digest will be equivalent to `XXH3_64bits_withSeed()`. * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the state. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); /*! * XXH3_64bits_reset_withSecret(): * `secret` is referenced, it _must outlive_ the hash streaming session. * Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`, * and the quality of produced hash values depends on secret's entropy * (secret's content should look like a bunch of random bytes). * When in doubt about the randomness of a candidate `secret`, * consider employing `XXH3_generateSecret()` instead (see below). */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); /*! * @brief Consumes a block of @p input to an @ref XXH3_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated XXH3 64-bit hash value from an @ref XXH3_state_t. * * @note * Calling XXH3_64bits_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated XXH3 64-bit hash value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /* note : canonical representation of XXH3 is the same as XXH64 * since they both produce XXH64_hash_t values */ /*-********************************************************************** * XXH3 128-bit variant ************************************************************************/ /*! * @brief The return value from 128-bit hashes. * * Stored in little endian order, although the fields themselves are in native * endianness. */ typedef struct { XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */ XXH64_hash_t high64; /*!< `value >> 64` */ } XXH128_hash_t; /*! * @brief Unseeded 128-bit variant of XXH3 * * The 128-bit variant of XXH3 has more strength, but it has a bit of overhead * for shorter inputs. * * This is equivalent to @ref XXH3_128bits_withSeed() with a seed of 0, however * it may have slightly better performance due to constant propagation of the * defaults. * * @see * XXH32(), XXH64(), XXH3_64bits(): equivalent for the other xxHash algorithms * @see * XXH3_128bits_withSeed(), XXH3_128bits_withSecret(): other seeding variants * @see * XXH3_128bits_reset(), XXH3_128bits_update(), XXH3_128bits_digest(): Streaming version. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* data, size_t len); /*! @brief Seeded 128-bit variant of XXH3. @see XXH3_64bits_withSeed(). */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); /*! @brief Custom secret 128-bit variant of XXH3. @see XXH3_64bits_withSecret(). */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize); /******* Streaming *******/ #ifndef XXH_NO_STREAM /* * Streaming requires state maintenance. * This operation costs memory and CPU. * As a consequence, streaming is slower than one-shot hashing. * For better performance, prefer one-shot functions whenever applicable. * * XXH3_128bits uses the same XXH3_state_t as XXH3_64bits(). * Use already declared XXH3_createState() and XXH3_freeState(). * * All reset and streaming functions have same meaning as their 64-bit counterpart. */ /*! * @brief Resets an @ref XXH3_state_t to begin a new hash. * * This function resets `statePtr` and generate a secret with default parameters. Call it before @ref XXH3_128bits_update(). * Digest will be equivalent to `XXH3_128bits()`. * * @param statePtr The state struct to reset. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr); /*! * @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash. * * This function resets `statePtr` and generate a secret from `seed`. Call it before @ref XXH3_128bits_update(). * Digest will be equivalent to `XXH3_128bits_withSeed()`. * * @param statePtr The state struct to reset. * @param seed The 64-bit seed to alter the state. * * @pre * @p statePtr must not be `NULL`. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. * */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed); /*! @brief Custom secret 128-bit variant of XXH3. @see XXH_64bits_reset_withSecret(). */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize); /*! * @brief Consumes a block of @p input to an @ref XXH3_state_t. * * Call this to incrementally consume blocks of data. * * @param statePtr The state struct to update. * @param input The block of data to be hashed, at least @p length bytes in size. * @param length The length of @p input, in bytes. * * @pre * @p statePtr must not be `NULL`. * @pre * The memory between @p input and @p input + @p length must be valid, * readable, contiguous memory. However, if @p length is `0`, @p input may be * `NULL`. In C++, this also must be *TriviallyCopyable*. * * @return @ref XXH_OK on success, @ref XXH_ERROR on failure. */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length); /*! * @brief Returns the calculated XXH3 128-bit hash value from an @ref XXH3_state_t. * * @note * Calling XXH3_128bits_digest() will not affect @p statePtr, so you can update, * digest, and update again. * * @param statePtr The state struct to calculate the hash from. * * @pre * @p statePtr must not be `NULL`. * * @return The calculated XXH3 128-bit hash value from that state. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr); #endif /* !XXH_NO_STREAM */ /* Following helper functions make it possible to compare XXH128_hast_t values. * Since XXH128_hash_t is a structure, this capability is not offered by the language. * Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */ /*! * XXH128_isEqual(): * Return: 1 if `h1` and `h2` are equal, 0 if they are not. */ XXH_PUBLIC_API XXH_PUREF int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2); /*! * @brief Compares two @ref XXH128_hash_t * This comparator is compatible with stdlib's `qsort()`/`bsearch()`. * * @return: >0 if *h128_1 > *h128_2 * =0 if *h128_1 == *h128_2 * <0 if *h128_1 < *h128_2 */ XXH_PUBLIC_API XXH_PUREF int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2); /******* Canonical representation *******/ typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; /*! * @brief Converts an @ref XXH128_hash_t to a big endian @ref XXH128_canonical_t. * * @param dst The @ref XXH128_canonical_t pointer to be stored to. * @param hash The @ref XXH128_hash_t to be converted. * * @pre * @p dst must not be `NULL`. */ XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash); /*! * @brief Converts an @ref XXH128_canonical_t to a native @ref XXH128_hash_t. * * @param src The @ref XXH128_canonical_t to convert. * * @pre * @p src must not be `NULL`. * * @return The converted hash. */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src); #endif /* !XXH_NO_XXH3 */ #endif /* XXH_NO_LONG_LONG */ /*! * @} */ #endif /* XXHASH_H_5627135585666179 */ #if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) #define XXHASH_H_STATIC_13879238742 /* **************************************************************************** * This section contains declarations which are not guaranteed to remain stable. * They may change in future versions, becoming incompatible with a different * version of the library. * These declarations should only be used with static linking. * Never use them in association with dynamic linking! ***************************************************************************** */ /* * These definitions are only present to allow static allocation * of XXH states, on stack or in a struct, for example. * Never **ever** access their members directly. */ /*! * @internal * @brief Structure for XXH32 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is * an opaque type. This allows fields to safely be changed. * * Typedef'd to @ref XXH32_state_t. * Do not access the members of this struct directly. * @see XXH64_state_s, XXH3_state_s */ struct XXH32_state_s { XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */ XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */ XXH32_hash_t v[4]; /*!< Accumulator lanes */ XXH32_hash_t mem32[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[16]. */ XXH32_hash_t memsize; /*!< Amount of data in @ref mem32 */ XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */ }; /* typedef'd to XXH32_state_t */ #ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */ /*! * @internal * @brief Structure for XXH64 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is * an opaque type. This allows fields to safely be changed. * * Typedef'd to @ref XXH64_state_t. * Do not access the members of this struct directly. * @see XXH32_state_s, XXH3_state_s */ struct XXH64_state_s { XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */ XXH64_hash_t v[4]; /*!< Accumulator lanes */ XXH64_hash_t mem64[4]; /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */ XXH32_hash_t memsize; /*!< Amount of data in @ref mem64 */ XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/ XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */ }; /* typedef'd to XXH64_state_t */ #ifndef XXH_NO_XXH3 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */ # include # define XXH_ALIGN(n) alignas(n) #elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */ /* In C++ alignas() is a keyword */ # define XXH_ALIGN(n) alignas(n) #elif defined(__GNUC__) # define XXH_ALIGN(n) __attribute__ ((aligned(n))) #elif defined(_MSC_VER) # define XXH_ALIGN(n) __declspec(align(n)) #else # define XXH_ALIGN(n) /* disabled */ #endif /* Old GCC versions only accept the attribute after the type in structures. */ #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ && ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \ && defined(__GNUC__) # define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) #else # define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type #endif /*! * @brief The size of the internal XXH3 buffer. * * This is the optimal update size for incremental hashing. * * @see XXH3_64b_update(), XXH3_128b_update(). */ #define XXH3_INTERNALBUFFER_SIZE 256 /*! * @internal * @brief Default size of the secret buffer (and @ref XXH3_kSecret). * * This is the size used in @ref XXH3_kSecret and the seeded functions. * * Not to be confused with @ref XXH3_SECRET_SIZE_MIN. */ #define XXH3_SECRET_DEFAULT_SIZE 192 /*! * @internal * @brief Structure for XXH3 streaming API. * * @note This is only defined when @ref XXH_STATIC_LINKING_ONLY, * @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. * Otherwise it is an opaque type. * Never use this definition in combination with dynamic library. * This allows fields to safely be changed in the future. * * @note ** This structure has a strict alignment requirement of 64 bytes!! ** * Do not allocate this with `malloc()` or `new`, * it will not be sufficiently aligned. * Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation. * * Typedef'd to @ref XXH3_state_t. * Do never access the members of this struct directly. * * @see XXH3_INITSTATE() for stack initialization. * @see XXH3_createState(), XXH3_freeState(). * @see XXH32_state_s, XXH64_state_s */ struct XXH3_state_s { XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); /*!< The 8 accumulators. See @ref XXH32_state_s::v and @ref XXH64_state_s::v */ XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); /*!< Used to store a custom secret generated from a seed. */ XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); /*!< The internal buffer. @see XXH32_state_s::mem32 */ XXH32_hash_t bufferedSize; /*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */ XXH32_hash_t useSeed; /*!< Reserved field. Needed for padding on 64-bit. */ size_t nbStripesSoFar; /*!< Number or stripes processed. */ XXH64_hash_t totalLen; /*!< Total length hashed. 64-bit even on 32-bit targets. */ size_t nbStripesPerBlock; /*!< Number of stripes per block. */ size_t secretLimit; /*!< Size of @ref customSecret or @ref extSecret */ XXH64_hash_t seed; /*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */ XXH64_hash_t reserved64; /*!< Reserved field. */ const unsigned char* extSecret; /*!< Reference to an external secret for the _withSecret variants, NULL * for other variants. */ /* note: there may be some padding at the end due to alignment on 64 bytes */ }; /* typedef'd to XXH3_state_t */ #undef XXH_ALIGN_MEMBER /*! * @brief Initializes a stack-allocated `XXH3_state_s`. * * When the @ref XXH3_state_t structure is merely emplaced on stack, * it should be initialized with XXH3_INITSTATE() or a memset() * in case its first reset uses XXH3_NNbits_reset_withSeed(). * This init can be omitted if the first reset uses default or _withSecret mode. * This operation isn't necessary when the state is created with XXH3_createState(). * Note that this doesn't prepare the state for a streaming operation, * it's still necessary to use XXH3_NNbits_reset*() afterwards. */ #define XXH3_INITSTATE(XXH3_state_ptr) \ do { \ XXH3_state_t* tmp_xxh3_state_ptr = (XXH3_state_ptr); \ tmp_xxh3_state_ptr->seed = 0; \ tmp_xxh3_state_ptr->extSecret = NULL; \ } while(0) /*! * simple alias to pre-selected XXH3_128bits variant */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed); /* === Experimental API === */ /* Symbols defined below must be considered tied to a specific library version. */ /*! * XXH3_generateSecret(): * * Derive a high-entropy secret from any user-defined content, named customSeed. * The generated secret can be used in combination with `*_withSecret()` functions. * The `_withSecret()` variants are useful to provide a higher level of protection * than 64-bit seed, as it becomes much more difficult for an external actor to * guess how to impact the calculation logic. * * The function accepts as input a custom seed of any length and any content, * and derives from it a high-entropy secret of length @p secretSize into an * already allocated buffer @p secretBuffer. * * The generated secret can then be used with any `*_withSecret()` variant. * The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(), * @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret() * are part of this list. They all accept a `secret` parameter * which must be large enough for implementation reasons (>= @ref XXH3_SECRET_SIZE_MIN) * _and_ feature very high entropy (consist of random-looking bytes). * These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can * be employed to ensure proper quality. * * @p customSeed can be anything. It can have any size, even small ones, * and its content can be anything, even "poor entropy" sources such as a bunch * of zeroes. The resulting `secret` will nonetheless provide all required qualities. * * @pre * - @p secretSize must be >= @ref XXH3_SECRET_SIZE_MIN * - When @p customSeedSize > 0, supplying NULL as customSeed is undefined behavior. * * Example code: * @code{.c} * #include * #include * #include * #define XXH_STATIC_LINKING_ONLY // expose unstable API * #include "xxhash.h" * // Hashes argv[2] using the entropy from argv[1]. * int main(int argc, char* argv[]) * { * char secret[XXH3_SECRET_SIZE_MIN]; * if (argv != 3) { return 1; } * XXH3_generateSecret(secret, sizeof(secret), argv[1], strlen(argv[1])); * XXH64_hash_t h = XXH3_64bits_withSecret( * argv[2], strlen(argv[2]), * secret, sizeof(secret) * ); * printf("%016llx\n", (unsigned long long) h); * } * @endcode */ XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize); /*! * @brief Generate the same secret as the _withSeed() variants. * * The generated secret can be used in combination with *`*_withSecret()` and `_withSecretandSeed()` variants. * * Example C++ `std::string` hash class: * @code{.cpp} * #include * #define XXH_STATIC_LINKING_ONLY // expose unstable API * #include "xxhash.h" * // Slow, seeds each time * class HashSlow { * XXH64_hash_t seed; * public: * HashSlow(XXH64_hash_t s) : seed{s} {} * size_t operator()(const std::string& x) const { * return size_t{XXH3_64bits_withSeed(x.c_str(), x.length(), seed)}; * } * }; * // Fast, caches the seeded secret for future uses. * class HashFast { * unsigned char secret[XXH3_SECRET_SIZE_MIN]; * public: * HashFast(XXH64_hash_t s) { * XXH3_generateSecret_fromSeed(secret, seed); * } * size_t operator()(const std::string& x) const { * return size_t{ * XXH3_64bits_withSecret(x.c_str(), x.length(), secret, sizeof(secret)) * }; * } * }; * @endcode * @param secretBuffer A writable buffer of @ref XXH3_SECRET_SIZE_MIN bytes * @param seed The seed to seed the state. */ XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed); /*! * These variants generate hash values using either * @p seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes) * or @p secret for "large" keys (>= XXH3_MIDSIZE_MAX). * * This generally benefits speed, compared to `_withSeed()` or `_withSecret()`. * `_withSeed()` has to generate the secret on the fly for "large" keys. * It's fast, but can be perceptible for "not so large" keys (< 1 KB). * `_withSecret()` has to generate the masks on the fly for "small" keys, * which requires more instructions than _withSeed() variants. * Therefore, _withSecretandSeed variant combines the best of both worlds. * * When @p secret has been generated by XXH3_generateSecret_fromSeed(), * this variant produces *exactly* the same results as `_withSeed()` variant, * hence offering only a pure speed benefit on "large" input, * by skipping the need to regenerate the secret for every large input. * * Another usage scenario is to hash the secret to a 64-bit hash value, * for example with XXH3_64bits(), which then becomes the seed, * and then employ both the seed and the secret in _withSecretandSeed(). * On top of speed, an added benefit is that each bit in the secret * has a 50% chance to swap each bit in the output, via its impact to the seed. * * This is not guaranteed when using the secret directly in "small data" scenarios, * because only portions of the secret are employed for small data. */ XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed); /*! @copydoc XXH3_64bits_withSecretandSeed() */ XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); #ifndef XXH_NO_STREAM /*! @copydoc XXH3_64bits_withSecretandSeed() */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); /*! @copydoc XXH3_64bits_withSecretandSeed() */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64); #endif /* !XXH_NO_STREAM */ #endif /* !XXH_NO_XXH3 */ #endif /* XXH_NO_LONG_LONG */ #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) # define XXH_IMPLEMENTATION #endif #endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */ /* ======================================================================== */ /* ======================================================================== */ /* ======================================================================== */ /*-********************************************************************** * xxHash implementation *-********************************************************************** * xxHash's implementation used to be hosted inside xxhash.c. * * However, inlining requires implementation to be visible to the compiler, * hence be included alongside the header. * Previously, implementation was hosted inside xxhash.c, * which was then #included when inlining was activated. * This construction created issues with a few build and install systems, * as it required xxhash.c to be stored in /include directory. * * xxHash implementation is now directly integrated within xxhash.h. * As a consequence, xxhash.c is no longer needed in /include. * * xxhash.c is still available and is still useful. * In a "normal" setup, when xxhash is not inlined, * xxhash.h only exposes the prototypes and public symbols, * while xxhash.c can be built into an object file xxhash.o * which can then be linked into the final binary. ************************************************************************/ #if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \ || defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387) # define XXH_IMPLEM_13a8737387 /* ************************************* * Tuning parameters ***************************************/ /*! * @defgroup tuning Tuning parameters * @{ * * Various macros to control xxHash's behavior. */ #ifdef XXH_DOXYGEN /*! * @brief Define this to disable 64-bit code. * * Useful if only using the @ref XXH32_family and you have a strict C90 compiler. */ # define XXH_NO_LONG_LONG # undef XXH_NO_LONG_LONG /* don't actually */ /*! * @brief Controls how unaligned memory is accessed. * * By default, access to unaligned memory is controlled by `memcpy()`, which is * safe and portable. * * Unfortunately, on some target/compiler combinations, the generated assembly * is sub-optimal. * * The below switch allow selection of a different access method * in the search for improved performance. * * @par Possible options: * * - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy` * @par * Use `memcpy()`. Safe and portable. Note that most modern compilers will * eliminate the function call and treat it as an unaligned access. * * - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((aligned(1)))` * @par * Depends on compiler extensions and is therefore not portable. * This method is safe _if_ your compiler supports it, * and *generally* as fast or faster than `memcpy`. * * - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast * @par * Casts directly and dereferences. This method doesn't depend on the * compiler, but it violates the C standard as it directly dereferences an * unaligned pointer. It can generate buggy code on targets which do not * support unaligned memory accesses, but in some circumstances, it's the * only known way to get the most performance. * * - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift * @par * Also portable. This can generate the best code on old compilers which don't * inline small `memcpy()` calls, and it might also be faster on big-endian * systems which lack a native byteswap instruction. However, some compilers * will emit literal byteshifts even if the target supports unaligned access. * * * @warning * Methods 1 and 2 rely on implementation-defined behavior. Use these with * care, as what works on one compiler/platform/optimization level may cause * another to read garbage data or even crash. * * See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details. * * Prefer these methods in priority order (0 > 3 > 1 > 2) */ # define XXH_FORCE_MEMORY_ACCESS 0 /*! * @def XXH_SIZE_OPT * @brief Controls how much xxHash optimizes for size. * * xxHash, when compiled, tends to result in a rather large binary size. This * is mostly due to heavy usage to forced inlining and constant folding of the * @ref XXH3_family to increase performance. * * However, some developers prefer size over speed. This option can * significantly reduce the size of the generated code. When using the `-Os` * or `-Oz` options on GCC or Clang, this is defined to 1 by default, * otherwise it is defined to 0. * * Most of these size optimizations can be controlled manually. * * This is a number from 0-2. * - `XXH_SIZE_OPT` == 0: Default. xxHash makes no size optimizations. Speed * comes first. * - `XXH_SIZE_OPT` == 1: Default for `-Os` and `-Oz`. xxHash is more * conservative and disables hacks that increase code size. It implies the * options @ref XXH_NO_INLINE_HINTS == 1, @ref XXH_FORCE_ALIGN_CHECK == 0, * and @ref XXH3_NEON_LANES == 8 if they are not already defined. * - `XXH_SIZE_OPT` == 2: xxHash tries to make itself as small as possible. * Performance may cry. For example, the single shot functions just use the * streaming API. */ # define XXH_SIZE_OPT 0 /*! * @def XXH_FORCE_ALIGN_CHECK * @brief If defined to non-zero, adds a special path for aligned inputs (XXH32() * and XXH64() only). * * This is an important performance trick for architectures without decent * unaligned memory access performance. * * It checks for input alignment, and when conditions are met, uses a "fast * path" employing direct 32-bit/64-bit reads, resulting in _dramatically * faster_ read speed. * * The check costs one initial branch per hash, which is generally negligible, * but not zero. * * Moreover, it's not useful to generate an additional code path if memory * access uses the same instruction for both aligned and unaligned * addresses (e.g. x86 and aarch64). * * In these cases, the alignment check can be removed by setting this macro to 0. * Then the code will always use unaligned memory access. * Align check is automatically disabled on x86, x64, ARM64, and some ARM chips * which are platforms known to offer good unaligned memory accesses performance. * * It is also disabled by default when @ref XXH_SIZE_OPT >= 1. * * This option does not affect XXH3 (only XXH32 and XXH64). */ # define XXH_FORCE_ALIGN_CHECK 0 /*! * @def XXH_NO_INLINE_HINTS * @brief When non-zero, sets all functions to `static`. * * By default, xxHash tries to force the compiler to inline almost all internal * functions. * * This can usually improve performance due to reduced jumping and improved * constant folding, but significantly increases the size of the binary which * might not be favorable. * * Additionally, sometimes the forced inlining can be detrimental to performance, * depending on the architecture. * * XXH_NO_INLINE_HINTS marks all internal functions as static, giving the * compiler full control on whether to inline or not. * * When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if * @ref XXH_SIZE_OPT >= 1, this will automatically be defined. */ # define XXH_NO_INLINE_HINTS 0 /*! * @def XXH3_INLINE_SECRET * @brief Determines whether to inline the XXH3 withSecret code. * * When the secret size is known, the compiler can improve the performance * of XXH3_64bits_withSecret() and XXH3_128bits_withSecret(). * * However, if the secret size is not known, it doesn't have any benefit. This * happens when xxHash is compiled into a global symbol. Therefore, if * @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0. * * Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers * that are *sometimes* force inline on -Og, and it is impossible to automatically * detect this optimization level. */ # define XXH3_INLINE_SECRET 0 /*! * @def XXH32_ENDJMP * @brief Whether to use a jump for `XXH32_finalize`. * * For performance, `XXH32_finalize` uses multiple branches in the finalizer. * This is generally preferable for performance, * but depending on exact architecture, a jmp may be preferable. * * This setting is only possibly making a difference for very small inputs. */ # define XXH32_ENDJMP 0 /*! * @internal * @brief Redefines old internal names. * * For compatibility with code that uses xxHash's internals before the names * were changed to improve namespacing. There is no other reason to use this. */ # define XXH_OLD_NAMES # undef XXH_OLD_NAMES /* don't actually use, it is ugly. */ /*! * @def XXH_NO_STREAM * @brief Disables the streaming API. * * When xxHash is not inlined and the streaming functions are not used, disabling * the streaming functions can improve code size significantly, especially with * the @ref XXH3_family which tends to make constant folded copies of itself. */ # define XXH_NO_STREAM # undef XXH_NO_STREAM /* don't actually */ #endif /* XXH_DOXYGEN */ /*! * @} */ #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ /* prefer __packed__ structures (method 1) for GCC * < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy * which for some reason does unaligned loads. */ # if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED)) # define XXH_FORCE_MEMORY_ACCESS 1 # endif #endif #ifndef XXH_SIZE_OPT /* default to 1 for -Os or -Oz */ # if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE_SIZE__) # define XXH_SIZE_OPT 1 # else # define XXH_SIZE_OPT 0 # endif #endif #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ /* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */ # if XXH_SIZE_OPT >= 1 || \ defined(__i386) || defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_FEATURE_UNALIGNED) \ || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM) /* visual */ # define XXH_FORCE_ALIGN_CHECK 0 # else # define XXH_FORCE_ALIGN_CHECK 1 # endif #endif #ifndef XXH_NO_INLINE_HINTS # if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__) /* -O0, -fno-inline */ # define XXH_NO_INLINE_HINTS 1 # else # define XXH_NO_INLINE_HINTS 0 # endif #endif #ifndef XXH3_INLINE_SECRET # if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \ || !defined(XXH_INLINE_ALL) # define XXH3_INLINE_SECRET 0 # else # define XXH3_INLINE_SECRET 1 # endif #endif #ifndef XXH32_ENDJMP /* generally preferable for performance */ # define XXH32_ENDJMP 0 #endif /*! * @defgroup impl Implementation * @{ */ /* ************************************* * Includes & Memory related functions ***************************************/ #if defined(XXH_NO_STREAM) /* nothing */ #elif defined(XXH_NO_STDLIB) /* When requesting to disable any mention of stdlib, * the library loses the ability to invoked malloc / free. * In practice, it means that functions like `XXH*_createState()` * will always fail, and return NULL. * This flag is useful in situations where * xxhash.h is integrated into some kernel, embedded or limited environment * without access to dynamic allocation. */ static XXH_CONSTF void* XXH_malloc(size_t s) { (void)s; return NULL; } static void XXH_free(void* p) { (void)p; } #else /* * Modify the local functions below should you wish to use * different memory routines for malloc() and free() */ #include /*! * @internal * @brief Modify this function to use a different routine than malloc(). */ static XXH_MALLOCF void* XXH_malloc(size_t s) { return malloc(s); } /*! * @internal * @brief Modify this function to use a different routine than free(). */ static void XXH_free(void* p) { free(p); } #endif /* XXH_NO_STDLIB */ #include /*! * @internal * @brief Modify this function to use a different routine than memcpy(). */ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } #include /* ULLONG_MAX */ /* ************************************* * Compiler Specific Options ***************************************/ #ifdef _MSC_VER /* Visual Studio warning fix */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #endif #if XXH_NO_INLINE_HINTS /* disable inlining hints */ # if defined(__GNUC__) || defined(__clang__) # define XXH_FORCE_INLINE static __attribute__((unused)) # else # define XXH_FORCE_INLINE static # endif # define XXH_NO_INLINE static /* enable inlining hints */ #elif defined(__GNUC__) || defined(__clang__) # define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) # define XXH_NO_INLINE static __attribute__((noinline)) #elif defined(_MSC_VER) /* Visual Studio */ # define XXH_FORCE_INLINE static __forceinline # define XXH_NO_INLINE static __declspec(noinline) #elif defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ # define XXH_FORCE_INLINE static inline # define XXH_NO_INLINE static #else # define XXH_FORCE_INLINE static # define XXH_NO_INLINE static #endif #if XXH3_INLINE_SECRET # define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE #else # define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE #endif /* ************************************* * Debug ***************************************/ /*! * @ingroup tuning * @def XXH_DEBUGLEVEL * @brief Sets the debugging level. * * XXH_DEBUGLEVEL is expected to be defined externally, typically via the * compiler's command line options. The value must be a number. */ #ifndef XXH_DEBUGLEVEL # ifdef DEBUGLEVEL /* backwards compat */ # define XXH_DEBUGLEVEL DEBUGLEVEL # else # define XXH_DEBUGLEVEL 0 # endif #endif #if (XXH_DEBUGLEVEL>=1) # include /* note: can still be disabled with NDEBUG */ # define XXH_ASSERT(c) assert(c) #else # if defined(__INTEL_COMPILER) # define XXH_ASSERT(c) XXH_ASSUME((unsigned char) (c)) # else # define XXH_ASSERT(c) XXH_ASSUME(c) # endif #endif /* note: use after variable declarations */ #ifndef XXH_STATIC_ASSERT # if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */ # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0) # elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */ # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0) # else # define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0) # endif # define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c) #endif /*! * @internal * @def XXH_COMPILER_GUARD(var) * @brief Used to prevent unwanted optimizations for @p var. * * It uses an empty GCC inline assembly statement with a register constraint * which forces @p var into a general purpose register (eg eax, ebx, ecx * on x86) and marks it as modified. * * This is used in a few places to avoid unwanted autovectorization (e.g. * XXH32_round()). All vectorization we want is explicit via intrinsics, * and _usually_ isn't wanted elsewhere. * * We also use it to prevent unwanted constant folding for AArch64 in * XXH3_initCustomSecret_scalar(). */ #if defined(__GNUC__) || defined(__clang__) # define XXH_COMPILER_GUARD(var) __asm__("" : "+r" (var)) #else # define XXH_COMPILER_GUARD(var) ((void)0) #endif /* Specifically for NEON vectors which use the "w" constraint, on * Clang. */ #if defined(__clang__) && defined(__ARM_ARCH) && !defined(__wasm__) # define XXH_COMPILER_GUARD_CLANG_NEON(var) __asm__("" : "+w" (var)) #else # define XXH_COMPILER_GUARD_CLANG_NEON(var) ((void)0) #endif /* ************************************* * Basic Types ***************************************/ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint8_t xxh_u8; #else typedef unsigned char xxh_u8; #endif typedef XXH32_hash_t xxh_u32; #ifdef XXH_OLD_NAMES # warning "XXH_OLD_NAMES is planned to be removed starting v0.9. If the program depends on it, consider moving away from it by employing newer type names directly" # define BYTE xxh_u8 # define U8 xxh_u8 # define U32 xxh_u32 #endif /* *** Memory access *** */ /*! * @internal * @fn xxh_u32 XXH_read32(const void* ptr) * @brief Reads an unaligned 32-bit integer from @p ptr in native endianness. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit native endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readLE32(const void* ptr) * @brief Reads an unaligned 32-bit little endian integer from @p ptr. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit little endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readBE32(const void* ptr) * @brief Reads an unaligned 32-bit big endian integer from @p ptr. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * * @param ptr The pointer to read from. * @return The 32-bit big endian integer from the bytes at @p ptr. */ /*! * @internal * @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) * @brief Like @ref XXH_readLE32(), but has an option for aligned reads. * * Affected by @ref XXH_FORCE_MEMORY_ACCESS. * Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is * always @ref XXH_alignment::XXH_unaligned. * * @param ptr The pointer to read from. * @param align Whether @p ptr is aligned. * @pre * If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte * aligned. * @return The 32-bit little endian integer from the bytes at @p ptr. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE32 and XXH_readBE32. */ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* * Force direct memory access. Only works on CPU which support unaligned memory * access in hardware. */ static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __attribute__((aligned(1))) is supported by gcc and clang. Originally the * documentation claimed that it only increased the alignment, but actually it * can decrease it on gcc, clang, and icc: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, * https://gcc.godbolt.org/z/xYez1j67Y. */ #ifdef XXH_OLD_NAMES typedef union { xxh_u32 u32; } __attribute__((packed)) unalign; #endif static xxh_u32 XXH_read32(const void* ptr) { typedef __attribute__((aligned(1))) xxh_u32 xxh_unalign32; return *((const xxh_unalign32*)ptr); } #else /* * Portable and safe solution. Generally efficient. * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html */ static xxh_u32 XXH_read32(const void* memPtr) { xxh_u32 val; XXH_memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ /* *** Endianness *** */ /*! * @ingroup tuning * @def XXH_CPU_LITTLE_ENDIAN * @brief Whether the target is little endian. * * Defined to 1 if the target is little endian, or 0 if it is big endian. * It can be defined externally, for example on the compiler command line. * * If it is not defined, * a runtime check (which is usually constant folded) is used instead. * * @note * This is not necessarily defined to an integer constant. * * @see XXH_isLittleEndian() for the runtime check. */ #ifndef XXH_CPU_LITTLE_ENDIAN /* * Try to detect endianness automatically, to avoid the nonstandard behavior * in `XXH_isLittleEndian()` */ # if defined(_WIN32) /* Windows is always little endian */ \ || defined(__LITTLE_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) # define XXH_CPU_LITTLE_ENDIAN 1 # elif defined(__BIG_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) # define XXH_CPU_LITTLE_ENDIAN 0 # else /*! * @internal * @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN. * * Most compilers will constant fold this. */ static int XXH_isLittleEndian(void) { /* * Portable and well-defined behavior. * Don't use static: it is detrimental to performance. */ const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 }; return one.c[0]; } # define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() # endif #endif /* **************************************** * Compiler-specific Functions and Macros ******************************************/ #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #ifdef __has_builtin # define XXH_HAS_BUILTIN(x) __has_builtin(x) #else # define XXH_HAS_BUILTIN(x) 0 #endif /* * C23 and future versions have standard "unreachable()". * Once it has been implemented reliably we can add it as an * additional case: * * ``` * #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) * # include * # ifdef unreachable * # define XXH_UNREACHABLE() unreachable() * # endif * #endif * ``` * * Note C++23 also has std::unreachable() which can be detected * as follows: * ``` * #if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L) * # include * # define XXH_UNREACHABLE() std::unreachable() * #endif * ``` * NB: `__cpp_lib_unreachable` is defined in the `` header. * We don't use that as including `` in `extern "C"` blocks * doesn't work on GCC12 */ #if XXH_HAS_BUILTIN(__builtin_unreachable) # define XXH_UNREACHABLE() __builtin_unreachable() #elif defined(_MSC_VER) # define XXH_UNREACHABLE() __assume(0) #else # define XXH_UNREACHABLE() #endif #if XXH_HAS_BUILTIN(__builtin_assume) # define XXH_ASSUME(c) __builtin_assume(c) #else # define XXH_ASSUME(c) if (!(c)) { XXH_UNREACHABLE(); } #endif /*! * @internal * @def XXH_rotl32(x,r) * @brief 32-bit rotate left. * * @param x The 32-bit integer to be rotated. * @param r The number of bits to rotate. * @pre * @p r > 0 && @p r < 32 * @note * @p x and @p r may be evaluated multiple times. * @return The rotated result. */ #if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ && XXH_HAS_BUILTIN(__builtin_rotateleft64) # define XXH_rotl32 __builtin_rotateleft32 # define XXH_rotl64 __builtin_rotateleft64 /* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ #elif defined(_MSC_VER) # define XXH_rotl32(x,r) _rotl(x,r) # define XXH_rotl64(x,r) _rotl64(x,r) #else # define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) # define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) #endif /*! * @internal * @fn xxh_u32 XXH_swap32(xxh_u32 x) * @brief A 32-bit byteswap. * * @param x The 32-bit integer to byteswap. * @return @p x, byteswapped. */ #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap32 _byteswap_ulong #elif XXH_GCC_VERSION >= 403 # define XXH_swap32 __builtin_bswap32 #else static xxh_u32 XXH_swap32 (xxh_u32 x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } #endif /* *************************** * Memory reads *****************************/ /*! * @internal * @brief Enum to indicate whether a pointer is aligned. */ typedef enum { XXH_aligned, /*!< Aligned */ XXH_unaligned /*!< Possibly unaligned */ } XXH_alignment; /* * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. * * This is ideal for older compilers which don't inline memcpy. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u32)bytePtr[1] << 8) | ((xxh_u32)bytePtr[2] << 16) | ((xxh_u32)bytePtr[3] << 24); } XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[3] | ((xxh_u32)bytePtr[2] << 8) | ((xxh_u32)bytePtr[1] << 16) | ((xxh_u32)bytePtr[0] << 24); } #else XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); } static xxh_u32 XXH_readBE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); } #endif XXH_FORCE_INLINE xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) { return XXH_readLE32(ptr); } else { return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); } } /* ************************************* * Misc ***************************************/ /*! @ingroup public */ XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } /* ******************************************************************* * 32-bit hash functions *********************************************************************/ /*! * @} * @defgroup XXH32_impl XXH32 implementation * @ingroup impl * * Details on the XXH32 implementation. * @{ */ /* #define instead of static const, to be used as initializers */ #define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */ #define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */ #define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */ #define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */ #define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */ #ifdef XXH_OLD_NAMES # define PRIME32_1 XXH_PRIME32_1 # define PRIME32_2 XXH_PRIME32_2 # define PRIME32_3 XXH_PRIME32_3 # define PRIME32_4 XXH_PRIME32_4 # define PRIME32_5 XXH_PRIME32_5 #endif /*! * @internal * @brief Normal stripe processing routine. * * This shuffles the bits so that any bit from @p input impacts several bits in * @p acc. * * @param acc The accumulator lane. * @param input The stripe of input to mix. * @return The mixed accumulator lane. */ static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input) { acc += input * XXH_PRIME32_2; acc = XXH_rotl32(acc, 13); acc *= XXH_PRIME32_1; #if (defined(__SSE4_1__) || defined(__aarch64__) || defined(__wasm_simd128__)) && !defined(XXH_ENABLE_AUTOVECTORIZE) /* * UGLY HACK: * A compiler fence is the only thing that prevents GCC and Clang from * autovectorizing the XXH32 loop (pragmas and attributes don't work for some * reason) without globally disabling SSE4.1. * * The reason we want to avoid vectorization is because despite working on * 4 integers at a time, there are multiple factors slowing XXH32 down on * SSE4: * - There's a ridiculous amount of lag from pmulld (10 cycles of latency on * newer chips!) making it slightly slower to multiply four integers at * once compared to four integers independently. Even when pmulld was * fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE * just to multiply unless doing a long operation. * * - Four instructions are required to rotate, * movqda tmp, v // not required with VEX encoding * pslld tmp, 13 // tmp <<= 13 * psrld v, 19 // x >>= 19 * por v, tmp // x |= tmp * compared to one for scalar: * roll v, 13 // reliably fast across the board * shldl v, v, 13 // Sandy Bridge and later prefer this for some reason * * - Instruction level parallelism is actually more beneficial here because * the SIMD actually serializes this operation: While v1 is rotating, v2 * can load data, while v3 can multiply. SSE forces them to operate * together. * * This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing * the loop. NEON is only faster on the A53, and with the newer cores, it is less * than half the speed. * * Additionally, this is used on WASM SIMD128 because it JITs to the same * SIMD instructions and has the same issue. */ XXH_COMPILER_GUARD(acc); #endif return acc; } /*! * @internal * @brief Mixes all bits to finalize the hash. * * The final mix ensures that all input bits have a chance to impact any bit in * the output digest, resulting in an unbiased distribution. * * @param hash The hash to avalanche. * @return The avalanched hash. */ static xxh_u32 XXH32_avalanche(xxh_u32 hash) { hash ^= hash >> 15; hash *= XXH_PRIME32_2; hash ^= hash >> 13; hash *= XXH_PRIME32_3; hash ^= hash >> 16; return hash; } #define XXH_get32bits(p) XXH_readLE32_align(p, align) /*! * @internal * @brief Processes the last 0-15 bytes of @p ptr. * * There may be up to 15 bytes remaining to consume from the input. * This final stage will digest them to ensure that all input bytes are present * in the final mix. * * @param hash The hash to finalize. * @param ptr The pointer to the remaining input. * @param len The remaining length, modulo 16. * @param align Whether @p ptr is aligned. * @return The finalized hash. * @see XXH64_finalize(). */ static XXH_PUREF xxh_u32 XXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) { #define XXH_PROCESS1 do { \ hash += (*ptr++) * XXH_PRIME32_5; \ hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; \ } while (0) #define XXH_PROCESS4 do { \ hash += XXH_get32bits(ptr) * XXH_PRIME32_3; \ ptr += 4; \ hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; \ } while (0) if (ptr==NULL) XXH_ASSERT(len == 0); /* Compact rerolled version; generally faster */ if (!XXH32_ENDJMP) { len &= 15; while (len >= 4) { XXH_PROCESS4; len -= 4; } while (len > 0) { XXH_PROCESS1; --len; } return XXH32_avalanche(hash); } else { switch(len&15) /* or switch(bEnd - p) */ { case 12: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 8: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 4: XXH_PROCESS4; return XXH32_avalanche(hash); case 13: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 9: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 5: XXH_PROCESS4; XXH_PROCESS1; return XXH32_avalanche(hash); case 14: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 10: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 6: XXH_PROCESS4; XXH_PROCESS1; XXH_PROCESS1; return XXH32_avalanche(hash); case 15: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 11: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 7: XXH_PROCESS4; XXH_FALLTHROUGH; /* fallthrough */ case 3: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 2: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 1: XXH_PROCESS1; XXH_FALLTHROUGH; /* fallthrough */ case 0: return XXH32_avalanche(hash); } XXH_ASSERT(0); return hash; /* reaching this point is deemed impossible */ } } #ifdef XXH_OLD_NAMES # define PROCESS1 XXH_PROCESS1 # define PROCESS4 XXH_PROCESS4 #else # undef XXH_PROCESS1 # undef XXH_PROCESS4 #endif /*! * @internal * @brief The implementation for @ref XXH32(). * * @param input , len , seed Directly passed from @ref XXH32(). * @param align Whether @p input is aligned. * @return The calculated hash. */ XXH_FORCE_INLINE XXH_PUREF xxh_u32 XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align) { xxh_u32 h32; if (input==NULL) XXH_ASSERT(len == 0); if (len>=16) { const xxh_u8* const bEnd = input + len; const xxh_u8* const limit = bEnd - 15; xxh_u32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; xxh_u32 v2 = seed + XXH_PRIME32_2; xxh_u32 v3 = seed + 0; xxh_u32 v4 = seed - XXH_PRIME32_1; do { v1 = XXH32_round(v1, XXH_get32bits(input)); input += 4; v2 = XXH32_round(v2, XXH_get32bits(input)); input += 4; v3 = XXH32_round(v3, XXH_get32bits(input)); input += 4; v4 = XXH32_round(v4, XXH_get32bits(input)); input += 4; } while (input < limit); h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); } else { h32 = seed + XXH_PRIME32_5; } h32 += (xxh_u32)len; return XXH32_finalize(h32, input, len&15, align); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed) { #if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH32_state_t state; XXH32_reset(&state, seed); XXH32_update(&state, (const xxh_u8*)input, len); return XXH32_digest(&state); #else if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); #endif } /******* Hash streaming *******/ #ifndef XXH_NO_STREAM /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) { return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) { XXH_memcpy(dstState, srcState, sizeof(*dstState)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed) { XXH_ASSERT(statePtr != NULL); memset(statePtr, 0, sizeof(*statePtr)); statePtr->v[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2; statePtr->v[1] = seed + XXH_PRIME32_2; statePtr->v[2] = seed + 0; statePtr->v[3] = seed - XXH_PRIME32_1; return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH_errorcode XXH32_update(XXH32_state_t* state, const void* input, size_t len) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } { const xxh_u8* p = (const xxh_u8*)input; const xxh_u8* const bEnd = p + len; state->total_len_32 += (XXH32_hash_t)len; state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16)); if (state->memsize + len < 16) { /* fill in tmp buffer */ XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, len); state->memsize += (XXH32_hash_t)len; return XXH_OK; } if (state->memsize) { /* some data left from previous update */ XXH_memcpy((xxh_u8*)(state->mem32) + state->memsize, input, 16-state->memsize); { const xxh_u32* p32 = state->mem32; state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p32)); p32++; state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p32)); p32++; state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p32)); p32++; state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p32)); } p += 16-state->memsize; state->memsize = 0; } if (p <= bEnd-16) { const xxh_u8* const limit = bEnd - 16; do { state->v[0] = XXH32_round(state->v[0], XXH_readLE32(p)); p+=4; state->v[1] = XXH32_round(state->v[1], XXH_readLE32(p)); p+=4; state->v[2] = XXH32_round(state->v[2], XXH_readLE32(p)); p+=4; state->v[3] = XXH32_round(state->v[3], XXH_readLE32(p)); p+=4; } while (p<=limit); } if (p < bEnd) { XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); state->memsize = (unsigned)(bEnd-p); } } return XXH_OK; } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state) { xxh_u32 h32; if (state->large_len) { h32 = XXH_rotl32(state->v[0], 1) + XXH_rotl32(state->v[1], 7) + XXH_rotl32(state->v[2], 12) + XXH_rotl32(state->v[3], 18); } else { h32 = state->v[2] /* == seed */ + XXH_PRIME32_5; } h32 += state->total_len_32; return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned); } #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! * @ingroup XXH32_family * The default return values from XXH functions are unsigned 32 and 64 bit * integers. * * The canonical representation uses big endian convention, the same convention * as human-readable numbers (large digits first). * * This way, hash values can be written into a file or buffer, remaining * comparable across different systems. * * The following functions allow transformation of hash values to and from their * canonical format. */ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); XXH_memcpy(dst, &hash, sizeof(*dst)); } /*! @ingroup XXH32_family */ XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) { return XXH_readBE32(src); } #ifndef XXH_NO_LONG_LONG /* ******************************************************************* * 64-bit hash functions *********************************************************************/ /*! * @} * @ingroup impl * @{ */ /******* Memory access *******/ typedef XXH64_hash_t xxh_u64; #ifdef XXH_OLD_NAMES # define U64 xxh_u64 #endif #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE64 and XXH_readBE64. */ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ static xxh_u64 XXH_read64(const void* memPtr) { return *(const xxh_u64*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __attribute__((aligned(1))) is supported by gcc and clang. Originally the * documentation claimed that it only increased the alignment, but actually it * can decrease it on gcc, clang, and icc: * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502, * https://gcc.godbolt.org/z/xYez1j67Y. */ #ifdef XXH_OLD_NAMES typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64; #endif static xxh_u64 XXH_read64(const void* ptr) { typedef __attribute__((aligned(1))) xxh_u64 xxh_unalign64; return *((const xxh_unalign64*)ptr); } #else /* * Portable and safe solution. Generally efficient. * see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html */ static xxh_u64 XXH_read64(const void* memPtr) { xxh_u64 val; XXH_memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap64 _byteswap_uint64 #elif XXH_GCC_VERSION >= 403 # define XXH_swap64 __builtin_bswap64 #else static xxh_u64 XXH_swap64(xxh_u64 x) { return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | ((x >> 8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL); } #endif /* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u64)bytePtr[1] << 8) | ((xxh_u64)bytePtr[2] << 16) | ((xxh_u64)bytePtr[3] << 24) | ((xxh_u64)bytePtr[4] << 32) | ((xxh_u64)bytePtr[5] << 40) | ((xxh_u64)bytePtr[6] << 48) | ((xxh_u64)bytePtr[7] << 56); } XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[7] | ((xxh_u64)bytePtr[6] << 8) | ((xxh_u64)bytePtr[5] << 16) | ((xxh_u64)bytePtr[4] << 24) | ((xxh_u64)bytePtr[3] << 32) | ((xxh_u64)bytePtr[2] << 40) | ((xxh_u64)bytePtr[1] << 48) | ((xxh_u64)bytePtr[0] << 56); } #else XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); } static xxh_u64 XXH_readBE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); } #endif XXH_FORCE_INLINE xxh_u64 XXH_readLE64_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) return XXH_readLE64(ptr); else return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); } /******* xxh64 *******/ /*! * @} * @defgroup XXH64_impl XXH64 implementation * @ingroup impl * * Details on the XXH64 implementation. * @{ */ /* #define rather that static const, to be used as initializers */ #define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */ #define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */ #define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */ #define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */ #define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */ #ifdef XXH_OLD_NAMES # define PRIME64_1 XXH_PRIME64_1 # define PRIME64_2 XXH_PRIME64_2 # define PRIME64_3 XXH_PRIME64_3 # define PRIME64_4 XXH_PRIME64_4 # define PRIME64_5 XXH_PRIME64_5 #endif /*! @copydoc XXH32_round */ static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) { acc += input * XXH_PRIME64_2; acc = XXH_rotl64(acc, 31); acc *= XXH_PRIME64_1; return acc; } static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) { val = XXH64_round(0, val); acc ^= val; acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; return acc; } /*! @copydoc XXH32_avalanche */ static xxh_u64 XXH64_avalanche(xxh_u64 hash) { hash ^= hash >> 33; hash *= XXH_PRIME64_2; hash ^= hash >> 29; hash *= XXH_PRIME64_3; hash ^= hash >> 32; return hash; } #define XXH_get64bits(p) XXH_readLE64_align(p, align) /*! * @internal * @brief Processes the last 0-31 bytes of @p ptr. * * There may be up to 31 bytes remaining to consume from the input. * This final stage will digest them to ensure that all input bytes are present * in the final mix. * * @param hash The hash to finalize. * @param ptr The pointer to the remaining input. * @param len The remaining length, modulo 32. * @param align Whether @p ptr is aligned. * @return The finalized hash * @see XXH32_finalize(). */ static XXH_PUREF xxh_u64 XXH64_finalize(xxh_u64 hash, const xxh_u8* ptr, size_t len, XXH_alignment align) { if (ptr==NULL) XXH_ASSERT(len == 0); len &= 31; while (len >= 8) { xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); ptr += 8; hash ^= k1; hash = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4; len -= 8; } if (len >= 4) { hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; ptr += 4; hash = XXH_rotl64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; len -= 4; } while (len > 0) { hash ^= (*ptr++) * XXH_PRIME64_5; hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1; --len; } return XXH64_avalanche(hash); } #ifdef XXH_OLD_NAMES # define PROCESS1_64 XXH_PROCESS1_64 # define PROCESS4_64 XXH_PROCESS4_64 # define PROCESS8_64 XXH_PROCESS8_64 #else # undef XXH_PROCESS1_64 # undef XXH_PROCESS4_64 # undef XXH_PROCESS8_64 #endif /*! * @internal * @brief The implementation for @ref XXH64(). * * @param input , len , seed Directly passed from @ref XXH64(). * @param align Whether @p input is aligned. * @return The calculated hash. */ XXH_FORCE_INLINE XXH_PUREF xxh_u64 XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align) { xxh_u64 h64; if (input==NULL) XXH_ASSERT(len == 0); if (len>=32) { const xxh_u8* const bEnd = input + len; const xxh_u8* const limit = bEnd - 31; xxh_u64 v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; xxh_u64 v2 = seed + XXH_PRIME64_2; xxh_u64 v3 = seed + 0; xxh_u64 v4 = seed - XXH_PRIME64_1; do { v1 = XXH64_round(v1, XXH_get64bits(input)); input+=8; v2 = XXH64_round(v2, XXH_get64bits(input)); input+=8; v3 = XXH64_round(v3, XXH_get64bits(input)); input+=8; v4 = XXH64_round(v4, XXH_get64bits(input)); input+=8; } while (input= 2 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH64_state_t state; XXH64_reset(&state, seed); XXH64_update(&state, (const xxh_u8*)input, len); return XXH64_digest(&state); #else if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned); } } return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned); #endif } /******* Hash Streaming *******/ #ifndef XXH_NO_STREAM /*! @ingroup XXH64_family*/ XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) { return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState) { XXH_memcpy(dstState, srcState, sizeof(*dstState)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed) { XXH_ASSERT(statePtr != NULL); memset(statePtr, 0, sizeof(*statePtr)); statePtr->v[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2; statePtr->v[1] = seed + XXH_PRIME64_2; statePtr->v[2] = seed + 0; statePtr->v[3] = seed - XXH_PRIME64_1; return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* state, XXH_NOESCAPE const void* input, size_t len) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } { const xxh_u8* p = (const xxh_u8*)input; const xxh_u8* const bEnd = p + len; state->total_len += len; if (state->memsize + len < 32) { /* fill in tmp buffer */ XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); state->memsize += (xxh_u32)len; return XXH_OK; } if (state->memsize) { /* tmp buffer is full */ XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); state->v[0] = XXH64_round(state->v[0], XXH_readLE64(state->mem64+0)); state->v[1] = XXH64_round(state->v[1], XXH_readLE64(state->mem64+1)); state->v[2] = XXH64_round(state->v[2], XXH_readLE64(state->mem64+2)); state->v[3] = XXH64_round(state->v[3], XXH_readLE64(state->mem64+3)); p += 32 - state->memsize; state->memsize = 0; } if (p+32 <= bEnd) { const xxh_u8* const limit = bEnd - 32; do { state->v[0] = XXH64_round(state->v[0], XXH_readLE64(p)); p+=8; state->v[1] = XXH64_round(state->v[1], XXH_readLE64(p)); p+=8; state->v[2] = XXH64_round(state->v[2], XXH_readLE64(p)); p+=8; state->v[3] = XXH64_round(state->v[3], XXH_readLE64(p)); p+=8; } while (p<=limit); } if (p < bEnd) { XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); state->memsize = (unsigned)(bEnd-p); } } return XXH_OK; } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state) { xxh_u64 h64; if (state->total_len >= 32) { h64 = XXH_rotl64(state->v[0], 1) + XXH_rotl64(state->v[1], 7) + XXH_rotl64(state->v[2], 12) + XXH_rotl64(state->v[3], 18); h64 = XXH64_mergeRound(h64, state->v[0]); h64 = XXH64_mergeRound(h64, state->v[1]); h64 = XXH64_mergeRound(h64, state->v[2]); h64 = XXH64_mergeRound(h64, state->v[3]); } else { h64 = state->v[2] /*seed*/ + XXH_PRIME64_5; } h64 += (xxh_u64) state->total_len; return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); } #endif /* !XXH_NO_STREAM */ /******* Canonical representation *******/ /*! @ingroup XXH64_family */ XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); XXH_memcpy(dst, &hash, sizeof(*dst)); } /*! @ingroup XXH64_family */ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src) { return XXH_readBE64(src); } #ifndef XXH_NO_XXH3 /* ********************************************************************* * XXH3 * New generation hash designed for speed on small keys and vectorization ************************************************************************ */ /*! * @} * @defgroup XXH3_impl XXH3 implementation * @ingroup impl * @{ */ /* === Compiler specifics === */ #if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */ # define XXH_RESTRICT /* disable */ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */ # define XXH_RESTRICT restrict #elif (defined (__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \ || (defined (__clang__)) \ || (defined (_MSC_VER) && (_MSC_VER >= 1400)) \ || (defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300)) /* * There are a LOT more compilers that recognize __restrict but this * covers the major ones. */ # define XXH_RESTRICT __restrict #else # define XXH_RESTRICT /* disable */ #endif #if (defined(__GNUC__) && (__GNUC__ >= 3)) \ || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ || defined(__clang__) # define XXH_likely(x) __builtin_expect(x, 1) # define XXH_unlikely(x) __builtin_expect(x, 0) #else # define XXH_likely(x) (x) # define XXH_unlikely(x) (x) #endif #ifndef XXH_HAS_INCLUDE # ifdef __has_include # define XXH_HAS_INCLUDE(x) __has_include(x) # else # define XXH_HAS_INCLUDE(x) 0 # endif #endif #if defined(__GNUC__) || defined(__clang__) # if defined(__ARM_FEATURE_SVE) # include # endif # if defined(__ARM_NEON__) || defined(__ARM_NEON) \ || (defined(_M_ARM) && _M_ARM >= 7) \ || defined(_M_ARM64) || defined(_M_ARM64EC) \ || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* WASM SIMD128 via SIMDe */ # define inline __inline__ /* circumvent a clang bug */ # include # undef inline # elif defined(__AVX2__) # include # elif defined(__SSE2__) # include # endif #endif #if defined(_MSC_VER) # include #endif /* * One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while * remaining a true 64-bit/128-bit hash function. * * This is done by prioritizing a subset of 64-bit operations that can be * emulated without too many steps on the average 32-bit machine. * * For example, these two lines seem similar, and run equally fast on 64-bit: * * xxh_u64 x; * x ^= (x >> 47); // good * x ^= (x >> 13); // bad * * However, to a 32-bit machine, there is a major difference. * * x ^= (x >> 47) looks like this: * * x.lo ^= (x.hi >> (47 - 32)); * * while x ^= (x >> 13) looks like this: * * // note: funnel shifts are not usually cheap. * x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13)); * x.hi ^= (x.hi >> 13); * * The first one is significantly faster than the second, simply because the * shift is larger than 32. This means: * - All the bits we need are in the upper 32 bits, so we can ignore the lower * 32 bits in the shift. * - The shift result will always fit in the lower 32 bits, and therefore, * we can ignore the upper 32 bits in the xor. * * Thanks to this optimization, XXH3 only requires these features to be efficient: * * - Usable unaligned access * - A 32-bit or 64-bit ALU * - If 32-bit, a decent ADC instruction * - A 32 or 64-bit multiply with a 64-bit result * - For the 128-bit variant, a decent byteswap helps short inputs. * * The first two are already required by XXH32, and almost all 32-bit and 64-bit * platforms which can run XXH32 can run XXH3 efficiently. * * Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one * notable exception. * * First of all, Thumb-1 lacks support for the UMULL instruction which * performs the important long multiply. This means numerous __aeabi_lmul * calls. * * Second of all, the 8 functional registers are just not enough. * Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need * Lo registers, and this shuffling results in thousands more MOVs than A32. * * A32 and T32 don't have this limitation. They can access all 14 registers, * do a 32->64 multiply with UMULL, and the flexible operand allowing free * shifts is helpful, too. * * Therefore, we do a quick sanity check. * * If compiling Thumb-1 for a target which supports ARM instructions, we will * emit a warning, as it is not a "sane" platform to compile for. * * Usually, if this happens, it is because of an accident and you probably need * to specify -march, as you likely meant to compile for a newer architecture. * * Credit: large sections of the vectorial and asm source code paths * have been contributed by @easyaspi314 */ #if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) # warning "XXH3 is highly inefficient without ARM or Thumb-2." #endif /* ========================================== * Vectorization detection * ========================================== */ #ifdef XXH_DOXYGEN /*! * @ingroup tuning * @brief Overrides the vectorization implementation chosen for XXH3. * * Can be defined to 0 to disable SIMD or any of the values mentioned in * @ref XXH_VECTOR_TYPE. * * If this is not defined, it uses predefined macros to determine the best * implementation. */ # define XXH_VECTOR XXH_SCALAR /*! * @ingroup tuning * @brief Possible values for @ref XXH_VECTOR. * * Note that these are actually implemented as macros. * * If this is not defined, it is detected automatically. * internal macro XXH_X86DISPATCH overrides this. */ enum XXH_VECTOR_TYPE /* fake enum */ { XXH_SCALAR = 0, /*!< Portable scalar version */ XXH_SSE2 = 1, /*!< * SSE2 for Pentium 4, Opteron, all x86_64. * * @note SSE2 is also guaranteed on Windows 10, macOS, and * Android x86. */ XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */ XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */ XXH_NEON = 4, /*!< * NEON for most ARMv7-A, all AArch64, and WASM SIMD128 * via the SIMDeverywhere polyfill provided with the * Emscripten SDK. */ XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */ XXH_SVE = 6, /*!< SVE for some ARMv8-A and ARMv9-A */ }; /*! * @ingroup tuning * @brief Selects the minimum alignment for XXH3's accumulators. * * When using SIMD, this should match the alignment required for said vector * type, so, for example, 32 for AVX2. * * Default: Auto detected. */ # define XXH_ACC_ALIGN 8 #endif /* Actual definition */ #ifndef XXH_DOXYGEN # define XXH_SCALAR 0 # define XXH_SSE2 1 # define XXH_AVX2 2 # define XXH_AVX512 3 # define XXH_NEON 4 # define XXH_VSX 5 # define XXH_SVE 6 #endif #ifndef XXH_VECTOR /* can be defined on command line */ # if defined(__ARM_FEATURE_SVE) # define XXH_VECTOR XXH_SVE # elif ( \ defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \ || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \ || (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* wasm simd128 via SIMDe */ \ ) && ( \ defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ ) # define XXH_VECTOR XXH_NEON # elif defined(__AVX512F__) # define XXH_VECTOR XXH_AVX512 # elif defined(__AVX2__) # define XXH_VECTOR XXH_AVX2 # elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) # define XXH_VECTOR XXH_SSE2 # elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ || (defined(__s390x__) && defined(__VEC__)) \ && defined(__GNUC__) /* TODO: IBM XL */ # define XXH_VECTOR XXH_VSX # else # define XXH_VECTOR XXH_SCALAR # endif #endif /* __ARM_FEATURE_SVE is only supported by GCC & Clang. */ #if (XXH_VECTOR == XXH_SVE) && !defined(__ARM_FEATURE_SVE) # ifdef _MSC_VER # pragma warning(once : 4606) # else # warning "__ARM_FEATURE_SVE isn't supported. Use SCALAR instead." # endif # undef XXH_VECTOR # define XXH_VECTOR XXH_SCALAR #endif /* * Controls the alignment of the accumulator, * for compatibility with aligned vector loads, which are usually faster. */ #ifndef XXH_ACC_ALIGN # if defined(XXH_X86DISPATCH) # define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ # elif XXH_VECTOR == XXH_SCALAR /* scalar */ # define XXH_ACC_ALIGN 8 # elif XXH_VECTOR == XXH_SSE2 /* sse2 */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX2 /* avx2 */ # define XXH_ACC_ALIGN 32 # elif XXH_VECTOR == XXH_NEON /* neon */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_VSX /* vsx */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX512 /* avx512 */ # define XXH_ACC_ALIGN 64 # elif XXH_VECTOR == XXH_SVE /* sve */ # define XXH_ACC_ALIGN 64 # endif #endif #if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 # define XXH_SEC_ALIGN XXH_ACC_ALIGN #elif XXH_VECTOR == XXH_SVE # define XXH_SEC_ALIGN XXH_ACC_ALIGN #else # define XXH_SEC_ALIGN 8 #endif #if defined(__GNUC__) || defined(__clang__) # define XXH_ALIASING __attribute__((may_alias)) #else # define XXH_ALIASING /* nothing */ #endif /* * UGLY HACK: * GCC usually generates the best code with -O3 for xxHash. * * However, when targeting AVX2, it is overzealous in its unrolling resulting * in code roughly 3/4 the speed of Clang. * * There are other issues, such as GCC splitting _mm256_loadu_si256 into * _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which * only applies to Sandy and Ivy Bridge... which don't even support AVX2. * * That is why when compiling the AVX2 version, it is recommended to use either * -O2 -mavx2 -march=haswell * or * -O2 -mavx2 -mno-avx256-split-unaligned-load * for decent performance, or to use Clang instead. * * Fortunately, we can control the first one with a pragma that forces GCC into * -O2, but the other one we can't control without "failed to inline always * inline function due to target mismatch" warnings. */ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */ # pragma GCC push_options # pragma GCC optimize("-O2") #endif #if XXH_VECTOR == XXH_NEON /* * UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3 * optimizes out the entire hashLong loop because of the aliasing violation. * * However, GCC is also inefficient at load-store optimization with vld1q/vst1q, * so the only option is to mark it as aliasing. */ typedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING; /*! * @internal * @brief `vld1q_u64` but faster and alignment-safe. * * On AArch64, unaligned access is always safe, but on ARMv7-a, it is only * *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86). * * GCC for AArch64 sees `vld1q_u8` as an intrinsic instead of a load, so it * prohibits load-store optimizations. Therefore, a direct dereference is used. * * Otherwise, `vld1q_u8` is used with `vreinterpretq_u8_u64` to do a safe * unaligned load. */ #if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */ { return *(xxh_aliasing_uint64x2_t const *)ptr; } #else XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) { return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr)); } #endif /*! * @internal * @brief `vmlal_u32` on low and high halves of a vector. * * This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with * inline assembly and were therefore incapable of merging the `vget_{low, high}_u32` * with `vmlal_u32`. */ #if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11 XXH_FORCE_INLINE uint64x2_t XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { /* Inline assembly is the only way */ __asm__("umlal %0.2d, %1.2s, %2.2s" : "+w" (acc) : "w" (lhs), "w" (rhs)); return acc; } XXH_FORCE_INLINE uint64x2_t XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { /* This intrinsic works as expected */ return vmlal_high_u32(acc, lhs, rhs); } #else /* Portable intrinsic versions */ XXH_FORCE_INLINE uint64x2_t XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { return vmlal_u32(acc, vget_low_u32(lhs), vget_low_u32(rhs)); } /*! @copydoc XXH_vmlal_low_u32 * Assume the compiler converts this to vmlal_high_u32 on aarch64 */ XXH_FORCE_INLINE uint64x2_t XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs) { return vmlal_u32(acc, vget_high_u32(lhs), vget_high_u32(rhs)); } #endif /*! * @ingroup tuning * @brief Controls the NEON to scalar ratio for XXH3 * * This can be set to 2, 4, 6, or 8. * * ARM Cortex CPUs are _very_ sensitive to how their pipelines are used. * * For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but only 2 of those * can be NEON. If you are only using NEON instructions, you are only using 2/3 of the CPU * bandwidth. * * This is even more noticeable on the more advanced cores like the Cortex-A76 which * can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once. * * Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes * and 2 scalar lanes, which is chosen by default. * * This does not apply to Apple processors or 32-bit processors, which run better with * full NEON. These will default to 8. Additionally, size-optimized builds run 8 lanes. * * This change benefits CPUs with large micro-op buffers without negatively affecting * most other CPUs: * * | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. | * |:----------------------|:--------------------|----------:|-----------:|------:| * | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% | * | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% | * | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% | * | Apple M1 | 4 NEON/8 micro-ops | 37.3 GB/s | 36.1 GB/s | ~-3% | * * It also seems to fix some bad codegen on GCC, making it almost as fast as clang. * * When using WASM SIMD128, if this is 2 or 6, SIMDe will scalarize 2 of the lanes meaning * it effectively becomes worse 4. * * @see XXH3_accumulate_512_neon() */ # ifndef XXH3_NEON_LANES # if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \ && !defined(__APPLE__) && XXH_SIZE_OPT <= 0 # define XXH3_NEON_LANES 6 # else # define XXH3_NEON_LANES XXH_ACC_NB # endif # endif #endif /* XXH_VECTOR == XXH_NEON */ /* * VSX and Z Vector helpers. * * This is very messy, and any pull requests to clean this up are welcome. * * There are a lot of problems with supporting VSX and s390x, due to * inconsistent intrinsics, spotty coverage, and multiple endiannesses. */ #if XXH_VECTOR == XXH_VSX /* Annoyingly, these headers _may_ define three macros: `bool`, `vector`, * and `pixel`. This is a problem for obvious reasons. * * These keywords are unnecessary; the spec literally says they are * equivalent to `__bool`, `__vector`, and `__pixel` and may be undef'd * after including the header. * * We use pragma push_macro/pop_macro to keep the namespace clean. */ # pragma push_macro("bool") # pragma push_macro("vector") # pragma push_macro("pixel") /* silence potential macro redefined warnings */ # undef bool # undef vector # undef pixel # if defined(__s390x__) # include # else # include # endif /* Restore the original macro values, if applicable. */ # pragma pop_macro("pixel") # pragma pop_macro("vector") # pragma pop_macro("bool") typedef __vector unsigned long long xxh_u64x2; typedef __vector unsigned char xxh_u8x16; typedef __vector unsigned xxh_u32x4; /* * UGLY HACK: Similar to aarch64 macOS GCC, s390x GCC has the same aliasing issue. */ typedef xxh_u64x2 xxh_aliasing_u64x2 XXH_ALIASING; # ifndef XXH_VSX_BE # if defined(__BIG_ENDIAN__) \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) # define XXH_VSX_BE 1 # elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__ # warning "-maltivec=be is not recommended. Please use native endianness." # define XXH_VSX_BE 1 # else # define XXH_VSX_BE 0 # endif # endif /* !defined(XXH_VSX_BE) */ # if XXH_VSX_BE # if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__)) # define XXH_vec_revb vec_revb # else /*! * A polyfill for POWER9's vec_revb(). */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val) { xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 }; return vec_perm(val, val, vByteSwap); } # endif # endif /* XXH_VSX_BE */ /*! * Performs an unaligned vector load and byte swaps it on big endian. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) { xxh_u64x2 ret; XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2)); # if XXH_VSX_BE ret = XXH_vec_revb(ret); # endif return ret; } /* * vec_mulo and vec_mule are very problematic intrinsics on PowerPC * * These intrinsics weren't added until GCC 8, despite existing for a while, * and they are endian dependent. Also, their meaning swap depending on version. * */ # if defined(__s390x__) /* s390x is always big endian, no issue on this platform */ # define XXH_vec_mulo vec_mulo # define XXH_vec_mule vec_mule # elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) && !defined(__ibmxl__) /* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ /* The IBM XL Compiler (which defined __clang__) only implements the vec_* operations */ # define XXH_vec_mulo __builtin_altivec_vmulouw # define XXH_vec_mule __builtin_altivec_vmuleuw # else /* gcc needs inline assembly */ /* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } # endif /* XXH_vec_mulo, XXH_vec_mule */ #endif /* XXH_VECTOR == XXH_VSX */ #if XXH_VECTOR == XXH_SVE #define ACCRND(acc, offset) \ do { \ svuint64_t input_vec = svld1_u64(mask, xinput + offset); \ svuint64_t secret_vec = svld1_u64(mask, xsecret + offset); \ svuint64_t mixed = sveor_u64_x(mask, secret_vec, input_vec); \ svuint64_t swapped = svtbl_u64(input_vec, kSwap); \ svuint64_t mixed_lo = svextw_u64_x(mask, mixed); \ svuint64_t mixed_hi = svlsr_n_u64_x(mask, mixed, 32); \ svuint64_t mul = svmad_u64_x(mask, mixed_lo, mixed_hi, swapped); \ acc = svadd_u64_x(mask, acc, mul); \ } while (0) #endif /* XXH_VECTOR == XXH_SVE */ /* prefetch * can be disabled, by declaring XXH_NO_PREFETCH build macro */ #if defined(XXH_NO_PREFETCH) # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ #else # if XXH_SIZE_OPT >= 1 # define XXH_PREFETCH(ptr) (void)(ptr) # elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */ # include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # else # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ # endif #endif /* XXH_NO_PREFETCH */ /* ========================================== * XXH3 default settings * ========================================== */ #define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ #if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) # error "default keyset is not large enough" #endif /*! Pseudorandom secret taken directly from FARSH. */ XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, }; static const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL; /*!< 0b0001011001010110011001111001000110011110001101110111100111111001 */ static const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; /*!< 0b1001111110110010000111000110010100011110100110001101111100100101 */ #ifdef XXH_OLD_NAMES # define kSecret XXH3_kSecret #endif #ifdef XXH_DOXYGEN /*! * @brief Calculates a 32-bit to 64-bit long multiply. * * Implemented as a macro. * * Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't * need to (but it shouldn't need to anyways, it is about 7 instructions to do * a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we * use that instead of the normal method. * * If you are compiling for platforms like Thumb-1 and don't have a better option, * you may also want to write your own long multiply routine here. * * @param x, y Numbers to be multiplied * @return 64-bit product of the low 32 bits of @p x and @p y. */ XXH_FORCE_INLINE xxh_u64 XXH_mult32to64(xxh_u64 x, xxh_u64 y) { return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF); } #elif defined(_MSC_VER) && defined(_M_IX86) # define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) #else /* * Downcast + upcast is usually better than masking on older compilers like * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. * * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands * and perform a full 64x64 multiply -- entirely redundant on 32-bit. */ # define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) #endif /*! * @brief Calculates a 64->128-bit long multiply. * * Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar * version. * * @param lhs , rhs The 64-bit integers to be multiplied * @return The 128-bit result represented in an @ref XXH128_hash_t. */ static XXH128_hash_t XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) { /* * GCC/Clang __uint128_t method. * * On most 64-bit targets, GCC and Clang define a __uint128_t type. * This is usually the best way as it usually uses a native long 64-bit * multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64. * * Usually. * * Despite being a 32-bit platform, Clang (and emscripten) define this type * despite not having the arithmetic for it. This results in a laggy * compiler builtin call which calculates a full 128-bit multiply. * In that case it is best to use the portable one. * https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677 */ #if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \ && defined(__SIZEOF_INT128__) \ || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; XXH128_hash_t r128; r128.low64 = (xxh_u64)(product); r128.high64 = (xxh_u64)(product >> 64); return r128; /* * MSVC for x64's _umul128 method. * * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); * * This compiles to single operand MUL on x64. */ #elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC) #ifndef _MSC_VER # pragma intrinsic(_umul128) #endif xxh_u64 product_high; xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); XXH128_hash_t r128; r128.low64 = product_low; r128.high64 = product_high; return r128; /* * MSVC for ARM64's __umulh method. * * This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method. */ #elif defined(_M_ARM64) || defined(_M_ARM64EC) #ifndef _MSC_VER # pragma intrinsic(__umulh) #endif XXH128_hash_t r128; r128.low64 = lhs * rhs; r128.high64 = __umulh(lhs, rhs); return r128; #else /* * Portable scalar method. Optimized for 32-bit and 64-bit ALUs. * * This is a fast and simple grade school multiply, which is shown below * with base 10 arithmetic instead of base 0x100000000. * * 9 3 // D2 lhs = 93 * x 7 5 // D2 rhs = 75 * ---------- * 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15 * 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45 * 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21 * + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63 * --------- * 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27 * + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67 * --------- * 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975 * * The reasons for adding the products like this are: * 1. It avoids manual carry tracking. Just like how * (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX. * This avoids a lot of complexity. * * 2. It hints for, and on Clang, compiles to, the powerful UMAAL * instruction available in ARM's Digital Signal Processing extension * in 32-bit ARMv6 and later, which is shown below: * * void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm) * { * xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm; * *RdLo = (xxh_u32)(product & 0xFFFFFFFF); * *RdHi = (xxh_u32)(product >> 32); * } * * This instruction was designed for efficient long multiplication, and * allows this to be calculated in only 4 instructions at speeds * comparable to some 64-bit ALUs. * * 3. It isn't terrible on other platforms. Usually this will be a couple * of 32-bit ADD/ADCs. */ /* First calculate all of the cross products. */ xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); /* Now add the products together. These will never overflow. */ xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); XXH128_hash_t r128; r128.low64 = lower; r128.high64 = upper; return r128; #endif } /*! * @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it. * * The reason for the separate function is to prevent passing too many structs * around by value. This will hopefully inline the multiply, but we don't force it. * * @param lhs , rhs The 64-bit integers to multiply * @return The low 64 bits of the product XOR'd by the high 64 bits. * @see XXH_mult64to128() */ static xxh_u64 XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) { XXH128_hash_t product = XXH_mult64to128(lhs, rhs); return product.low64 ^ product.high64; } /*! Seems to produce slightly better code on GCC for some reason. */ XXH_FORCE_INLINE XXH_CONSTF xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) { XXH_ASSERT(0 <= shift && shift < 64); return v64 ^ (v64 >> shift); } /* * This is a fast avalanche stage, * suitable when input bits are already partially mixed */ static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) { h64 = XXH_xorshift64(h64, 37); h64 *= PRIME_MX1; h64 = XXH_xorshift64(h64, 32); return h64; } /* * This is a stronger avalanche, * inspired by Pelle Evensen's rrmxmx * preferable when input has not been previously mixed */ static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len) { /* this mix is inspired by Pelle Evensen's rrmxmx */ h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24); h64 *= PRIME_MX2; h64 ^= (h64 >> 35) + len ; h64 *= PRIME_MX2; return XXH_xorshift64(h64, 28); } /* ========================================== * Short keys * ========================================== * One of the shortcomings of XXH32 and XXH64 was that their performance was * sub-optimal on short lengths. It used an iterative algorithm which strongly * favored lengths that were a multiple of 4 or 8. * * Instead of iterating over individual inputs, we use a set of single shot * functions which piece together a range of lengths and operate in constant time. * * Additionally, the number of multiplies has been significantly reduced. This * reduces latency, especially when emulating 64-bit multiplies on 32-bit. * * Depending on the platform, this may or may not be faster than XXH32, but it * is almost guaranteed to be faster than XXH64. */ /* * At very short lengths, there isn't enough input to fully hide secrets, or use * the entire secret. * * There is also only a limited amount of mixing we can do before significantly * impacting performance. * * Therefore, we use different sections of the secret and always mix two secret * samples with an XOR. This should have no effect on performance on the * seedless or withSeed variants because everything _should_ be constant folded * by modern compilers. * * The XOR mixing hides individual parts of the secret and increases entropy. * * This adds an extra layer of strength for custom secrets. */ XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(1 <= len && len <= 3); XXH_ASSERT(secret != NULL); /* * len = 1: combined = { input[0], 0x01, input[0], input[0] } * len = 2: combined = { input[1], 0x02, input[0], input[1] } * len = 3: combined = { input[2], 0x03, input[0], input[1] } */ { xxh_u8 const c1 = input[0]; xxh_u8 const c2 = input[len >> 1]; xxh_u8 const c3 = input[len - 1]; xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24) | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; xxh_u64 const keyed = (xxh_u64)combined ^ bitflip; return XXH64_avalanche(keyed); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(4 <= len && len <= 8); seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; { xxh_u32 const input1 = XXH_readLE32(input); xxh_u32 const input2 = XXH_readLE32(input + len - 4); xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed; xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32); xxh_u64 const keyed = input64 ^ bitflip; return XXH3_rrmxmx(keyed, len); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(9 <= len && len <= 16); { xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed; xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed; xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1; xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2; xxh_u64 const acc = len + XXH_swap64(input_lo) + input_hi + XXH3_mul128_fold64(input_lo, input_hi); return XXH3_avalanche(acc); } } XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(len <= 16); { if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed); if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed); if (len) return XXH3_len_1to3_64b(input, len, secret, seed); return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64))); } } /* * DISCLAIMER: There are known *seed-dependent* multicollisions here due to * multiplication by zero, affecting hashes of lengths 17 to 240. * * However, they are very unlikely. * * Keep this in mind when using the unseeded XXH3_64bits() variant: As with all * unseeded non-cryptographic hashes, it does not attempt to defend itself * against specially crafted inputs, only random inputs. * * Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes * cancelling out the secret is taken an arbitrary number of times (addressed * in XXH3_accumulate_512), this collision is very unlikely with random inputs * and/or proper seeding: * * This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a * function that is only called up to 16 times per hash with up to 240 bytes of * input. * * This is not too bad for a non-cryptographic hash function, especially with * only 64 bit outputs. * * The 128-bit variant (which trades some speed for strength) is NOT affected * by this, although it is always a good idea to use a proper seed if you care * about strength. */ XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) { #if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ /* * UGLY HACK: * GCC for x86 tends to autovectorize the 128-bit multiply, resulting in * slower code. * * By forcing seed64 into a register, we disrupt the cost model and * cause it to scalarize. See `XXH32_round()` * * FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600, * XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on * GCC 9.2, despite both emitting scalar code. * * GCC generates much better scalar code than Clang for the rest of XXH3, * which is why finding a more optimal codepath is an interest. */ XXH_COMPILER_GUARD(seed64); #endif { xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 const input_hi = XXH_readLE64(input+8); return XXH3_mul128_fold64( input_lo ^ (XXH_readLE64(secret) + seed64), input_hi ^ (XXH_readLE64(secret+8) - seed64) ); } } /* For mid range keys, XXH3 uses a Mum-hash variant. */ XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(16 < len && len <= 128); { xxh_u64 acc = len * XXH_PRIME64_1; #if XXH_SIZE_OPT >= 1 /* Smaller and cleaner, but slightly slower. */ unsigned int i = (unsigned int)(len - 1) / 32; do { acc += XXH3_mix16B(input+16 * i, secret+32*i, seed); acc += XXH3_mix16B(input+len-16*(i+1), secret+32*i+16, seed); } while (i-- != 0); #else if (len > 32) { if (len > 64) { if (len > 96) { acc += XXH3_mix16B(input+48, secret+96, seed); acc += XXH3_mix16B(input+len-64, secret+112, seed); } acc += XXH3_mix16B(input+32, secret+64, seed); acc += XXH3_mix16B(input+len-48, secret+80, seed); } acc += XXH3_mix16B(input+16, secret+32, seed); acc += XXH3_mix16B(input+len-32, secret+48, seed); } acc += XXH3_mix16B(input+0, secret+0, seed); acc += XXH3_mix16B(input+len-16, secret+16, seed); #endif return XXH3_avalanche(acc); } } #define XXH3_MIDSIZE_MAX 240 XXH_NO_INLINE XXH_PUREF XXH64_hash_t XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); #define XXH3_MIDSIZE_STARTOFFSET 3 #define XXH3_MIDSIZE_LASTOFFSET 17 { xxh_u64 acc = len * XXH_PRIME64_1; xxh_u64 acc_end; unsigned int const nbRounds = (unsigned int)len / 16; unsigned int i; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); for (i=0; i<8; i++) { acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed); } /* last bytes */ acc_end = XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed); XXH_ASSERT(nbRounds >= 8); acc = XXH3_avalanche(acc); #if defined(__clang__) /* Clang */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ /* * UGLY HACK: * Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86. * In everywhere else, it uses scalar code. * * For 64->128-bit multiplies, even if the NEON was 100% optimal, it * would still be slower than UMAAL (see XXH_mult64to128). * * Unfortunately, Clang doesn't handle the long multiplies properly and * converts them to the nonexistent "vmulq_u64" intrinsic, which is then * scalarized into an ugly mess of VMOV.32 instructions. * * This mess is difficult to avoid without turning autovectorization * off completely, but they are usually relatively minor and/or not * worth it to fix. * * This loop is the easiest to fix, as unlike XXH32, this pragma * _actually works_ because it is a loop vectorization instead of an * SLP vectorization. */ #pragma clang loop vectorize(disable) #endif for (i=8 ; i < nbRounds; i++) { /* * Prevents clang for unrolling the acc loop and interleaving with this one. */ XXH_COMPILER_GUARD(acc); acc_end += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed); } return XXH3_avalanche(acc + acc_end); } } /* ======= Long Keys ======= */ #define XXH_STRIPE_LEN 64 #define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ #define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) #ifdef XXH_OLD_NAMES # define STRIPE_LEN XXH_STRIPE_LEN # define ACC_NB XXH_ACC_NB #endif #ifndef XXH_PREFETCH_DIST # ifdef __clang__ # define XXH_PREFETCH_DIST 320 # else # if (XXH_VECTOR == XXH_AVX512) # define XXH_PREFETCH_DIST 512 # else # define XXH_PREFETCH_DIST 384 # endif # endif /* __clang__ */ #endif /* XXH_PREFETCH_DIST */ /* * These macros are to generate an XXH3_accumulate() function. * The two arguments select the name suffix and target attribute. * * The name of this symbol is XXH3_accumulate_() and it calls * XXH3_accumulate_512_(). * * It may be useful to hand implement this function if the compiler fails to * optimize the inline function. */ #define XXH3_ACCUMULATE_TEMPLATE(name) \ void \ XXH3_accumulate_##name(xxh_u64* XXH_RESTRICT acc, \ const xxh_u8* XXH_RESTRICT input, \ const xxh_u8* XXH_RESTRICT secret, \ size_t nbStripes) \ { \ size_t n; \ for (n = 0; n < nbStripes; n++ ) { \ const xxh_u8* const in = input + n*XXH_STRIPE_LEN; \ XXH_PREFETCH(in + XXH_PREFETCH_DIST); \ XXH3_accumulate_512_##name( \ acc, \ in, \ secret + n*XXH_SECRET_CONSUME_RATE); \ } \ } XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) { if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); XXH_memcpy(dst, &v64, sizeof(v64)); } /* Several intrinsic functions below are supposed to accept __int64 as argument, * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . * However, several environments do not define __int64 type, * requiring a workaround. */ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) typedef int64_t xxh_i64; #else /* the following type must have a width of 64-bit */ typedef long long xxh_i64; #endif /* * XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized. * * It is a hardened version of UMAC, based off of FARSH's implementation. * * This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD * implementations, and it is ridiculously fast. * * We harden it by mixing the original input to the accumulators as well as the product. * * This means that in the (relatively likely) case of a multiply by zero, the * original input is preserved. * * On 128-bit inputs, we swap 64-bit pairs when we add the input to improve * cross-pollination, as otherwise the upper and lower halves would be * essentially independent. * * This doesn't matter on 64-bit hashes since they all get merged together in * the end, so we skip the extra step. * * Both XXH3_64bits and XXH3_128bits use this subroutine. */ #if (XXH_VECTOR == XXH_AVX512) \ || (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0) #ifndef XXH_TARGET_AVX512 # define XXH_TARGET_AVX512 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { __m512i* const xacc = (__m512i *) acc; XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { /* data_vec = input[0]; */ __m512i const data_vec = _mm512_loadu_si512 (input); /* key_vec = secret[0]; */ __m512i const key_vec = _mm512_loadu_si512 (secret); /* data_key = data_vec ^ key_vec; */ __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m512i const data_key_lo = _mm512_srli_epi64 (data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); /* xacc[0] += swap(data_vec); */ __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); __m512i const sum = _mm512_add_epi64(*xacc, data_swap); /* xacc[0] += product; */ *xacc = _mm512_add_epi64(product, sum); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512) /* * XXH3_scrambleAcc: Scrambles the accumulators to improve mixing. * * Multiplication isn't perfect, as explained by Google in HighwayHash: * * // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to * // varying degrees. In descending order of goodness, bytes * // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32. * // As expected, the upper and lower bytes are much worse. * * Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291 * * Since our algorithm uses a pseudorandom secret to add some variance into the * mix, we don't need to (or want to) mix as often or as much as HighwayHash does. * * This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid * extraction. * * Both XXH3_64bits and XXH3_128bits use this subroutine. */ XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { __m512i* const xacc = (__m512i*) acc; const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); /* xacc[0] ^= (xacc[0] >> 47) */ __m512i const acc_vec = *xacc; __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); /* xacc[0] ^= secret; */ __m512i const key_vec = _mm512_loadu_si512 (secret); __m512i const data_key = _mm512_ternarylogic_epi32(key_vec, acc_vec, shifted, 0x96 /* key_vec ^ acc_vec ^ shifted */); /* xacc[0] *= XXH_PRIME32_1; */ __m512i const data_key_hi = _mm512_srli_epi64 (data_key, 32); __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); XXH_ASSERT(((size_t)customSecret & 63) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); __m512i const seed_pos = _mm512_set1_epi64((xxh_i64)seed64); __m512i const seed = _mm512_mask_sub_epi64(seed_pos, 0xAA, _mm512_set1_epi8(0), seed_pos); const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret); __m512i* const dest = ( __m512i*) customSecret; int i; XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */ XXH_ASSERT(((size_t)dest & 63) == 0); for (i=0; i < nbRounds; ++i) { dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed); } } } #endif #if (XXH_VECTOR == XXH_AVX2) \ || (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0) #ifndef XXH_TARGET_AVX2 # define XXH_TARGET_AVX2 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xinput = (const __m256i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* data_vec = xinput[i]; */ __m256i const data_vec = _mm256_loadu_si256 (xinput+i); /* key_vec = xsecret[i]; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m256i const data_key_lo = _mm256_srli_epi64 (data_key, 32); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm256_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2) XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { __m256i* const xacc = (__m256i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m256i const acc_vec = xacc[i]; __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); /* xacc[i] ^= xsecret; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m256i const data_key_hi = _mm256_srli_epi64 (data_key, 32); __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); (void)(&XXH_writeLE64); XXH_PREFETCH(customSecret); { __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64); const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret); __m256i* dest = ( __m256i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack */ XXH_COMPILER_GUARD(dest); # endif XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */ XXH_ASSERT(((size_t)dest & 31) == 0); /* GCC -O2 need unroll loop manually */ dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed); dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed); dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed); dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed); dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed); dest[5] = _mm256_add_epi64(_mm256_load_si256(src+5), seed); } } #endif /* x86dispatch always generates SSE2 */ #if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) #ifndef XXH_TARGET_SSE2 # define XXH_TARGET_SSE2 /* disable attribute target */ #endif XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { /* SSE2 is just a half-scale version of the AVX2 version. */ XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xinput = (const __m128i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* data_vec = xinput[i]; */ __m128i const data_vec = _mm_loadu_si128 (xinput+i); /* key_vec = xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); __m128i const sum = _mm_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2) XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { __m128i* const xacc = (__m128i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m128i const acc_vec = xacc[i]; __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); # if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 /* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */ XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) }; __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); # else __m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64); # endif int i; const void* const src16 = XXH3_kSecret; __m128i* dst16 = (__m128i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack */ XXH_COMPILER_GUARD(dst16); # endif XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */ XXH_ASSERT(((size_t)dst16 & 15) == 0); for (i=0; i < nbRounds; ++i) { dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed); } } } #endif #if (XXH_VECTOR == XXH_NEON) /* forward declarations for the scalar routines */ XXH_FORCE_INLINE void XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, void const* XXH_RESTRICT secret, size_t lane); XXH_FORCE_INLINE void XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT secret, size_t lane); /*! * @internal * @brief The bulk processing loop for NEON and WASM SIMD128. * * The NEON code path is actually partially scalar when running on AArch64. This * is to optimize the pipelining and can have up to 15% speedup depending on the * CPU, and it also mitigates some GCC codegen issues. * * @see XXH3_NEON_LANES for configuring this and details about this optimization. * * NEON's 32-bit to 64-bit long multiply takes a half vector of 32-bit * integers instead of the other platforms which mask full 64-bit vectors, * so the setup is more complicated than just shifting right. * * Additionally, there is an optimization for 4 lanes at once noted below. * * Since, as stated, the most optimal amount of lanes for Cortexes is 6, * there needs to be *three* versions of the accumulate operation used * for the remaining 2 lanes. * * WASM's SIMD128 uses SIMDe's arm_neon.h polyfill because the intrinsics overlap * nearly perfectly. */ XXH_FORCE_INLINE void XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0); { /* GCC for darwin arm64 does not like aliasing here */ xxh_aliasing_uint64x2_t* const xacc = (xxh_aliasing_uint64x2_t*) acc; /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ uint8_t const* xinput = (const uint8_t *) input; uint8_t const* xsecret = (const uint8_t *) secret; size_t i; #ifdef __wasm_simd128__ /* * On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret * is constant propagated, which results in it converting it to this * inside the loop: * * a = v128.load(XXH3_kSecret + 0 + $secret_offset, offset = 0) * b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0) * ... * * This requires a full 32-bit address immediate (and therefore a 6 byte * instruction) as well as an add for each offset. * * Putting an asm guard prevents it from folding (at the cost of losing * the alignment hint), and uses the free offset in `v128.load` instead * of adding secret_offset each time which overall reduces code size by * about a kilobyte and improves performance. */ XXH_COMPILER_GUARD(xsecret); #endif /* Scalar lanes use the normal scalarRound routine */ for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { XXH3_scalarRound(acc, input, secret, i); } i = 0; /* 4 NEON lanes at a time. */ for (; i+1 < XXH3_NEON_LANES / 2; i+=2) { /* data_vec = xinput[i]; */ uint64x2_t data_vec_1 = XXH_vld1q_u64(xinput + (i * 16)); uint64x2_t data_vec_2 = XXH_vld1q_u64(xinput + ((i+1) * 16)); /* key_vec = xsecret[i]; */ uint64x2_t key_vec_1 = XXH_vld1q_u64(xsecret + (i * 16)); uint64x2_t key_vec_2 = XXH_vld1q_u64(xsecret + ((i+1) * 16)); /* data_swap = swap(data_vec) */ uint64x2_t data_swap_1 = vextq_u64(data_vec_1, data_vec_1, 1); uint64x2_t data_swap_2 = vextq_u64(data_vec_2, data_vec_2, 1); /* data_key = data_vec ^ key_vec; */ uint64x2_t data_key_1 = veorq_u64(data_vec_1, key_vec_1); uint64x2_t data_key_2 = veorq_u64(data_vec_2, key_vec_2); /* * If we reinterpret the 64x2 vectors as 32x4 vectors, we can use a * de-interleave operation for 4 lanes in 1 step with `vuzpq_u32` to * get one vector with the low 32 bits of each lane, and one vector * with the high 32 bits of each lane. * * The intrinsic returns a double vector because the original ARMv7-a * instruction modified both arguments in place. AArch64 and SIMD128 emit * two instructions from this intrinsic. * * [ dk11L | dk11H | dk12L | dk12H ] -> [ dk11L | dk12L | dk21L | dk22L ] * [ dk21L | dk21H | dk22L | dk22H ] -> [ dk11H | dk12H | dk21H | dk22H ] */ uint32x4x2_t unzipped = vuzpq_u32( vreinterpretq_u32_u64(data_key_1), vreinterpretq_u32_u64(data_key_2) ); /* data_key_lo = data_key & 0xFFFFFFFF */ uint32x4_t data_key_lo = unzipped.val[0]; /* data_key_hi = data_key >> 32 */ uint32x4_t data_key_hi = unzipped.val[1]; /* * Then, we can split the vectors horizontally and multiply which, as for most * widening intrinsics, have a variant that works on both high half vectors * for free on AArch64. A similar instruction is available on SIMD128. * * sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi */ uint64x2_t sum_1 = XXH_vmlal_low_u32(data_swap_1, data_key_lo, data_key_hi); uint64x2_t sum_2 = XXH_vmlal_high_u32(data_swap_2, data_key_lo, data_key_hi); /* * Clang reorders * a += b * c; // umlal swap.2d, dkl.2s, dkh.2s * c += a; // add acc.2d, acc.2d, swap.2d * to * c += a; // add acc.2d, acc.2d, swap.2d * c += b * c; // umlal acc.2d, dkl.2s, dkh.2s * * While it would make sense in theory since the addition is faster, * for reasons likely related to umlal being limited to certain NEON * pipelines, this is worse. A compiler guard fixes this. */ XXH_COMPILER_GUARD_CLANG_NEON(sum_1); XXH_COMPILER_GUARD_CLANG_NEON(sum_2); /* xacc[i] = acc_vec + sum; */ xacc[i] = vaddq_u64(xacc[i], sum_1); xacc[i+1] = vaddq_u64(xacc[i+1], sum_2); } /* Operate on the remaining NEON lanes 2 at a time. */ for (; i < XXH3_NEON_LANES / 2; i++) { /* data_vec = xinput[i]; */ uint64x2_t data_vec = XXH_vld1q_u64(xinput + (i * 16)); /* key_vec = xsecret[i]; */ uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); /* acc_vec_2 = swap(data_vec) */ uint64x2_t data_swap = vextq_u64(data_vec, data_vec, 1); /* data_key = data_vec ^ key_vec; */ uint64x2_t data_key = veorq_u64(data_vec, key_vec); /* For two lanes, just use VMOVN and VSHRN. */ /* data_key_lo = data_key & 0xFFFFFFFF; */ uint32x2_t data_key_lo = vmovn_u64(data_key); /* data_key_hi = data_key >> 32; */ uint32x2_t data_key_hi = vshrn_n_u64(data_key, 32); /* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi; */ uint64x2_t sum = vmlal_u32(data_swap, data_key_lo, data_key_hi); /* Same Clang workaround as before */ XXH_COMPILER_GUARD_CLANG_NEON(sum); /* xacc[i] = acc_vec + sum; */ xacc[i] = vaddq_u64 (xacc[i], sum); } } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(neon) XXH_FORCE_INLINE void XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { xxh_aliasing_uint64x2_t* xacc = (xxh_aliasing_uint64x2_t*) acc; uint8_t const* xsecret = (uint8_t const*) secret; size_t i; /* WASM uses operator overloads and doesn't need these. */ #ifndef __wasm_simd128__ /* { prime32_1, prime32_1 } */ uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1); /* { 0, prime32_1, 0, prime32_1 } */ uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32)); #endif /* AArch64 uses both scalar and neon at the same time */ for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) { XXH3_scalarScrambleRound(acc, secret, i); } for (i=0; i < XXH3_NEON_LANES / 2; i++) { /* xacc[i] ^= (xacc[i] >> 47); */ uint64x2_t acc_vec = xacc[i]; uint64x2_t shifted = vshrq_n_u64(acc_vec, 47); uint64x2_t data_vec = veorq_u64(acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16)); uint64x2_t data_key = veorq_u64(data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1 */ #ifdef __wasm_simd128__ /* SIMD128 has multiply by u64x2, use it instead of expanding and scalarizing */ xacc[i] = data_key * XXH_PRIME32_1; #else /* * Expanded version with portable NEON intrinsics * * lo(x) * lo(y) + (hi(x) * lo(y) << 32) * * prod_hi = hi(data_key) * lo(prime) << 32 * * Since we only need 32 bits of this multiply a trick can be used, reinterpreting the vector * as a uint32x4_t and multiplying by { 0, prime, 0, prime } to cancel out the unwanted bits * and avoid the shift. */ uint32x4_t prod_hi = vmulq_u32 (vreinterpretq_u32_u64(data_key), kPrimeHi); /* Extract low bits for vmlal_u32 */ uint32x2_t data_key_lo = vmovn_u64(data_key); /* xacc[i] = prod_hi + lo(data_key) * XXH_PRIME32_1; */ xacc[i] = vmlal_u32(vreinterpretq_u64_u32(prod_hi), data_key_lo, kPrimeLo); #endif } } } #endif #if (XXH_VECTOR == XXH_VSX) XXH_FORCE_INLINE void XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { /* presumed aligned */ xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; xxh_u8 const* const xinput = (xxh_u8 const*) input; /* no alignment restriction */ xxh_u8 const* const xsecret = (xxh_u8 const*) secret; /* no alignment restriction */ xxh_u64x2 const v32 = { 32, 32 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* data_vec = xinput[i]; */ xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + 16*i); /* key_vec = xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* shuffled = (data_key << 32) | (data_key >> 32); */ xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); /* acc_vec = xacc[i]; */ xxh_u64x2 acc_vec = xacc[i]; acc_vec += product; /* swap high and low halves */ #ifdef __s390x__ acc_vec += vec_permi(data_vec, data_vec, 2); #else acc_vec += vec_xxpermdi(data_vec, data_vec, 2); #endif xacc[i] = acc_vec; } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx) XXH_FORCE_INLINE void XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc; const xxh_u8* const xsecret = (const xxh_u8*) secret; /* constants */ xxh_u64x2 const v32 = { 32, 32 }; xxh_u64x2 const v47 = { 47, 47 }; xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* xacc[i] ^= (xacc[i] >> 47); */ xxh_u64x2 const acc_vec = xacc[i]; xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); /* xacc[i] ^= xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* xacc[i] *= XXH_PRIME32_1 */ /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); xacc[i] = prod_odd + (prod_even << v32); } } } #endif #if (XXH_VECTOR == XXH_SVE) XXH_FORCE_INLINE void XXH3_accumulate_512_sve( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { uint64_t *xacc = (uint64_t *)acc; const uint64_t *xinput = (const uint64_t *)(const void *)input; const uint64_t *xsecret = (const uint64_t *)(const void *)secret; svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); uint64_t element_count = svcntd(); if (element_count >= 8) { svbool_t mask = svptrue_pat_b64(SV_VL8); svuint64_t vacc = svld1_u64(mask, xacc); ACCRND(vacc, 0); svst1_u64(mask, xacc, vacc); } else if (element_count == 2) { /* sve128 */ svbool_t mask = svptrue_pat_b64(SV_VL2); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 2); svuint64_t acc2 = svld1_u64(mask, xacc + 4); svuint64_t acc3 = svld1_u64(mask, xacc + 6); ACCRND(acc0, 0); ACCRND(acc1, 2); ACCRND(acc2, 4); ACCRND(acc3, 6); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 2, acc1); svst1_u64(mask, xacc + 4, acc2); svst1_u64(mask, xacc + 6, acc3); } else { svbool_t mask = svptrue_pat_b64(SV_VL4); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 4); ACCRND(acc0, 0); ACCRND(acc1, 4); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 4, acc1); } } XXH_FORCE_INLINE void XXH3_accumulate_sve(xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, size_t nbStripes) { if (nbStripes != 0) { uint64_t *xacc = (uint64_t *)acc; const uint64_t *xinput = (const uint64_t *)(const void *)input; const uint64_t *xsecret = (const uint64_t *)(const void *)secret; svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1); uint64_t element_count = svcntd(); if (element_count >= 8) { svbool_t mask = svptrue_pat_b64(SV_VL8); svuint64_t vacc = svld1_u64(mask, xacc + 0); do { /* svprfd(svbool_t, void *, enum svfprop); */ svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(vacc, 0); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, vacc); } else if (element_count == 2) { /* sve128 */ svbool_t mask = svptrue_pat_b64(SV_VL2); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 2); svuint64_t acc2 = svld1_u64(mask, xacc + 4); svuint64_t acc3 = svld1_u64(mask, xacc + 6); do { svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(acc0, 0); ACCRND(acc1, 2); ACCRND(acc2, 4); ACCRND(acc3, 6); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 2, acc1); svst1_u64(mask, xacc + 4, acc2); svst1_u64(mask, xacc + 6, acc3); } else { svbool_t mask = svptrue_pat_b64(SV_VL4); svuint64_t acc0 = svld1_u64(mask, xacc + 0); svuint64_t acc1 = svld1_u64(mask, xacc + 4); do { svprfd(mask, xinput + 128, SV_PLDL1STRM); ACCRND(acc0, 0); ACCRND(acc1, 4); xinput += 8; xsecret += 1; nbStripes--; } while (nbStripes != 0); svst1_u64(mask, xacc + 0, acc0); svst1_u64(mask, xacc + 4, acc1); } } } #endif /* scalar variants - universal */ #if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) /* * In XXH3_scalarRound(), GCC and Clang have a similar codegen issue, where they * emit an excess mask and a full 64-bit multiply-add (MADD X-form). * * While this might not seem like much, as AArch64 is a 64-bit architecture, only * big Cortex designs have a full 64-bit multiplier. * * On the little cores, the smaller 32-bit multiplier is used, and full 64-bit * multiplies expand to 2-3 multiplies in microcode. This has a major penalty * of up to 4 latency cycles and 2 stall cycles in the multiply pipeline. * * Thankfully, AArch64 still provides the 32-bit long multiply-add (UMADDL) which does * not have this penalty and does the mask automatically. */ XXH_FORCE_INLINE xxh_u64 XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) { xxh_u64 ret; /* note: %x = 64-bit register, %w = 32-bit register */ __asm__("umaddl %x0, %w1, %w2, %x3" : "=r" (ret) : "r" (lhs), "r" (rhs), "r" (acc)); return ret; } #else XXH_FORCE_INLINE xxh_u64 XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc) { return XXH_mult32to64((xxh_u32)lhs, (xxh_u32)rhs) + acc; } #endif /*! * @internal * @brief Scalar round for @ref XXH3_accumulate_512_scalar(). * * This is extracted to its own function because the NEON path uses a combination * of NEON and scalar. */ XXH_FORCE_INLINE void XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input, void const* XXH_RESTRICT secret, size_t lane) { xxh_u64* xacc = (xxh_u64*) acc; xxh_u8 const* xinput = (xxh_u8 const*) input; xxh_u8 const* xsecret = (xxh_u8 const*) secret; XXH_ASSERT(lane < XXH_ACC_NB); XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); { xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8); xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8); xacc[lane ^ 1] += data_val; /* swap adjacent lanes */ xacc[lane] = XXH_mult32to64_add64(data_key /* & 0xFFFFFFFF */, data_key >> 32, xacc[lane]); } } /*! * @internal * @brief Processes a 64 byte block of data using the scalar path. */ XXH_FORCE_INLINE void XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { size_t i; /* ARM GCC refuses to unroll this loop, resulting in a 24% slowdown on ARMv6. */ #if defined(__GNUC__) && !defined(__clang__) \ && (defined(__arm__) || defined(__thumb2__)) \ && defined(__ARM_FEATURE_UNALIGNED) /* no unaligned access just wastes bytes */ \ && XXH_SIZE_OPT <= 0 # pragma GCC unroll 8 #endif for (i=0; i < XXH_ACC_NB; i++) { XXH3_scalarRound(acc, input, secret, i); } } XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar) /*! * @internal * @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar(). * * This is extracted to its own function because the NEON path uses a combination * of NEON and scalar. */ XXH_FORCE_INLINE void XXH3_scalarScrambleRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT secret, size_t lane) { xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); XXH_ASSERT(lane < XXH_ACC_NB); { xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8); xxh_u64 acc64 = xacc[lane]; acc64 = XXH_xorshift64(acc64, 47); acc64 ^= key64; acc64 *= XXH_PRIME32_1; xacc[lane] = acc64; } } /*! * @internal * @brief Scrambles the accumulators after a large chunk has been read */ XXH_FORCE_INLINE void XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { size_t i; for (i=0; i < XXH_ACC_NB; i++) { XXH3_scalarScrambleRound(acc, secret, i); } } XXH_FORCE_INLINE void XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { /* * We need a separate pointer for the hack below, * which requires a non-const pointer. * Any decent compiler will optimize this out otherwise. */ const xxh_u8* kSecretPtr = XXH3_kSecret; XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); #if defined(__GNUC__) && defined(__aarch64__) /* * UGLY HACK: * GCC and Clang generate a bunch of MOV/MOVK pairs for aarch64, and they are * placed sequentially, in order, at the top of the unrolled loop. * * While MOVK is great for generating constants (2 cycles for a 64-bit * constant compared to 4 cycles for LDR), it fights for bandwidth with * the arithmetic instructions. * * I L S * MOVK * MOVK * MOVK * MOVK * ADD * SUB STR * STR * By forcing loads from memory (as the asm line causes the compiler to assume * that XXH3_kSecretPtr has been changed), the pipelines are used more * efficiently: * I L S * LDR * ADD LDR * SUB STR * STR * * See XXH3_NEON_LANES for details on the pipsline. * * XXH3_64bits_withSeed, len == 256, Snapdragon 835 * without hack: 2654.4 MB/s * with hack: 3202.9 MB/s */ XXH_COMPILER_GUARD(kSecretPtr); #endif { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16; int i; for (i=0; i < nbRounds; i++) { /* * The asm hack causes the compiler to assume that kSecretPtr aliases with * customSecret, and on aarch64, this prevented LDP from merging two * loads together for free. Putting the loads together before the stores * properly generates LDP. */ xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64; xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64; XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo); XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi); } } } typedef void (*XXH3_f_accumulate)(xxh_u64* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, size_t); typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); #if (XXH_VECTOR == XXH_AVX512) #define XXH3_accumulate_512 XXH3_accumulate_512_avx512 #define XXH3_accumulate XXH3_accumulate_avx512 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 #elif (XXH_VECTOR == XXH_AVX2) #define XXH3_accumulate_512 XXH3_accumulate_512_avx2 #define XXH3_accumulate XXH3_accumulate_avx2 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 #elif (XXH_VECTOR == XXH_SSE2) #define XXH3_accumulate_512 XXH3_accumulate_512_sse2 #define XXH3_accumulate XXH3_accumulate_sse2 #define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 #define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 #elif (XXH_VECTOR == XXH_NEON) #define XXH3_accumulate_512 XXH3_accumulate_512_neon #define XXH3_accumulate XXH3_accumulate_neon #define XXH3_scrambleAcc XXH3_scrambleAcc_neon #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_VSX) #define XXH3_accumulate_512 XXH3_accumulate_512_vsx #define XXH3_accumulate XXH3_accumulate_vsx #define XXH3_scrambleAcc XXH3_scrambleAcc_vsx #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #elif (XXH_VECTOR == XXH_SVE) #define XXH3_accumulate_512 XXH3_accumulate_512_sve #define XXH3_accumulate XXH3_accumulate_sve #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #else /* scalar */ #define XXH3_accumulate_512 XXH3_accumulate_512_scalar #define XXH3_accumulate XXH3_accumulate_scalar #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #endif #if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */ # undef XXH3_initCustomSecret # define XXH3_initCustomSecret XXH3_initCustomSecret_scalar #endif XXH_FORCE_INLINE void XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; size_t const nb_blocks = (len - 1) / block_len; size_t n; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); for (n = 0; n < nb_blocks; n++) { f_acc(acc, input + n*block_len, secret, nbStripesPerBlock); f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); } /* last partial block */ XXH_ASSERT(len > XXH_STRIPE_LEN); { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); f_acc(acc, input + nb_blocks*block_len, secret, nbStripes); /* last stripe */ { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; #define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ XXH3_accumulate_512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); } } } XXH_FORCE_INLINE xxh_u64 XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) { return XXH3_mul128_fold64( acc[0] ^ XXH_readLE64(secret), acc[1] ^ XXH_readLE64(secret+8) ); } static XXH64_hash_t XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) { xxh_u64 result64 = start; size_t i = 0; for (i = 0; i < 4; i++) { result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); #if defined(__clang__) /* Clang */ \ && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ /* * UGLY HACK: * Prevent autovectorization on Clang ARMv7-a. Exact same problem as * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. * XXH3_64bits, len == 256, Snapdragon 835: * without hack: 2063.7 MB/s * with hack: 2560.7 MB/s */ XXH_COMPILER_GUARD(result64); #endif } return XXH3_avalanche(result64); } #define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len, const void* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc, f_scramble); /* converge into final hash */ XXH_STATIC_ASSERT(sizeof(acc) == 64); /* do not align on 8, so that the secret is different from the accumulator */ #define XXH_SECRET_MERGEACCS_START 11 XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); return XXH3_mergeAccs(acc, (const xxh_u8*)secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); } /* * It's important for performance to transmit secret's size (when it's static) * so that the compiler can properly optimize the vectorized loop. * This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set. * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE * breaks -Og, this is XXH_NO_INLINE. */ XXH3_WITH_SECRET_INLINE XXH64_hash_t XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc); } /* * It's preferable for performance that XXH3_hashLong is not inlined, * as it results in a smaller function for small data, easier to the instruction cache. * Note that inside this no_inline function, we do inline the internal loop, * and provide a statically defined secret size to allow optimization of vector loop. */ XXH_NO_INLINE XXH_PUREF XXH64_hash_t XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; (void)secret; (void)secretLen; return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc); } /* * XXH3_hashLong_64b_withSeed(): * Generate a custom key based on alteration of default XXH3_kSecret with the seed, * and then use this key for long mode hashing. * * This operation is decently fast but nonetheless costs a little bit of time. * Try to avoid it whenever possible (typically when seed==0). * * It's important for performance that XXH3_hashLong is not inlined. Not sure * why (uop cache maybe?), but the difference is large and easily measurable. */ XXH_FORCE_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len, XXH64_hash_t seed, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble, XXH3_f_initCustomSecret f_initSec) { #if XXH_SIZE_OPT <= 0 if (seed == 0) return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc, f_scramble); #endif { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; f_initSec(secret, seed); return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret), f_acc, f_scramble); } } /* * It's important for performance that XXH3_hashLong is not inlined. */ XXH_NO_INLINE XXH64_hash_t XXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen) { (void)secret; (void)secretLen; return XXH3_hashLong_64b_withSeed_internal(input, len, seed, XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); } typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); XXH_FORCE_INLINE XXH64_hash_t XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, XXH3_hashLong64_f f_hashLong) { XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); /* * If an action is to be taken if `secretLen` condition is not respected, * it should be done here. * For now, it's a contract pre-condition. * Adding a check and a branch here would cost performance at every hash. * Also, note that function signature doesn't offer room to return an error. */ if (len <= 16) return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); if (len <= 128) return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen); } /* === Public entry point === */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length) { return XXH3_64bits_internal(input, length, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_64bits_internal(input, length, 0, secret, secretSize, XXH3_hashLong_64b_withSecret); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed) { return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed); } XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { if (length <= XXH3_MIDSIZE_MAX) return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize); } /* === XXH3 streaming === */ #ifndef XXH_NO_STREAM /* * Malloc's a pointer that is always aligned to align. * * This must be freed with `XXH_alignedFree()`. * * malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte * alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2 * or on 32-bit, the 16 byte aligned loads in SSE2 and NEON. * * This underalignment previously caused a rather obvious crash which went * completely unnoticed due to XXH3_createState() not actually being tested. * Credit to RedSpah for noticing this bug. * * The alignment is done manually: Functions like posix_memalign or _mm_malloc * are avoided: To maintain portability, we would have to write a fallback * like this anyways, and besides, testing for the existence of library * functions without relying on external build tools is impossible. * * The method is simple: Overallocate, manually align, and store the offset * to the original behind the returned pointer. * * Align must be a power of 2 and 8 <= align <= 128. */ static XXH_MALLOCF void* XXH_alignedMalloc(size_t s, size_t align) { XXH_ASSERT(align <= 128 && align >= 8); /* range check */ XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */ XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */ { /* Overallocate to make room for manual realignment and an offset byte */ xxh_u8* base = (xxh_u8*)XXH_malloc(s + align); if (base != NULL) { /* * Get the offset needed to align this pointer. * * Even if the returned pointer is aligned, there will always be * at least one byte to store the offset to the original pointer. */ size_t offset = align - ((size_t)base & (align - 1)); /* base % align */ /* Add the offset for the now-aligned pointer */ xxh_u8* ptr = base + offset; XXH_ASSERT((size_t)ptr % align == 0); /* Store the offset immediately before the returned pointer. */ ptr[-1] = (xxh_u8)offset; return ptr; } return NULL; } } /* * Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass * normal malloc'd pointers, XXH_alignedMalloc has a specific data layout. */ static void XXH_alignedFree(void* p) { if (p != NULL) { xxh_u8* ptr = (xxh_u8*)p; /* Get the offset byte we added in XXH_malloc. */ xxh_u8 offset = ptr[-1]; /* Free the original malloc'd pointer */ xxh_u8* base = ptr - offset; XXH_free(base); } } /*! @ingroup XXH3_family */ /*! * @brief Allocate an @ref XXH3_state_t. * * Must be freed with XXH3_freeState(). * @return An allocated XXH3_state_t on success, `NULL` on failure. */ XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void) { XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64); if (state==NULL) return NULL; XXH3_INITSTATE(state); return state; } /*! @ingroup XXH3_family */ /*! * @brief Frees an @ref XXH3_state_t. * * Must be allocated with XXH3_createState(). * @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState(). * @return XXH_OK. */ XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr) { XXH_alignedFree(statePtr); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state) { XXH_memcpy(dst_state, src_state, sizeof(*dst_state)); } static void XXH3_reset_internal(XXH3_state_t* statePtr, XXH64_hash_t seed, const void* secret, size_t secretSize) { size_t const initStart = offsetof(XXH3_state_t, bufferedSize); size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); XXH_ASSERT(statePtr != NULL); /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ memset((char*)statePtr + initStart, 0, initLength); statePtr->acc[0] = XXH_PRIME32_3; statePtr->acc[1] = XXH_PRIME64_1; statePtr->acc[2] = XXH_PRIME64_2; statePtr->acc[3] = XXH_PRIME64_3; statePtr->acc[4] = XXH_PRIME64_4; statePtr->acc[5] = XXH_PRIME32_2; statePtr->acc[6] = XXH_PRIME64_5; statePtr->acc[7] = XXH_PRIME32_1; statePtr->seed = seed; statePtr->useSeed = (seed != 0); statePtr->extSecret = (const unsigned char*)secret; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) { if (statePtr == NULL) return XXH_ERROR; XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) { if (statePtr == NULL) return XXH_ERROR; XXH3_reset_internal(statePtr, 0, secret, secretSize); if (secret == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) { if (statePtr == NULL) return XXH_ERROR; if (seed==0) return XXH3_64bits_reset(statePtr); if ((seed != statePtr->seed) || (statePtr->extSecret != NULL)) XXH3_initCustomSecret(statePtr->customSecret, seed); XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE); return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64) { if (statePtr == NULL) return XXH_ERROR; if (secret == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; XXH3_reset_internal(statePtr, seed64, secret, secretSize); statePtr->useSeed = 1; /* always, even if seed64==0 */ return XXH_OK; } /*! * @internal * @brief Processes a large input for XXH3_update() and XXH3_digest_long(). * * Unlike XXH3_hashLong_internal_loop(), this can process data that overlaps a block. * * @param acc Pointer to the 8 accumulator lanes * @param nbStripesSoFarPtr In/out pointer to the number of leftover stripes in the block* * @param nbStripesPerBlock Number of stripes in a block * @param input Input pointer * @param nbStripes Number of stripes to process * @param secret Secret pointer * @param secretLimit Offset of the last block in @p secret * @param f_acc Pointer to an XXH3_accumulate implementation * @param f_scramble Pointer to an XXH3_scrambleAcc implementation * @return Pointer past the end of @p input after processing */ XXH_FORCE_INLINE const xxh_u8 * XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, const xxh_u8* XXH_RESTRICT input, size_t nbStripes, const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE; /* Process full blocks */ if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) { /* Process the initial partial block... */ size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr; do { /* Accumulate and scramble */ f_acc(acc, input, initialSecret, nbStripesThisIter); f_scramble(acc, secret + secretLimit); input += nbStripesThisIter * XXH_STRIPE_LEN; nbStripes -= nbStripesThisIter; /* Then continue the loop with the full block size */ nbStripesThisIter = nbStripesPerBlock; initialSecret = secret; } while (nbStripes >= nbStripesPerBlock); *nbStripesSoFarPtr = 0; } /* Process a partial block */ if (nbStripes > 0) { f_acc(acc, input, initialSecret, nbStripes); input += nbStripes * XXH_STRIPE_LEN; *nbStripesSoFarPtr += nbStripes; } /* Return end pointer */ return input; } #ifndef XXH3_STREAM_USE_STACK # if XXH_SIZE_OPT <= 0 && !defined(__clang__) /* clang doesn't need additional stack space */ # define XXH3_STREAM_USE_STACK 1 # endif #endif /* * Both XXH3_64bits_update and XXH3_128bits_update use this routine. */ XXH_FORCE_INLINE XXH_errorcode XXH3_update(XXH3_state_t* XXH_RESTRICT const state, const xxh_u8* XXH_RESTRICT input, size_t len, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { if (input==NULL) { XXH_ASSERT(len == 0); return XXH_OK; } XXH_ASSERT(state != NULL); { const xxh_u8* const bEnd = input + len; const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; #if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 /* For some reason, gcc and MSVC seem to suffer greatly * when operating accumulators directly into state. * Operating into stack space seems to enable proper optimization. * clang, on the other hand, doesn't seem to need this trick */ XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; XXH_memcpy(acc, state->acc, sizeof(acc)); #else xxh_u64* XXH_RESTRICT const acc = state->acc; #endif state->totalLen += len; XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE); /* small input : just fill in tmp buffer */ if (len <= XXH3_INTERNALBUFFER_SIZE - state->bufferedSize) { XXH_memcpy(state->buffer + state->bufferedSize, input, len); state->bufferedSize += (XXH32_hash_t)len; return XXH_OK; } /* total input is now > XXH3_INTERNALBUFFER_SIZE */ #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ /* * Internal buffer is partially filled (always, except at beginning) * Complete it, then consume it. */ if (state->bufferedSize) { size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); input += loadSize; XXH3_consumeStripes(acc, &state->nbStripesSoFar, state->nbStripesPerBlock, state->buffer, XXH3_INTERNALBUFFER_STRIPES, secret, state->secretLimit, f_acc, f_scramble); state->bufferedSize = 0; } XXH_ASSERT(input < bEnd); if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) { size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN; input = XXH3_consumeStripes(acc, &state->nbStripesSoFar, state->nbStripesPerBlock, input, nbStripes, secret, state->secretLimit, f_acc, f_scramble); XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); } /* Some remaining input (always) : buffer it */ XXH_ASSERT(input < bEnd); XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE); XXH_ASSERT(state->bufferedSize == 0); XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); state->bufferedSize = (XXH32_hash_t)(bEnd-input); #if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1 /* save stack accumulators into state */ XXH_memcpy(state->acc, acc, sizeof(acc)); #endif } return XXH_OK; } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) { return XXH3_update(state, (const xxh_u8*)input, len, XXH3_accumulate, XXH3_scrambleAcc); } XXH_FORCE_INLINE void XXH3_digest_long (XXH64_hash_t* acc, const XXH3_state_t* state, const unsigned char* secret) { xxh_u8 lastStripe[XXH_STRIPE_LEN]; const xxh_u8* lastStripePtr; /* * Digest on a local copy. This way, the state remains unaltered, and it can * continue ingesting more input afterwards. */ XXH_memcpy(acc, state->acc, sizeof(state->acc)); if (state->bufferedSize >= XXH_STRIPE_LEN) { /* Consume remaining stripes then point to remaining data in buffer */ size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; size_t nbStripesSoFar = state->nbStripesSoFar; XXH3_consumeStripes(acc, &nbStripesSoFar, state->nbStripesPerBlock, state->buffer, nbStripes, secret, state->secretLimit, XXH3_accumulate, XXH3_scrambleAcc); lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN; } else { /* bufferedSize < XXH_STRIPE_LEN */ /* Copy to temp buffer */ size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); lastStripePtr = lastStripe; } /* Last stripe */ XXH3_accumulate_512(acc, lastStripePtr, secret + state->secretLimit - XXH_SECRET_LASTACC_START); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* state) { const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; if (state->totalLen > XXH3_MIDSIZE_MAX) { XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; XXH3_digest_long(acc, state, secret); return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)state->totalLen * XXH_PRIME64_1); } /* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */ if (state->useSeed) return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen), secret, state->secretLimit + XXH_STRIPE_LEN); } #endif /* !XXH_NO_STREAM */ /* ========================================== * XXH3 128 bits (a.k.a XXH128) * ========================================== * XXH3's 128-bit variant has better mixing and strength than the 64-bit variant, * even without counting the significantly larger output size. * * For example, extra steps are taken to avoid the seed-dependent collisions * in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B). * * This strength naturally comes at the cost of some speed, especially on short * lengths. Note that longer hashes are about as fast as the 64-bit version * due to it using only a slight modification of the 64-bit loop. * * XXH128 is also more oriented towards 64-bit machines. It is still extremely * fast for a _128-bit_ hash on 32-bit (it usually clears XXH64). */ XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { /* A doubled version of 1to3_64b with different constants. */ XXH_ASSERT(input != NULL); XXH_ASSERT(1 <= len && len <= 3); XXH_ASSERT(secret != NULL); /* * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } */ { xxh_u8 const c1 = input[0]; xxh_u8 const c2 = input[len >> 1]; xxh_u8 const c3 = input[len - 1]; xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; XXH128_hash_t h128; h128.low64 = XXH64_avalanche(keyed_lo); h128.high64 = XXH64_avalanche(keyed_hi); return h128; } } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(4 <= len && len <= 8); seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; { xxh_u32 const input_lo = XXH_readLE32(input); xxh_u32 const input_hi = XXH_readLE32(input + len - 4); xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; xxh_u64 const keyed = input_64 ^ bitflip; /* Shift len to the left to ensure it is even, this avoids even multiplies. */ XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); m128.high64 += (m128.low64 << 1); m128.low64 ^= (m128.high64 >> 3); m128.low64 = XXH_xorshift64(m128.low64, 35); m128.low64 *= PRIME_MX2; m128.low64 = XXH_xorshift64(m128.low64, 28); m128.high64 = XXH3_avalanche(m128.high64); return m128; } } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(9 <= len && len <= 16); { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 input_hi = XXH_readLE64(input + len - 8); XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); /* * Put len in the middle of m128 to ensure that the length gets mixed to * both the low and high bits in the 128x64 multiply below. */ m128.low64 += (xxh_u64)(len - 1) << 54; input_hi ^= bitfliph; /* * Add the high 32 bits of input_hi to the high 32 bits of m128, then * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to * the high 64 bits of m128. * * The best approach to this operation is different on 32-bit and 64-bit. */ if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ /* * 32-bit optimized version, which is more readable. * * On 32-bit, it removes an ADC and delays a dependency between the two * halves of m128.high64, but it generates an extra mask on 64-bit. */ m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); } else { /* * 64-bit optimized (albeit more confusing) version. * * Uses some properties of addition and multiplication to remove the mask: * * Let: * a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF) * b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000) * c = XXH_PRIME32_2 * * a + (b * c) * Inverse Property: x + y - x == y * a + (b * (1 + c - 1)) * Distributive Property: x * (y + z) == (x * y) + (x * z) * a + (b * 1) + (b * (c - 1)) * Identity Property: x * 1 == x * a + b + (b * (c - 1)) * * Substitute a, b, and c: * input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) * * Since input_hi.hi + input_hi.lo == input_hi, we get this: * input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1)) */ m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); } /* m128 ^= XXH_swap64(m128 >> 64); */ m128.low64 ^= XXH_swap64(m128.high64); { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); h128.high64 += m128.high64 * XXH_PRIME64_2; h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = XXH3_avalanche(h128.high64); return h128; } } } /* * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN */ XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(len <= 16); { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); if (len) return XXH3_len_1to3_128b(input, len, secret, seed); { XXH128_hash_t h128; xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); h128.low64 = XXH64_avalanche(seed ^ bitflipl); h128.high64 = XXH64_avalanche( seed ^ bitfliph); return h128; } } } /* * A bit slower than XXH3_mix16B, but handles multiply by zero better. */ XXH_FORCE_INLINE XXH128_hash_t XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, const xxh_u8* secret, XXH64_hash_t seed) { acc.low64 += XXH3_mix16B (input_1, secret+0, seed); acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); acc.high64 += XXH3_mix16B (input_2, secret+16, seed); acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); return acc; } XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(16 < len && len <= 128); { XXH128_hash_t acc; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; #if XXH_SIZE_OPT >= 1 { /* Smaller, but slightly slower. */ unsigned int i = (unsigned int)(len - 1) / 32; do { acc = XXH128_mix32B(acc, input+16*i, input+len-16*(i+1), secret+32*i, seed); } while (i-- != 0); } #else if (len > 32) { if (len > 64) { if (len > 96) { acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); } acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); } acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); } acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); #endif { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } XXH_NO_INLINE XXH_PUREF XXH128_hash_t XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); { XXH128_hash_t acc; unsigned i; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; /* * We set as `i` as offset + 32. We do this so that unchanged * `len` can be used as upper bound. This reaches a sweet spot * where both x86 and aarch64 get simple agen and good codegen * for the loop. */ for (i = 32; i < 160; i += 32) { acc = XXH128_mix32B(acc, input + i - 32, input + i - 16, secret + i - 32, seed); } acc.low64 = XXH3_avalanche(acc.low64); acc.high64 = XXH3_avalanche(acc.high64); /* * NB: `i <= len` will duplicate the last 32-bytes if * len % 32 was zero. This is an unfortunate necessity to keep * the hash result stable. */ for (i=160; i <= len; i += 32) { acc = XXH128_mix32B(acc, input + i - 32, input + i - 16, secret + XXH3_MIDSIZE_STARTOFFSET + i - 160, seed); } /* last bytes */ acc = XXH128_mix32B(acc, input + len - 16, input + len - 32, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, (XXH64_hash_t)0 - seed); { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc, f_scramble); /* converge into final hash */ XXH_STATIC_ASSERT(sizeof(acc) == 64); XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); { XXH128_hash_t h128; h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); h128.high64 = XXH3_mergeAccs(acc, secret + secretSize - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)len * XXH_PRIME64_2)); return h128; } } /* * It's important for performance that XXH3_hashLong() is not inlined. */ XXH_NO_INLINE XXH_PUREF XXH128_hash_t XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; (void)secret; (void)secretLen; return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc); } /* * It's important for performance to pass @p secretLen (when it's static) * to the compiler, so that it can properly optimize the vectorized loop. * * When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE * breaks -Og, this is XXH_NO_INLINE. */ XXH3_WITH_SECRET_INLINE XXH128_hash_t XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc); } XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, XXH3_f_accumulate f_acc, XXH3_f_scrambleAcc f_scramble, XXH3_f_initCustomSecret f_initSec) { if (seed64 == 0) return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), f_acc, f_scramble); { XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE]; f_initSec(secret, seed64); return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret), f_acc, f_scramble); } } /* * It's important for performance that XXH3_hashLong is not inlined. */ XXH_NO_INLINE XXH128_hash_t XXH3_hashLong_128b_withSeed(const void* input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)secret; (void)secretLen; return XXH3_hashLong_128b_withSeed_internal(input, len, seed64, XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret); } typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const void* XXH_RESTRICT, size_t); XXH_FORCE_INLINE XXH128_hash_t XXH3_128bits_internal(const void* input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, XXH3_hashLong128_f f_hl128) { XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); /* * If an action is to be taken if `secret` conditions are not respected, * it should be done here. * For now, it's a contract pre-condition. * Adding a check and a branch here would cost performance at every hash. */ if (len <= 16) return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); if (len <= 128) return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); return f_hl128(input, len, seed64, secret, secretLen); } /* === Public XXH128 API === */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len) { return XXH3_128bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_default); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_128bits_internal(input, len, 0, (const xxh_u8*)secret, secretSize, XXH3_hashLong_128b_withSecret); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) { return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_withSeed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { if (len <= XXH3_MIDSIZE_MAX) return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL); return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH128(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed) { return XXH3_128bits_withSeed(input, len, seed); } /* === XXH3 128-bit streaming === */ #ifndef XXH_NO_STREAM /* * All initialization and update functions are identical to 64-bit streaming variant. * The only difference is the finalization routine. */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr) { return XXH3_64bits_reset(statePtr); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize) { return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed) { return XXH3_64bits_reset_withSeed(statePtr, seed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed) { return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len) { return XXH3_64bits_update(state, input, len); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* state) { const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; if (state->totalLen > XXH3_MIDSIZE_MAX) { XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; XXH3_digest_long(acc, state, secret); XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); { XXH128_hash_t h128; h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)state->totalLen * XXH_PRIME64_1); h128.high64 = XXH3_mergeAccs(acc, secret + state->secretLimit + XXH_STRIPE_LEN - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); return h128; } } /* len <= XXH3_MIDSIZE_MAX : short code */ if (state->seed) return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed); return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), secret, state->secretLimit + XXH_STRIPE_LEN); } #endif /* !XXH_NO_STREAM */ /* 128-bit utility functions */ #include /* memcmp, memcpy */ /* return : 1 is equal, 0 if different */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2) { /* note : XXH128_hash_t is compact, it has no padding byte */ return !(memcmp(&h1, &h2, sizeof(h1))); } /* This prototype is compatible with stdlib's qsort(). * @return : >0 if *h128_1 > *h128_2 * <0 if *h128_1 < *h128_2 * =0 if *h128_1 == *h128_2 */ /*! @ingroup XXH3_family */ XXH_PUBLIC_API int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2) { XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1; XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2; int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64); /* note : bets that, in most cases, hash values are different */ if (hcmp) return hcmp; return (h1.low64 > h2.low64) - (h2.low64 > h1.low64); } /*====== Canonical representation ======*/ /*! @ingroup XXH3_family */ XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) { hash.high64 = XXH_swap64(hash.high64); hash.low64 = XXH_swap64(hash.low64); } XXH_memcpy(dst, &hash.high64, sizeof(hash.high64)); XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64)); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src) { XXH128_hash_t h; h.high64 = XXH_readBE64(src); h.low64 = XXH_readBE64(src->digest + 8); return h; } /* ========================================== * Secret generators * ========================================== */ #define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128) { XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 ); XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 ); } /*! @ingroup XXH3_family */ XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize) { #if (XXH_DEBUGLEVEL >= 1) XXH_ASSERT(secretBuffer != NULL); XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); #else /* production mode, assert() are disabled */ if (secretBuffer == NULL) return XXH_ERROR; if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR; #endif if (customSeedSize == 0) { customSeed = XXH3_kSecret; customSeedSize = XXH_SECRET_DEFAULT_SIZE; } #if (XXH_DEBUGLEVEL >= 1) XXH_ASSERT(customSeed != NULL); #else if (customSeed == NULL) return XXH_ERROR; #endif /* Fill secretBuffer with a copy of customSeed - repeat as needed */ { size_t pos = 0; while (pos < secretSize) { size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize); memcpy((char*)secretBuffer + pos, customSeed, toCopy); pos += toCopy; } } { size_t const nbSeg16 = secretSize / 16; size_t n; XXH128_canonical_t scrambler; XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0)); for (n=0; n [ ...]" exit 1 fi TEMPDIR="mupen64plus-temp-build" rm -rf ${TEMPDIR} mkdir -p ${TEMPDIR}/source cd ${TEMPDIR}/source echo "************************************ Downloading Mupen64Plus module source code" git clone --branch $1 https://github.com/mupen64plus/mupen64plus-core.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-rom.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-ui-console.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-audio-sdl.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-input-sdl.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-rsp-hle.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-video-rice.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-video-glide64mk2.git shift for dirname in ./mupen64plus-*; do rm -rf ${dirname}/.git*; done OUTPUTDIR="mupen64plus-bundle-$1" shift echo "************************************ Building Mupen64Plus modules" cd .. tar xzvf source/mupen64plus-core/tools/m64p_helper_scripts.tar.gz ./m64p_build.sh COREDIR=/usr/local/lib/ $@ mv "test" "${OUTPUTDIR}" echo "************************************ Creating archive" cp source/mupen64plus-core/tools/install_binary_bundle.sh "${OUTPUTDIR}/install.sh" cp source/mupen64plus-core/tools/uninstall_binary_bundle.sh "${OUTPUTDIR}/uninstall.sh" tar c "${OUTPUTDIR}" --owner 0 --group 0 --numeric-owner | gzip -n > "../${OUTPUTDIR}.tar.gz" cd .. rm -rf "${TEMPDIR}" mupen64plus-core-src-2.6.0/tools/build_bundle_src.sh000077500000000000000000000057661464506436200224620ustar00rootroot00000000000000#!/bin/sh #/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # * Mupen64plus - build_bundle_src.sh * # * Mupen64Plus homepage: https://mupen64plus.org/ * # * Copyright (C) 2009-2013 Richard Goedeken * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ # terminate the script if any commands return a non-zero error code set -e if [ $# -lt 2 ]; then echo "Usage: build_bundle_src.sh " exit 1 fi OUTPUTDIR="mupen64plus-bundle-$2" echo "************************************ Creating directory: " ${OUTPUTDIR} rm -rf ${OUTPUTDIR} mkdir -p ${OUTPUTDIR}/source cd ${OUTPUTDIR}/source echo "************************************ Downloading Mupen64Plus module source code" git clone --branch $1 https://github.com/mupen64plus/mupen64plus-core.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-rom.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-ui-console.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-audio-sdl.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-input-sdl.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-rsp-hle.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-video-rice.git git clone --branch $1 https://github.com/mupen64plus/mupen64plus-video-glide64mk2.git for dirname in ./mupen64plus-*; do rm -rf ${dirname}/.git*; done # unzip the helper scripts and remove the Mercurial scripts cd .. tar xzvf source/mupen64plus-core/tools/m64p_helper_scripts.tar.gz rm -f m64p_get.sh m64p_update.sh echo "************************************ Creating archive" cd .. tar c "${OUTPUTDIR}" --owner 0 --group 0 --numeric-owner | gzip -n > "${OUTPUTDIR}.tar.gz" rm -rf "${OUTPUTDIR}" mupen64plus-core-src-2.6.0/tools/build_modules_src.sh000077500000000000000000000044171464506436200226510ustar00rootroot00000000000000#!/bin/sh #/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # * Mupen64plus - build_modules_src.sh * # * Mupen64Plus homepage: https://mupen64plus.org/ * # * Copyright (C) 2009-2013 Richard Goedeken * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ # terminate the script if any commands return a non-zero error code set -e if [ $# -lt 2 ]; then echo "Usage: build_modules_src.sh " exit 1 fi modules='mupen64plus-core mupen64plus-rom mupen64plus-ui-console mupen64plus-audio-sdl mupen64plus-input-sdl mupen64plus-rsp-hle mupen64plus-video-rice mupen64plus-video-glide64mk2' for modname in ${modules}; do echo "************************************ Downloading and packaging module source code: ${modname}" rm -rf "tmp" OUTPUTDIR="${modname}-$2" git clone --bare "https://github.com/mupen64plus/${modname}.git" "tmp" git --git-dir="$(pwd)/tmp/" archive --format=tar --prefix="${OUTPUTDIR}/" $1 | gzip -n --best > "${OUTPUTDIR}.tar.gz" rm -rf "tmp" done mupen64plus-core-src-2.6.0/tools/cheat_code_convert.py000077500000000000000000000102771464506436200230100ustar00rootroot00000000000000#!/usr/bin/python '''* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - code_convert.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2010 Rhett Osborne * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Usage: python code_convert.py > ../data/mupencheat.txt < ../data/mupen64plus.cht ''' from sys import stdin class cheat: def __init__(self): self.n="" self.d="" self.c=[] self.v=0 self.hb='00' def add(self, l): if(self.n == ""): return l.append(" cn %s"%(self.n)) if(self.d != ""): l.append(" cd %s"%(self.d)) for code in self.c: l.append(" "+code) def clear(self): self.n="" self.d="" self.c=[] self.v=0 l=[] cCount=0 _cs = [] for i in range(225): _cs.append(cheat()) cs = _cs[:] def print_l(): global l, cs for cheat in cs: cheat.add(l) for line in l: print line.replace("\x00", "") l=[] cCount=0 for i in range(225): cs[i].clear() lines = stdin.read().split("\n") for line in lines: if len(line) < 2: continue elif(line[:2] == "//" and line != "//----" and line != "//---" ): l.append(line) elif len(line) < 4: continue elif(line[0] == '[' and line[-1] == ']' and len(line) > 23): print_l() l.append("\ncrc %s" % line[1:-1]) elif(line[:5] == "Name="): l.append("gn %s" % (line[5:])) elif(line[:5] == "Cheat"): t = line[5:].split('=')[0] if (len(t)>1 and t[-2] == '_'): n = int(t[:-2]) if(t[-1] == 'N'): cs[n].d = line.split("=")[1] else: for option in line.split("=")[1].split("$")[1:]: if(len(option) < 4): break; if(option[-1]==','): end =-1 else: end = None if(option[2] == " "): cs[n].c[cs[n].v] += "%s%s:\"%s\""%(cs[n].hb,option[:2],option[3:end].replace("\"", "\\\"")) else: cs[n].c[cs[n].v] += "%s:\"%s\""%(option[:4],option[5:end].replace("\"", "\\\"")) cs[n].c[cs[n].v]+=',' cs[n].c[cs[n].v] = cs[n].c[cs[n].v][:-1] else: n = int(t) cn = line.split('"') cs[n].c = cn[2][1:].split(',') cs[n].n = cn[1]; i=0 for cheat in cs[n].c: if(cheat[-1] == '?'): if(cheat[-2:] == '??' and cheat[-4:-2] != '??'): cs[n].hb = cheat[-4:-2] else: cs[n].hb = '00' cs[n].c[i] = cheat[:9] + "???? "; cs[n].v=i i+=1 if(n > cCount): cCount = n elif(line != "//----" and line != "//---" ): l.append("//%s" %line) mupen64plus-core-src-2.6.0/tools/gen_asm_defines.awk000066400000000000000000000004041464506436200224160ustar00rootroot00000000000000BEGIN { nasm_file = dest_dir"/asm_defines_nasm.h"; gas_file = dest_dir"/asm_defines_gas.h"; } /@ASM_DEFINE offsetof_struct_[a-zA-Z_0-9]+ 0x[0-9a-fA-F]+/ { print "%define "$2" ("$3")" > nasm_file; print "#define "$2" ("$3")" > gas_file; } END {} mupen64plus-core-src-2.6.0/tools/gen_asm_script.cmd000066400000000000000000000056401464506436200222750ustar00rootroot00000000000000@echo off setlocal enableextensions :: Countermeasure vs tainted build environment by known third party utilities set FIND=find find /? >nul 2>&1 if errorlevel 1 ( echo WARNING: GNU utilities in PATH can break MSVC echo. set FIND=findstr ) :: Anchor to the project file path, otherwise the arguments would be invalid: :: :: * In theory this is unnecessary, but it makes the process more transparent :: to people unfamiliar with VS's not-so-well-explained behaviors :: pushd "%~dp0..\projects\msvc\" if errorlevel 1 exit /b 101 :: Validating arguments passed from Visual Studio to use as variables: :: :: * Arguments with conflicting syntax can terminate the script abruptly :: * 'GAS_EXTRA' argument isn't used in some cases :: set GAS_SRCDIR= set GAS_OBJDIR= set GAS_EXTRA= for /f "tokens=1,2*" %%A in ('echo %*') do ( set GAS_SRCDIR=%%A set GAS_OBJDIR=%%B set GAS_EXTRA=%%C ) set GAS_CLARG=%GAS_OBJDIR% if defined GAS_EXTRA set GAS_CLARG=%GAS_OBJDIR% %GAS_EXTRA% :: "Anti-PEBCAK": :: :: * Ensure that 'GAS_SRCDIR' and 'GAS_OBJDIR' exist or are defined and send an :: error signal if not :: if not exist "%GAS_SRCDIR%asm_defines.c" exit /b 202 if not defined GAS_OBJDIR exit /b 303 :: Legacy code adaptation for this script: :: :: * Delete the libraries previously generated by 'gawk' or this script :: * CL's stuff/witchcraft, if all goes well it will generate 'asm_defines.obj' :: del /f /q "%GAS_SRCDIR%asm_defines_*" 2>nul cl /c /Fo%GAS_CLARG% /I ..\..\src "%GAS_SRCDIR%asm_defines.c" :: If 'asm_defines.obj' does not exist, send error if not exist "%GAS_OBJDIR%asm_defines.obj" exit /b 404 if "%USE_GAWK%" NEQ "1" goto native :: Legacy code adaptation for 'gawk': :: :: * Define 'USE_GAWK=1' to use 'gawk' :: * A POSIX version of 'GAS_SRCDIR' is required for 'dest_dir' argument :: set "GAS_SRCDIR2=%GAS_SRCDIR:\=/%" set GAWK=..\..\..\mupen64plus-win32-deps\gawk-3.1.6-1\bin\gawk.exe "%GAWK%" -v dest_dir="%GAS_SRCDIR2%" -f "%~dp0gen_asm_defines.awk" "%GAS_OBJDIR%asm_defines.obj" goto log :native :: Adaptation of 'gen_asm_defines.awk' / 'gen_asm_script.sh': :: :: 1. Display 'asm_defines.obj' as a list, looking only for patterns :: '@ASM_DEFINE' :: 2. Sort for easy reading, the result is interpreted as an array :: with ' ' as default delimiter in the 'for' command :: 3. The for's 'tokens=2,3' ignores pattern "1" (@ASM_DEFINE) and anything :: beyond "3", take "2" (offset* value) as 'J' and "3" (hex* value) as 'K' :: 4. Print current values and repeat steps 3 and 4 on the next line :: until EOL is reached :: for /f "tokens=2,3" %%J in ('type "%GAS_OBJDIR%asm_defines.obj" ^| %FIND% "@ASM_DEFINE" ^| sort') do ( echo %%define %%J ^(%%K^)>>"%GAS_SRCDIR%asm_defines_nasm.h" echo #define %%J ^(%%K^)>>"%GAS_SRCDIR%asm_defines_gas.h" ) :log :: Display 'asm_defines_nasm.h' in the log echo. type "%GAS_SRCDIR%asm_defines_nasm.h" echo. exit /b 0 mupen64plus-core-src-2.6.0/tools/gen_asm_script.sh000077500000000000000000000025131464506436200221430ustar00rootroot00000000000000#!/bin/bash set -e set +f # Set the "print" outputs NASM_FILE="$1/asm_defines_nasm.h" GAS_FILE="$1/asm_defines_gas.h" rm -f "$1/asm_defines_*" # Adaptation of 'gen_asm_defines.awk' / 'gen_asm_script.cmd': # # 1. Display 'asm_defines.o' as a list, looking only for # patterns '@ASM_DEFINE' # 2. Sort for easy reading, the result is interpreted as an array or # worksheet with ' ' as a self-imposed delimiter in the 'cut' command # 3. The cut's '-f2,3' discards column "1" (@ASM_DEFINE) and anything # beyond "3", take "2" (offset* column), the delimiters and # "3" (hex* column) to be kept # 4. After setting 'GAS_OBJSTR', all the next lines (LF) are degraded # to ' ' and thus all patterns in columns "2" and "3" become a # predictable text sequence GAS_OBJSTR=$(LC_ALL=C grep -a "@ASM_DEFINE" "$2" | sort | cut -d ' ' -f2,3) for GAS_CURSTR in ${GAS_OBJSTR}; do # 5. If the current value doesn't contain a hex glob (pattern matching), # it must be a "offset* value" if [ "${GAS_CURSTR:0:2}" != "0x" ]; then # 6. Save current value and repeat step 5 on the next value GAS_OFFSET=${GAS_CURSTR} else # 7. Print current values and repeat steps 5-7 on the next value # until EOL is reached echo "%define ${GAS_OFFSET} (${GAS_CURSTR})" >> "$NASM_FILE" echo "#define ${GAS_OFFSET} (${GAS_CURSTR})" >> "$GAS_FILE" fi done mupen64plus-core-src-2.6.0/tools/gen_sdl_key_converter.c000066400000000000000000000447021464506436200233330ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - gen_sdl_key_converter.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2013 Mupen64plus development team * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* gcc -E `sdl2-config --cflags --libs` `sdl-config --cflags --libs` gen_sdl_key_converter.c -o gen_sdl_key_converter */ #include #include #include #include struct keycode2scancode { const char *keysym_name; uint32_t keysym; const char *scancode_name; uint32_t scancode; }; #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define _XSTR(x) #x #define KEYSYM2SCANCODE(k, s) { \ .keysym_name = _XSTR(SDLK_##k), \ .keysym = SDLK_##k, \ .scancode_name = _XSTR(SDL_SCANCODE_##s), \ .scancode = SDL_SCANCODE_##s, \ } /* Table from SDL 1.2.5 to SDL2 2.0-rc1 */ static const struct keycode2scancode keycode2scancode[] = { KEYSYM2SCANCODE(BACKSPACE, BACKSPACE), KEYSYM2SCANCODE(TAB, TAB), KEYSYM2SCANCODE(CLEAR, CLEAR), KEYSYM2SCANCODE(RETURN, RETURN), KEYSYM2SCANCODE(PAUSE, PAUSE), KEYSYM2SCANCODE(ESCAPE, ESCAPE), KEYSYM2SCANCODE(SPACE, SPACE), KEYSYM2SCANCODE(EXCLAIM, UNKNOWN), KEYSYM2SCANCODE(QUOTEDBL, UNKNOWN), KEYSYM2SCANCODE(HASH, UNKNOWN), KEYSYM2SCANCODE(DOLLAR, UNKNOWN), KEYSYM2SCANCODE(AMPERSAND, UNKNOWN), KEYSYM2SCANCODE(QUOTE, UNKNOWN), KEYSYM2SCANCODE(LEFTPAREN, UNKNOWN), KEYSYM2SCANCODE(RIGHTPAREN, UNKNOWN), KEYSYM2SCANCODE(ASTERISK, UNKNOWN), KEYSYM2SCANCODE(PLUS, UNKNOWN), KEYSYM2SCANCODE(COMMA, COMMA), KEYSYM2SCANCODE(MINUS, MINUS), KEYSYM2SCANCODE(PERIOD, PERIOD), KEYSYM2SCANCODE(SLASH, SLASH), KEYSYM2SCANCODE(0, 0), KEYSYM2SCANCODE(1, 1), KEYSYM2SCANCODE(2, 2), KEYSYM2SCANCODE(3, 3), KEYSYM2SCANCODE(4, 4), KEYSYM2SCANCODE(5, 5), KEYSYM2SCANCODE(6, 6), KEYSYM2SCANCODE(7, 7), KEYSYM2SCANCODE(8, 8), KEYSYM2SCANCODE(9, 9), KEYSYM2SCANCODE(COLON, UNKNOWN), KEYSYM2SCANCODE(SEMICOLON, SEMICOLON), KEYSYM2SCANCODE(LESS, UNKNOWN), KEYSYM2SCANCODE(EQUALS, EQUALS), KEYSYM2SCANCODE(GREATER, UNKNOWN), KEYSYM2SCANCODE(QUESTION, UNKNOWN), KEYSYM2SCANCODE(AT, UNKNOWN), KEYSYM2SCANCODE(LEFTBRACKET, LEFTBRACKET), KEYSYM2SCANCODE(BACKSLASH, BACKSLASH), KEYSYM2SCANCODE(RIGHTBRACKET, RIGHTBRACKET), KEYSYM2SCANCODE(CARET, UNKNOWN), KEYSYM2SCANCODE(UNDERSCORE, UNKNOWN), KEYSYM2SCANCODE(BACKQUOTE, UNKNOWN), KEYSYM2SCANCODE(a, A), KEYSYM2SCANCODE(b, B), KEYSYM2SCANCODE(c, C), KEYSYM2SCANCODE(d, D), KEYSYM2SCANCODE(e, E), KEYSYM2SCANCODE(f, F), KEYSYM2SCANCODE(g, G), KEYSYM2SCANCODE(h, H), KEYSYM2SCANCODE(i, I), KEYSYM2SCANCODE(j, J), KEYSYM2SCANCODE(k, K), KEYSYM2SCANCODE(l, L), KEYSYM2SCANCODE(m, M), KEYSYM2SCANCODE(n, N), KEYSYM2SCANCODE(o, O), KEYSYM2SCANCODE(p, P), KEYSYM2SCANCODE(q, Q), KEYSYM2SCANCODE(r, R), KEYSYM2SCANCODE(s, S), KEYSYM2SCANCODE(t, T), KEYSYM2SCANCODE(u, U), KEYSYM2SCANCODE(v, V), KEYSYM2SCANCODE(w, W), KEYSYM2SCANCODE(x, X), KEYSYM2SCANCODE(y, Y), KEYSYM2SCANCODE(z, Z), KEYSYM2SCANCODE(DELETE, DELETE), KEYSYM2SCANCODE(WORLD_0, UNKNOWN), KEYSYM2SCANCODE(WORLD_1, UNKNOWN), KEYSYM2SCANCODE(WORLD_2, UNKNOWN), KEYSYM2SCANCODE(WORLD_3, UNKNOWN), KEYSYM2SCANCODE(WORLD_4, UNKNOWN), KEYSYM2SCANCODE(WORLD_5, UNKNOWN), KEYSYM2SCANCODE(WORLD_6, UNKNOWN), KEYSYM2SCANCODE(WORLD_7, UNKNOWN), KEYSYM2SCANCODE(WORLD_8, UNKNOWN), KEYSYM2SCANCODE(WORLD_9, UNKNOWN), KEYSYM2SCANCODE(WORLD_10, UNKNOWN), KEYSYM2SCANCODE(WORLD_11, UNKNOWN), KEYSYM2SCANCODE(WORLD_12, UNKNOWN), KEYSYM2SCANCODE(WORLD_13, UNKNOWN), KEYSYM2SCANCODE(WORLD_14, UNKNOWN), KEYSYM2SCANCODE(WORLD_15, UNKNOWN), KEYSYM2SCANCODE(WORLD_16, UNKNOWN), KEYSYM2SCANCODE(WORLD_17, UNKNOWN), KEYSYM2SCANCODE(WORLD_18, UNKNOWN), KEYSYM2SCANCODE(WORLD_19, UNKNOWN), KEYSYM2SCANCODE(WORLD_20, UNKNOWN), KEYSYM2SCANCODE(WORLD_21, UNKNOWN), KEYSYM2SCANCODE(WORLD_22, UNKNOWN), KEYSYM2SCANCODE(WORLD_23, UNKNOWN), KEYSYM2SCANCODE(WORLD_24, UNKNOWN), KEYSYM2SCANCODE(WORLD_25, UNKNOWN), KEYSYM2SCANCODE(WORLD_26, UNKNOWN), KEYSYM2SCANCODE(WORLD_27, UNKNOWN), KEYSYM2SCANCODE(WORLD_28, UNKNOWN), KEYSYM2SCANCODE(WORLD_29, UNKNOWN), KEYSYM2SCANCODE(WORLD_30, UNKNOWN), KEYSYM2SCANCODE(WORLD_31, UNKNOWN), KEYSYM2SCANCODE(WORLD_32, UNKNOWN), KEYSYM2SCANCODE(WORLD_33, UNKNOWN), KEYSYM2SCANCODE(WORLD_34, UNKNOWN), KEYSYM2SCANCODE(WORLD_35, UNKNOWN), KEYSYM2SCANCODE(WORLD_36, UNKNOWN), KEYSYM2SCANCODE(WORLD_37, UNKNOWN), KEYSYM2SCANCODE(WORLD_38, UNKNOWN), KEYSYM2SCANCODE(WORLD_39, UNKNOWN), KEYSYM2SCANCODE(WORLD_40, UNKNOWN), KEYSYM2SCANCODE(WORLD_41, UNKNOWN), KEYSYM2SCANCODE(WORLD_42, UNKNOWN), KEYSYM2SCANCODE(WORLD_43, UNKNOWN), KEYSYM2SCANCODE(WORLD_44, UNKNOWN), KEYSYM2SCANCODE(WORLD_45, UNKNOWN), KEYSYM2SCANCODE(WORLD_46, UNKNOWN), KEYSYM2SCANCODE(WORLD_47, UNKNOWN), KEYSYM2SCANCODE(WORLD_48, UNKNOWN), KEYSYM2SCANCODE(WORLD_49, UNKNOWN), KEYSYM2SCANCODE(WORLD_50, UNKNOWN), KEYSYM2SCANCODE(WORLD_51, UNKNOWN), KEYSYM2SCANCODE(WORLD_52, UNKNOWN), KEYSYM2SCANCODE(WORLD_53, UNKNOWN), KEYSYM2SCANCODE(WORLD_54, UNKNOWN), KEYSYM2SCANCODE(WORLD_55, UNKNOWN), KEYSYM2SCANCODE(WORLD_56, UNKNOWN), KEYSYM2SCANCODE(WORLD_57, UNKNOWN), KEYSYM2SCANCODE(WORLD_58, UNKNOWN), KEYSYM2SCANCODE(WORLD_59, UNKNOWN), KEYSYM2SCANCODE(WORLD_60, UNKNOWN), KEYSYM2SCANCODE(WORLD_61, UNKNOWN), KEYSYM2SCANCODE(WORLD_62, UNKNOWN), KEYSYM2SCANCODE(WORLD_63, UNKNOWN), KEYSYM2SCANCODE(WORLD_64, UNKNOWN), KEYSYM2SCANCODE(WORLD_65, UNKNOWN), KEYSYM2SCANCODE(WORLD_66, UNKNOWN), KEYSYM2SCANCODE(WORLD_67, UNKNOWN), KEYSYM2SCANCODE(WORLD_68, UNKNOWN), KEYSYM2SCANCODE(WORLD_69, UNKNOWN), KEYSYM2SCANCODE(WORLD_70, UNKNOWN), KEYSYM2SCANCODE(WORLD_71, UNKNOWN), KEYSYM2SCANCODE(WORLD_72, UNKNOWN), KEYSYM2SCANCODE(WORLD_73, UNKNOWN), KEYSYM2SCANCODE(WORLD_74, UNKNOWN), KEYSYM2SCANCODE(WORLD_75, UNKNOWN), KEYSYM2SCANCODE(WORLD_76, UNKNOWN), KEYSYM2SCANCODE(WORLD_77, UNKNOWN), KEYSYM2SCANCODE(WORLD_78, UNKNOWN), KEYSYM2SCANCODE(WORLD_79, UNKNOWN), KEYSYM2SCANCODE(WORLD_80, UNKNOWN), KEYSYM2SCANCODE(WORLD_81, UNKNOWN), KEYSYM2SCANCODE(WORLD_82, UNKNOWN), KEYSYM2SCANCODE(WORLD_83, UNKNOWN), KEYSYM2SCANCODE(WORLD_84, UNKNOWN), KEYSYM2SCANCODE(WORLD_85, UNKNOWN), KEYSYM2SCANCODE(WORLD_86, UNKNOWN), KEYSYM2SCANCODE(WORLD_87, UNKNOWN), KEYSYM2SCANCODE(WORLD_88, UNKNOWN), KEYSYM2SCANCODE(WORLD_89, UNKNOWN), KEYSYM2SCANCODE(WORLD_90, UNKNOWN), KEYSYM2SCANCODE(WORLD_91, UNKNOWN), KEYSYM2SCANCODE(WORLD_92, UNKNOWN), KEYSYM2SCANCODE(WORLD_93, UNKNOWN), KEYSYM2SCANCODE(WORLD_94, UNKNOWN), KEYSYM2SCANCODE(WORLD_95, UNKNOWN), KEYSYM2SCANCODE(KP0, KP_0), KEYSYM2SCANCODE(KP1, KP_1), KEYSYM2SCANCODE(KP2, KP_2), KEYSYM2SCANCODE(KP3, KP_3), KEYSYM2SCANCODE(KP4, KP_4), KEYSYM2SCANCODE(KP5, KP_5), KEYSYM2SCANCODE(KP6, KP_6), KEYSYM2SCANCODE(KP7, KP_7), KEYSYM2SCANCODE(KP8, KP_8), KEYSYM2SCANCODE(KP9, KP_9), KEYSYM2SCANCODE(KP_PERIOD, KP_PERIOD), KEYSYM2SCANCODE(KP_DIVIDE, KP_DIVIDE), KEYSYM2SCANCODE(KP_MULTIPLY, KP_MULTIPLY), KEYSYM2SCANCODE(KP_MINUS, KP_MINUS), KEYSYM2SCANCODE(KP_PLUS, KP_PLUS), KEYSYM2SCANCODE(KP_ENTER, KP_ENTER), KEYSYM2SCANCODE(KP_EQUALS, KP_EQUALS), KEYSYM2SCANCODE(UP, UP), KEYSYM2SCANCODE(DOWN, DOWN), KEYSYM2SCANCODE(RIGHT, RIGHT), KEYSYM2SCANCODE(LEFT, LEFT), KEYSYM2SCANCODE(INSERT, INSERT), KEYSYM2SCANCODE(HOME, HOME), KEYSYM2SCANCODE(END, END), KEYSYM2SCANCODE(PAGEUP, PAGEUP), KEYSYM2SCANCODE(PAGEDOWN, PAGEDOWN), KEYSYM2SCANCODE(F1, F1), KEYSYM2SCANCODE(F2, F2), KEYSYM2SCANCODE(F3, F3), KEYSYM2SCANCODE(F4, F4), KEYSYM2SCANCODE(F5, F5), KEYSYM2SCANCODE(F6, F6), KEYSYM2SCANCODE(F7, F7), KEYSYM2SCANCODE(F8, F8), KEYSYM2SCANCODE(F9, F9), KEYSYM2SCANCODE(F10, F10), KEYSYM2SCANCODE(F11, F11), KEYSYM2SCANCODE(F12, F12), KEYSYM2SCANCODE(F13, F13), KEYSYM2SCANCODE(F14, F14), KEYSYM2SCANCODE(F15, F15), KEYSYM2SCANCODE(NUMLOCK, NUMLOCKCLEAR), KEYSYM2SCANCODE(CAPSLOCK, CAPSLOCK), KEYSYM2SCANCODE(SCROLLOCK, UNKNOWN), KEYSYM2SCANCODE(RSHIFT, RSHIFT), KEYSYM2SCANCODE(LSHIFT, LSHIFT), KEYSYM2SCANCODE(RCTRL, RCTRL), KEYSYM2SCANCODE(LCTRL, LCTRL), KEYSYM2SCANCODE(RALT, RALT), KEYSYM2SCANCODE(LALT, LALT), KEYSYM2SCANCODE(RMETA, UNKNOWN), KEYSYM2SCANCODE(LMETA, UNKNOWN), KEYSYM2SCANCODE(LSUPER, LGUI), KEYSYM2SCANCODE(RSUPER, RGUI), KEYSYM2SCANCODE(MODE, MODE), KEYSYM2SCANCODE(COMPOSE, UNKNOWN), KEYSYM2SCANCODE(HELP, HELP), KEYSYM2SCANCODE(PRINT, UNKNOWN), KEYSYM2SCANCODE(SYSREQ, SYSREQ), KEYSYM2SCANCODE(BREAK, UNKNOWN), KEYSYM2SCANCODE(MENU, MENU), KEYSYM2SCANCODE(POWER, POWER), KEYSYM2SCANCODE(EURO, UNKNOWN), KEYSYM2SCANCODE(UNDO, UNDO), KEYSYM2SCANCODE(UNKNOWN, NONUSHASH), KEYSYM2SCANCODE(UNKNOWN, APOSTROPHE), KEYSYM2SCANCODE(UNKNOWN, GRAVE), KEYSYM2SCANCODE(UNKNOWN, PRINTSCREEN), KEYSYM2SCANCODE(UNKNOWN, SCROLLLOCK), KEYSYM2SCANCODE(UNKNOWN, NONUSBACKSLASH), KEYSYM2SCANCODE(UNKNOWN, APPLICATION), KEYSYM2SCANCODE(UNKNOWN, F16), KEYSYM2SCANCODE(UNKNOWN, F17), KEYSYM2SCANCODE(UNKNOWN, F18), KEYSYM2SCANCODE(UNKNOWN, F19), KEYSYM2SCANCODE(UNKNOWN, F20), KEYSYM2SCANCODE(UNKNOWN, F21), KEYSYM2SCANCODE(UNKNOWN, F22), KEYSYM2SCANCODE(UNKNOWN, F23), KEYSYM2SCANCODE(UNKNOWN, F24), KEYSYM2SCANCODE(UNKNOWN, EXECUTE), KEYSYM2SCANCODE(UNKNOWN, SELECT), KEYSYM2SCANCODE(UNKNOWN, STOP), KEYSYM2SCANCODE(UNKNOWN, AGAIN), KEYSYM2SCANCODE(UNKNOWN, CUT), KEYSYM2SCANCODE(UNKNOWN, COPY), KEYSYM2SCANCODE(UNKNOWN, PASTE), KEYSYM2SCANCODE(UNKNOWN, FIND), KEYSYM2SCANCODE(UNKNOWN, MUTE), KEYSYM2SCANCODE(UNKNOWN, VOLUMEUP), KEYSYM2SCANCODE(UNKNOWN, VOLUMEDOWN), KEYSYM2SCANCODE(UNKNOWN, KP_COMMA), KEYSYM2SCANCODE(UNKNOWN, KP_EQUALSAS400), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL1), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL2), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL3), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL4), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL5), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL6), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL7), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL8), KEYSYM2SCANCODE(UNKNOWN, INTERNATIONAL9), KEYSYM2SCANCODE(UNKNOWN, LANG1), KEYSYM2SCANCODE(UNKNOWN, LANG2), KEYSYM2SCANCODE(UNKNOWN, LANG3), KEYSYM2SCANCODE(UNKNOWN, LANG4), KEYSYM2SCANCODE(UNKNOWN, LANG5), KEYSYM2SCANCODE(UNKNOWN, LANG6), KEYSYM2SCANCODE(UNKNOWN, LANG7), KEYSYM2SCANCODE(UNKNOWN, LANG8), KEYSYM2SCANCODE(UNKNOWN, LANG9), KEYSYM2SCANCODE(UNKNOWN, ALTERASE), KEYSYM2SCANCODE(UNKNOWN, CANCEL), KEYSYM2SCANCODE(UNKNOWN, PRIOR), KEYSYM2SCANCODE(UNKNOWN, RETURN2), KEYSYM2SCANCODE(UNKNOWN, SEPARATOR), KEYSYM2SCANCODE(UNKNOWN, OUT), KEYSYM2SCANCODE(UNKNOWN, OPER), KEYSYM2SCANCODE(UNKNOWN, CLEARAGAIN), KEYSYM2SCANCODE(UNKNOWN, CRSEL), KEYSYM2SCANCODE(UNKNOWN, EXSEL), KEYSYM2SCANCODE(UNKNOWN, KP_00), KEYSYM2SCANCODE(UNKNOWN, KP_000), KEYSYM2SCANCODE(UNKNOWN, THOUSANDSSEPARATOR), KEYSYM2SCANCODE(UNKNOWN, DECIMALSEPARATOR), KEYSYM2SCANCODE(UNKNOWN, CURRENCYUNIT), KEYSYM2SCANCODE(UNKNOWN, CURRENCYSUBUNIT), KEYSYM2SCANCODE(UNKNOWN, KP_LEFTPAREN), KEYSYM2SCANCODE(UNKNOWN, KP_RIGHTPAREN), KEYSYM2SCANCODE(UNKNOWN, KP_LEFTBRACE), KEYSYM2SCANCODE(UNKNOWN, KP_RIGHTBRACE), KEYSYM2SCANCODE(UNKNOWN, KP_TAB), KEYSYM2SCANCODE(UNKNOWN, KP_BACKSPACE), KEYSYM2SCANCODE(UNKNOWN, KP_A), KEYSYM2SCANCODE(UNKNOWN, KP_B), KEYSYM2SCANCODE(UNKNOWN, KP_C), KEYSYM2SCANCODE(UNKNOWN, KP_D), KEYSYM2SCANCODE(UNKNOWN, KP_E), KEYSYM2SCANCODE(UNKNOWN, KP_F), KEYSYM2SCANCODE(UNKNOWN, KP_XOR), KEYSYM2SCANCODE(UNKNOWN, KP_POWER), KEYSYM2SCANCODE(UNKNOWN, KP_PERCENT), KEYSYM2SCANCODE(UNKNOWN, KP_LESS), KEYSYM2SCANCODE(UNKNOWN, KP_GREATER), KEYSYM2SCANCODE(UNKNOWN, KP_AMPERSAND), KEYSYM2SCANCODE(UNKNOWN, KP_DBLAMPERSAND), KEYSYM2SCANCODE(UNKNOWN, KP_VERTICALBAR), KEYSYM2SCANCODE(UNKNOWN, KP_DBLVERTICALBAR), KEYSYM2SCANCODE(UNKNOWN, KP_COLON), KEYSYM2SCANCODE(UNKNOWN, KP_HASH), KEYSYM2SCANCODE(UNKNOWN, KP_SPACE), KEYSYM2SCANCODE(UNKNOWN, KP_AT), KEYSYM2SCANCODE(UNKNOWN, KP_EXCLAM), KEYSYM2SCANCODE(UNKNOWN, KP_MEMSTORE), KEYSYM2SCANCODE(UNKNOWN, KP_MEMRECALL), KEYSYM2SCANCODE(UNKNOWN, KP_MEMCLEAR), KEYSYM2SCANCODE(UNKNOWN, KP_MEMADD), KEYSYM2SCANCODE(UNKNOWN, KP_MEMSUBTRACT), KEYSYM2SCANCODE(UNKNOWN, KP_MEMMULTIPLY), KEYSYM2SCANCODE(UNKNOWN, KP_MEMDIVIDE), KEYSYM2SCANCODE(UNKNOWN, KP_PLUSMINUS), KEYSYM2SCANCODE(UNKNOWN, KP_CLEAR), KEYSYM2SCANCODE(UNKNOWN, KP_CLEARENTRY), KEYSYM2SCANCODE(UNKNOWN, KP_BINARY), KEYSYM2SCANCODE(UNKNOWN, KP_OCTAL), KEYSYM2SCANCODE(UNKNOWN, KP_DECIMAL), KEYSYM2SCANCODE(UNKNOWN, KP_HEXADECIMAL), KEYSYM2SCANCODE(UNKNOWN, AUDIONEXT), KEYSYM2SCANCODE(UNKNOWN, AUDIOPREV), KEYSYM2SCANCODE(UNKNOWN, AUDIOSTOP), KEYSYM2SCANCODE(UNKNOWN, AUDIOPLAY), KEYSYM2SCANCODE(UNKNOWN, AUDIOMUTE), KEYSYM2SCANCODE(UNKNOWN, MEDIASELECT), KEYSYM2SCANCODE(UNKNOWN, WWW), KEYSYM2SCANCODE(UNKNOWN, MAIL), KEYSYM2SCANCODE(UNKNOWN, CALCULATOR), KEYSYM2SCANCODE(UNKNOWN, COMPUTER), KEYSYM2SCANCODE(UNKNOWN, AC_SEARCH), KEYSYM2SCANCODE(UNKNOWN, AC_HOME), KEYSYM2SCANCODE(UNKNOWN, AC_BACK), KEYSYM2SCANCODE(UNKNOWN, AC_FORWARD), KEYSYM2SCANCODE(UNKNOWN, AC_STOP), KEYSYM2SCANCODE(UNKNOWN, AC_REFRESH), KEYSYM2SCANCODE(UNKNOWN, AC_BOOKMARKS), KEYSYM2SCANCODE(UNKNOWN, BRIGHTNESSDOWN), KEYSYM2SCANCODE(UNKNOWN, BRIGHTNESSUP), KEYSYM2SCANCODE(UNKNOWN, DISPLAYSWITCH), KEYSYM2SCANCODE(UNKNOWN, KBDILLUMTOGGLE), KEYSYM2SCANCODE(UNKNOWN, KBDILLUMDOWN), KEYSYM2SCANCODE(UNKNOWN, KBDILLUMUP), KEYSYM2SCANCODE(UNKNOWN, EJECT), KEYSYM2SCANCODE(UNKNOWN, SLEEP), KEYSYM2SCANCODE(UNKNOWN, APP1), KEYSYM2SCANCODE(UNKNOWN, APP2), }; int main(void) { size_t i, j; int found; uint16_t max_keysym = 0, max_scancode = 0; for (i = 0; i < ARRAY_SIZE(keycode2scancode); i++) { if (max_keysym < keycode2scancode[i].keysym) max_keysym = keycode2scancode[i].keysym; if (max_scancode < keycode2scancode[i].scancode) max_scancode = keycode2scancode[i].scancode; } puts("#include "); puts("#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))\n"); puts("uint16_t sdl_keysym2scancode(uint16_t keysym)\n{"); printf(" static const uint16_t keysym2scancode[%"PRIu16"] = {\n", max_keysym + 1); for (i = 0; i < (max_keysym + 1); i++) { found = 0; for (j = 0; j < ARRAY_SIZE(keycode2scancode); j++) { if (i != 0 && keycode2scancode[j].keysym == i) { printf(" 0x%04xu, /* %s -> %s */\n", keycode2scancode[j].scancode, keycode2scancode[j].keysym_name, keycode2scancode[j].scancode_name); if (found) fprintf(stderr, "Multiple entry with keysym %zu, %s -> %s\n", i, keycode2scancode[j].keysym_name, keycode2scancode[j].scancode_name); found = 1; } } if (!found) printf(" 0x%04xu, /* %s -> %s */\n", 0, "unassigned", "SDL_SCANCODE_UNKNOWN"); } puts(" };\n"); puts(" if (keysym >= ARRAY_SIZE(keysym2scancode))"); puts(" return 0;"); puts(" return keysym2scancode[keysym];\n}\n"); puts("uint16_t sdl_scancode2keysym(uint16_t scancode)\n{"); printf(" static const uint16_t scancode2keysym[%"PRIu16"] = {\n", max_scancode + 1); for (i = 0; i < (max_scancode + 1); i++) { found = 0; for (j = 0; j < ARRAY_SIZE(keycode2scancode); j++) { if (i != 0 && keycode2scancode[j].scancode == i) { printf(" 0x%04xu, /* %s -> %s */\n", keycode2scancode[j].keysym, keycode2scancode[j].scancode_name, keycode2scancode[j].keysym_name); if (found) fprintf(stderr, "Multiple entry with scancode %zu, %s -> %s\n", i, keycode2scancode[j].scancode_name, keycode2scancode[j].keysym_name); found = 1; } } if (!found) printf(" 0x%04xu, /* %s -> %s */\n", 0, "unassigned", "SDLK_UNKNOWN"); } puts(" };\n"); puts(" if (scancode >= ARRAY_SIZE(scancode2keysym))"); puts(" return 0;"); puts(" return scancode2keysym[scancode];\n}"); return 0; } mupen64plus-core-src-2.6.0/tools/install_binary_bundle.sh000077500000000000000000000120631464506436200235120ustar00rootroot00000000000000#!/bin/sh # # mupen64plus binary bundle install script # # Copyright 2007-2014 The Mupen64Plus Development Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # set -e export PATH=/bin:/usr/bin GINSTALLFLAG=-D if `which ginstall >/dev/null 2>&1`; then INSTALL=ginstall elif install --help >/dev/null 2>&1; then INSTALL=install elif [ -e "`which install 2>/dev/null`" ]; then printf "warning: GNU install not found, assuming BSD install\n" >&2 INSTALL=install GINSTALLFLAG= else printf "error: install tool not found\n" >&2 exit 1 fi INSTALL_STRIP_FLAG="${INSTALL_STRIP_FLAG:=-s}" usage() { printf "usage: $(basename $0) [PREFIX] [SHAREDIR] [BINDIR] [LIBDIR] [PLUGINDIR] [MANDIR] [APPSDIR] [ICONSDIR] \tPREFIX - installation directories prefix (default: /usr/local) \tSHAREDIR - path to Mupen64Plus shared data files (default: \$PREFIX/share/mupen64plus) \tBINDIR - path to Mupen64Plus binary program files (default: \$PREFIX/bin) \tLIBDIR - path to Mupen64Plus core library (default: \$PREFIX/lib) \tPLUGINDIR - path to Mupen64Plus plugin libraries (default: \$PREFIX/lib/mupen64plus) \tMANDIR - path to manual files (default: \$PREFIX/share/man) \tAPPSDIR - path to install desktop file (default: \$PREFIX/share/applications) \tICONSDIR - path to install icon files (default: \$PREFIX/share/icons/hicolor) " } if [ $# -gt 8 ]; then usage exit 1 fi PREFIX="${1:-/usr/local}" SHAREDIR="${2:-${PREFIX}/share/mupen64plus}" BINDIR="${3:-${PREFIX}/bin}" LIBDIR="${4:-${PREFIX}/lib}" PLUGINDIR="${5:-${PREFIX}/lib/mupen64plus}" MANDIR="${6:-${PREFIX}/share/man}" APPSDIR="${7:-${PREFIX}/share/applications}" ICONSDIR="${8:-${PREFIX}/share/icons/hicolor}" # simple check for permissions if [ -d "${SHAREDIR}" -a ! -w "${SHAREDIR}" ]; then printf "Error: you do not have permission to install at: ${SHAREDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${BINDIR}" -a ! -w "${BINDIR}" ]; then printf "Error: you do not have permission to install at: ${BINDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${LIBDIR}" -a ! -w "${LIBDIR}" ]; then printf "Error: you do not have permission to install at: ${LIBDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${PLUGINDIR}" -a ! -w "${PLUGINDIR}" ]; then printf "Error: you do not have permission to install at: ${PLUGINDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${MANDIR}" -a ! -w "${MANDIR}" ]; then printf "Error: you do not have permission to install at: ${MANDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${APPSDIR}" -a ! -w "${APPSDIR}" ]; then printf "Error: you do not have permission to install at: ${APPSDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${ICONSDIR}" -a ! -w "${ICONSDIR}" ]; then printf "Error: you do not have permission to install at: ${ICONSDIR}\nMaybe you need to be root?\n" exit 1 fi printf "Installing Mupen64Plus Binary Bundle to ${PREFIX}\n" # Mupen64Plus-Core $INSTALL -d -v "${LIBDIR}" $INSTALL -m 0644 "${INSTALL_STRIP_FLAG}" libmupen64plus.so.2.* "${LIBDIR}" /sbin/ldconfig $INSTALL -d -v "${SHAREDIR}" $INSTALL -m 0644 font.ttf "${SHAREDIR}" $INSTALL -m 0644 mupencheat.txt "${SHAREDIR}" $INSTALL -m 0644 mupen64plus.ini "${SHAREDIR}" $INSTALL -d -v "${SHAREDIR}/doc" $INSTALL -m 0644 doc/* "${SHAREDIR}/doc" # Mupen64Plus-ROM $INSTALL -m 0644 m64p_test_rom.v64 "${SHAREDIR}" # Mupen64Plus-UI-Console $INSTALL -d -v "${BINDIR}" $INSTALL $GINSTALLFLAG -m 0755 mupen64plus "${BINDIR}" $INSTALL -d -v "${MANDIR}/man6" $INSTALL -m 0644 man6/mupen64plus.6 "${MANDIR}/man6" $INSTALL -d -v "${APPSDIR}" $INSTALL -m 0644 mupen64plus.desktop "${APPSDIR}" $INSTALL -d -v "${ICONSDIR}/48x48/apps" $INSTALL -m 0644 icons/48x48/apps/mupen64plus.png "${ICONSDIR}/48x48/apps" $INSTALL -d -v "${ICONSDIR}/scalable/apps" $INSTALL -m 0644 icons/scalable/apps/mupen64plus.svg "${ICONSDIR}/scalable/apps" # Plugins $INSTALL -d -v "${PLUGINDIR}" $INSTALL -m 0644 "${INSTALL_STRIP_FLAG}" mupen64plus-audio-sdl.so "${PLUGINDIR}" $INSTALL -m 0644 "${INSTALL_STRIP_FLAG}" mupen64plus-input-sdl.so "${PLUGINDIR}" $INSTALL -m 0644 "${INSTALL_STRIP_FLAG}" mupen64plus-rsp-hle.so "${PLUGINDIR}" $INSTALL -m 0644 "${INSTALL_STRIP_FLAG}" mupen64plus-video-rice.so "${PLUGINDIR}" $INSTALL -m 0644 "${INSTALL_STRIP_FLAG}" mupen64plus-video-glide64mk2.so "${PLUGINDIR}" $INSTALL -m 0644 RiceVideoLinux.ini "${SHAREDIR}" $INSTALL -m 0644 InputAutoCfg.ini "${SHAREDIR}" $INSTALL -m 0644 Glide64mk2.ini "${SHAREDIR}" printf "Installation successful.\n" mupen64plus-core-src-2.6.0/tools/joymodel.c000066400000000000000000000376311464506436200206060ustar00rootroot00000000000000 #include #include #include #include #include "SDL.h" #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 // compile with: gcc -o joymodel -std=c99 -I/usr/include/SDL -lSDL -lpthread -lm joymodel.c static void DrawLine(SDL_Surface *screen, int x1, int y1, int x2, int y2, int color) { // Bresenham's line algorithm int itmp; const int steep = (abs(y2 - y1) > abs(x2 - x1)) ? 1 : 0; if(steep) { itmp = x1; x1 = y1; y1 = itmp; itmp = x2; x2 = y2; y2 = itmp; } if(x1 > x2) { itmp = x1; x1 = x2; x2 = itmp; itmp = y1; y1 = y2; y2 = itmp; } const int dx = x2 - x1; const int dy = abs(y2 - y1); float error = dx / 2.0f; const int ystep = (y1 < y2) ? 1 : -1; int y = y1; SDL_Rect pix_area; for (int x = x1; x <= x2; x++) { if(steep) { pix_area.x = y; pix_area.y = x; } else { pix_area.x = x; pix_area.y = y; } pix_area.w = 1; pix_area.h = 1; SDL_FillRect(screen, &pix_area, color); error -= dy; if (error < 0) { y += ystep; error += dx; } } } static int compareDoubles(const void *p1, const void *p2) { double d1 = *((double *) p1); double d2 = *((double *) p2); if (d1 < d2) return -1; else if (d1 > d2) return 1; else return 0; } void WatchJoystick(SDL_Joystick *joystick) { SDL_Surface *screen; const char *name; int i, done; SDL_Event event; int x, y, draw; SDL_Rect axis_area[2]; /* Set a video mode to display joystick axis position */ screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 16, 0); if ( screen == NULL ) { fprintf(stderr, "Couldn't set video mode: %s\n",SDL_GetError()); return; } /* Print info about the joystick we are watching */ name = SDL_JoystickName(SDL_JoystickIndex(joystick)); printf("Watching joystick %d: (%s)\n", SDL_JoystickIndex(joystick), name ? name : "Unknown Joystick"); printf("Joystick has %d axes, %d hats, %d balls, and %d buttons\n", SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick), SDL_JoystickNumBalls(joystick),SDL_JoystickNumButtons(joystick)); /* Initialize drawing rectangles */ memset(axis_area, 0, (sizeof axis_area)); draw = 0; double dMaxR = 0; double dRmaxByAngle[1024]; int iNonZeroValues = 0; for (i = 0; i < 1024; i++) dRmaxByAngle[i] = 0.0; /* Loop, getting joystick events! */ done = 0; while ( ! done ) { while ( SDL_PollEvent(&event) ) { switch (event.type) { case SDL_JOYAXISMOTION: if (event.jaxis.axis >= 0 && event.jaxis.axis <= 1) { double dX = (float) SDL_JoystickGetAxis(joystick, 0) / 32767.0; double dY = (float) SDL_JoystickGetAxis(joystick, 1) / 32767.0; double dR = sqrt(dX * dX + dY * dY); if (dR > dMaxR) dMaxR = dR; if (dR > 0.5) { // calculate 10-bit angle double dAngle = 0.0; if (dX == 0.0) { if (dY < 0.0) dAngle = 256; else dAngle = 768; } else if (dX > 0.0) { dAngle = atan(-dY/dX) * 512.0 / 3.1415926535797; if (dAngle < 0.0) dAngle += 1024.0; } else { dAngle = atan(-dY/dX) * 512.0 / 3.1415926535797 + 512.0; } //printf("Radius: %.2lf Angle: %.2lf (%lf, %lf)\n", dR, dAngle, dX, dY); int iAngle = (int) dAngle; if (dRmaxByAngle[iAngle] == 0.0f) { iNonZeroValues++; printf("non-zero values: %i\n", iNonZeroValues); if (iNonZeroValues == 800) // fixme 850 done = 1; } if (dR > dRmaxByAngle[iAngle]) dRmaxByAngle[iAngle] = dR; } } break; case SDL_KEYDOWN: if ( event.key.keysym.sym != SDLK_ESCAPE ) { break; } /* Fall through to signal quit */ case SDL_QUIT: done = 1; break; default: break; } } /* Erase previous axes */ SDL_FillRect(screen, &axis_area[draw], 0x0000); /* Draw the X/Y axis */ draw = !draw; x = (((int)SDL_JoystickGetAxis(joystick, 0))+32768); x *= SCREEN_WIDTH; x /= 65535; if ( x < 0 ) { x = 0; } else if ( x > (SCREEN_WIDTH-16) ) { x = SCREEN_WIDTH-16; } y = (((int)SDL_JoystickGetAxis(joystick, 1))+32768); y *= SCREEN_HEIGHT; y /= 65535; if ( y < 0 ) { y = 0; } else if ( y > (SCREEN_HEIGHT-16) ) { y = SCREEN_HEIGHT-16; } axis_area[draw].x = (Sint16)x; axis_area[draw].y = (Sint16)y; axis_area[draw].w = 16; axis_area[draw].h = 16; SDL_FillRect(screen, &axis_area[draw], 0xFFFF); SDL_UpdateRects(screen, 2, axis_area); } if (iNonZeroValues >= 800) { /* Erase previous axes */ SDL_FillRect(screen, &axis_area[draw], 0x0000); // normalize the radii values printf("Maximum radius = %.3lf (16-bit: %i)\n", dMaxR, (int) (dMaxR * 32768)); for (int x = 0; x < 1024; x++) { dRmaxByAngle[x] /= dMaxR; } // divide circle into octants double dCoefA[8], dCoefB[8], dCoefC[8]; for (int oct = 0; oct < 8; oct++) { const int startX = oct * 128; const int stopX = startX + 128; // pre-process the Rmax data by throwing out all of the non-0 points which are below the mean in any of the encompassing 16-point windows double dRmaxWindow[16], dRmaxSum = 0.0; int iXWindow[16]; int windHead = 0, windTail=0; for (x = startX; x < stopX; x++) { // new point? const double dNewPoint = dRmaxByAngle[x]; if (dNewPoint == 0.0) continue; // remove old point falling out of window if (windHead-windTail == 16) { dRmaxSum -= dRmaxWindow[windTail & 15]; windTail++; } // add new point dRmaxWindow[windHead & 15] = dNewPoint; iXWindow[windHead & 15] = x; dRmaxSum += dNewPoint; windHead++; // cull the herd if (windHead - windTail == 16) { double dAverage = dRmaxSum / 16.0; for (int i = 2; i < 14; i++) { if (dRmaxWindow[i] < dAverage) { dRmaxByAngle[iXWindow[i]] = 0.0; } } } } // pre-process the Rmax data by throwing out all of the points that are less than the median /* double dOctantSorted[128]; for (x = startX; x < stopX; x++) { dOctantSorted[x-startX] = dRmaxByAngle[x]; } qsort(dOctantSorted, 128, sizeof(double), compareDoubles); for (x = 0; x < 128; x++) if (dOctantSorted[x] > 0.0) break; double dRmaxMedian = dOctantSorted[(x+128)/2]; for (x = startX; x < stopX; x++) { if (dRmaxByAngle[x] < dRmaxMedian) dRmaxByAngle[x] = 0.0; } */ // calculate least-squares quadratic regression fit double dS[5][2]; for (int i = 0; i < 2; i++) for (int j = 0; j < 5; j++) dS[j][i] = 0.0; double dYSum = 0.0; int N = 0; for (x = startX; x < stopX; x++) { if (dRmaxByAngle[x] > 0.0) { dYSum += dRmaxByAngle[x]; N++; } } const double dYMean = dYSum / N; for (x = startX; x < stopX; x++) { double dX = (x - startX) / 128.0; double dY = dRmaxByAngle[x]; if (dY > 0.0) { dY -= dYMean; dS[0][0] += 1.0; dS[1][0] += dX; dS[2][0] += dX * dX; dS[3][0] += dX * dX * dX; dS[4][0] += dX * dX * dX * dX; dS[0][1] += dY; dS[1][1] += dX * dY; dS[2][1] += dX * dX * dY; } } /* Here's one way to do it double dDenom2 = (dS[0][0] * dS[2][0] * dS[4][0] - pow(dS[1][0],2) * dS[4][0] - dS[0][0] * pow(dS[3][0],2) + 2 * dS[1][0] * dS[2][0] * dS[3][0] - pow(dS[2][0],3)); double dA2 = (dS[0][1] * dS[1][0] * dS[3][0] - dS[1][1] * dS[0][0] * dS[3][0] - dS[0][1] * pow(dS[2][0],2) + dS[1][1] * dS[1][0] * dS[2][0] + dS[2][1] * dS[0][0] * dS[2][0] - dS[2][1] * pow(dS[1][0],2)) / dDenom2; double dB2 = (dS[1][1] * dS[0][0] * dS[4][0] - dS[0][1] * dS[1][0] * dS[4][0] + dS[0][1] * dS[2][0] * dS[3][0] - dS[2][1] * dS[0][0] * dS[3][0] - dS[1][1] * pow(dS[2][0],2) + dS[2][1] * dS[1][0] * dS[2][0]) / dDenom2; double dC2 = (dS[0][1] * dS[2][0] * dS[4][0] - dS[1][1] * dS[1][0] * dS[4][0] - dS[0][1] * pow(dS[3][0],2) + dS[1][1] * dS[2][0] * dS[3][0] + dS[2][1] * dS[1][0] * dS[3][0] - dS[2][1] * pow(dS[2][0],2)) / dDenom2 + dYMean; printf("Least-squares fit for %03i - %03i degrees: A=%.3lf B=%.3lf C=%.3lf\n", oct*45, oct*45+45, dA2, dB2, dC2); */ /* Here's another */ double dSxx = dS[2][0] - dS[1][0] * dS[1][0] / dS[0][0]; double dSxy = dS[1][1] - dS[1][0] * dS[0][1] / dS[0][0]; double dSxx2 = dS[3][0] - dS[1][0] * dS[2][0] / dS[0][0]; double dSx2y = dS[2][1] - dS[2][0] * dS[0][1] / dS[0][0]; double dSx2x2 = dS[4][0] - dS[2][0] * dS[2][0] / dS[0][0]; double dDenom = dSxx * dSx2x2 - dSxx2 * dSxx2; double dA = (dSx2y * dSxx - dSxy * dSxx2) / dDenom; double dB = (dSxy * dSx2x2 - dSx2y * dSxx2) / dDenom; double dC = dS[0][1] / dS[0][0] - dB * dS[1][0] / dS[0][0] - dA * dS[2][0] / dS[0][0] + dYMean; printf("Least-squares fit for %03i - %03i degrees: A=%.3lf B=%.3lf C=%.3lf\n", oct*45, oct*45+45, dA, dB, dC); dCoefA[oct] = dA; dCoefB[oct] = dB; dCoefC[oct] = dC; // draw the points for (x = startX; x < stopX; x++) { if (dRmaxByAngle[x] == 0.0) continue; int pixX = (int) ((0.5 * dRmaxByAngle[x] * cos(x * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); int pixY = (int) ((0.5 * dRmaxByAngle[x] * -sin(x * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); if (pixY < 1) pixY = 1; if (pixY > SCREEN_HEIGHT-2) pixY = SCREEN_HEIGHT-2; axis_area[0].x = pixX - 1; axis_area[0].y = pixY - 1; axis_area[0].w = 3; axis_area[0].h = 3; SDL_FillRect(screen, &axis_area[0], 0xF800); } // draw the curve for (x = startX; x < stopX; x += 4) { double dX0 = (x - startX) / 128.0; double dX1 = dX0 + (4.0 / 128.0); double dR0 = (dA*dX0*dX0 + dB*dX0 + dC); double dR1 = (dA*dX1*dX1 + dB*dX1 + dC); int lineX0 = (int) ((0.5 * dR0 * cos(x * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); int lineY0 = (int) ((0.5 * dR0 * -sin(x * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); int lineX1 = (int) ((0.5 * dR1 * cos((x+4) * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); int lineY1 = (int) ((0.5 * dR1 * -sin((x+4) * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); DrawLine(screen, lineX0, lineY0, lineX1, lineY1, 0xffff); } // refresh the screen SDL_UpdateRect(screen, 0, 0, 0, 0); } // find the octant with the maximum area under the curve int iBigOct[2] = { -1, -1 }; double dBigArea[2] = { 0.0, 0.0 }; for (int oct = 0; oct < 8; oct++) { double dArea = (dCoefA[oct] / 3.0) + (dCoefB[oct] / 2.0) + dCoefC[oct]; if (iBigOct[oct&1] == -1 || dArea > dBigArea[oct&1]) { iBigOct[oct&1] = oct; dBigArea[oct&1] = dArea; } } printf("Octants %i and %i have the most area\n", iBigOct[0], iBigOct[1]); // draw this curve in blue on each octant double dHardA[2] = { 0.250, 0.228 }; double dHardB[2] = { -0.115, -0.361 }; double dHardC[2] = { 0.867, 1.000 }; for (int oct = 0; oct < 8; oct++) { const int startX = oct * 128; const int stopX = startX + 128; // draw the curve //const double dA = dCoefA[iBigOct[oct&1]]; //const double dB = dCoefB[iBigOct[oct&1]]; //const double dC = dCoefC[iBigOct[oct&1]]; const double dA = dHardA[oct&1]; const double dB = dHardB[oct&1]; const double dC = dHardC[oct&1]; for (x = startX; x < stopX; x += 4) { double dX0 = (x - startX) / 128.0; double dX1 = dX0 + (4.0 / 128.0); double dR0 = (dA*dX0*dX0 + dB*dX0 + dC); double dR1 = (dA*dX1*dX1 + dB*dX1 + dC); int lineX0 = (int) ((0.5 * dR0 * cos(x * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); int lineY0 = (int) ((0.5 * dR0 * -sin(x * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); int lineX1 = (int) ((0.5 * dR1 * cos((x+4) * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); int lineY1 = (int) ((0.5 * dR1 * -sin((x+4) * 3.14159265 / 512) + 0.5) * SCREEN_HEIGHT); DrawLine(screen, lineX0, lineY0, lineX1, lineY1, 0x001f); } } // refresh the screen SDL_UpdateRect(screen, 0, 0, 0, 0); // wait for keypress while (1) { if (SDL_PollEvent(&event)) { if (event.type == SDL_KEYDOWN) break; } SDL_Delay(10); } } } int main(int argc, char *argv[]) { const char *name; int i; SDL_Joystick *joystick; /* Initialize SDL (Note: video is required to start event loop) */ if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0 ) { fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError()); exit(1); } /* Print information about the joysticks */ printf("There are %d joysticks attached\n", SDL_NumJoysticks()); for ( i=0; iÂ4 JKX†v‡'‰Nµv»Í#”f³9Û²8g~Z¦¥ëzRŠl6›Ëå+ccéT¦T.S¢u:í(Œ¤c;–e2ž  |?J Ó´9—q;¶£ëºïy•ÑÑz­–¶œ‹/º(p½§wíÜ0öƒb¾`é¦L‹cƸ ºa¦S ¤¤Èʦs¥""Ðh6ã0° ‹öÚÄÀ6mË0SN*Ÿ+”Ë]…B¾ËyíVmllthhààþbiQuZm¿Ù [mðcŠ0`”H!‰ÒVª3ˆÇIÇó¢$.”˽óú»úzìTªÝq¬VªùLnÅòe Ìga´{çöíÛ~Ãb¦›ºaš¦í¤Òi;m—»º,\˜J9ÍZm`ßþ±¡as¿ÕJüÐ$ZÚq(!n§ív܈1AÒ)GDQ”Ä€Õ5Í4,Û¶§\.ºáuÜJe¬Ón’ Œ”HKqÆ…À€Æ”ÃгÙ\6›M’¸Vo4„'™\¶X(•Ê¥L.gZ–ä¬:2òôÓ{#Éúúç_¸|Y*—|˜Ì:éR:—ÒL¿Õyò‰ÍG†‡;¡ðˆSÔ=¯/“Î /hûIFa†>ÜÛÛséÅ—^vÉ%K–\0§·@îÛ·o÷Þ=­VS×t*¥›Ys¬V9<26Z‰Â0]È¥²9Ý2±¦!ŒE¡ãØ==Ý]årúöí>Òj7cžpq{¾—J§ˆFÍÆ‘#G¢(Bû®‡¢Eˆ8¶­Íí¸IœhT·Sv&›íŸ??—ËAØnµ$‡þþù+–-Ÿ3gN!ŸG ]¯úÁðÈ‘Ý;w8°oll¬Ñl×F"4Ûê›3wnßÇtª£•±Ñ ’رít*rÒN:íA˜ÄcªSL±¦é„`¿ãŽŽŒvZ-!”²B±ˆt:8 »ººí´%A¶ZíF³D‘e©tF×-G·MÍ2 +íØñááÃî÷C·P(,YrA*í`‚[­öÈÈX½Þˆ¢Ä÷ƒ ¨®çóùr¹”N¥ Óò¼N¥Z‰“ȲLÛ¶Bß÷]Ï÷ü( à –1#ˆèš¦Q¸äA"„-ÛéÓ·pÑ"Ë´æàà`«ÕŠ¢˜íòu—¯\±Òq·Ý>2Ül6óùü¾}û0ÅÙB¾ÜÓÕÕ×m§Sš¡§3)j^§3tèÐÀþ<áÑ Ã´l‡êÆ¡¡Ã¿úõ¶‘±ãb^ßÜ‹V¬L;vä­vsttõ·ÃĶmÛ¶aÃPEQ”³€V«•z­ÆXJ!G74'åøˆb˜¦e[¦mº¡Ù†Ä(Œ¢8I$&DÓuS7’ D„]“cJIŽ ŽãN»£S-ö‘$ @K‰¥ \pA’$:HÐ%˜ ’\H‡‘Çnj&Æ$â$ QÅ„PC7lËòM#’ !„0F˜‚Lb)%€R 2t-fq’ÄBp€ñl !@PŠ5ª×jõNÛ•€1FXš–¸ëw$Cq˜P]×LÍpl¬i\H‘ÎQʶiF+•zšõ–ßvCÏQÈ’Ù€Œ0pa‚(Õ¨F¥”Qq.ABGŽÇ9×5RJ1‘\$Q$8¶e3–a@‘ #×õ™ ãN:e;©0ްF1¡­v‡óCIœPªq!ÜŽ‹0ÆÁ ÍzÝõ<;•Òm‹êºiY•z-ˆ‰IW·A‰D"$¥äœù¾g:%cÇI…œ1Ó²(%˜`–$IœaHtêPÌ#Ī',‘QBt¤#¢„%.9OxÀ±H LD CŒ¤A)•RJa›&‘’'ÈÔ©©aR°DÇk„¤QL0â\ !%#$ArK!… $EX£„H¤clhþ·7IOÔyNEQåì¡Bò?~Û–/_þò—¿¼§§GEDQEQΟþô§O>ùäè¶ý@i*å’’s„Q±\µjÍó}×÷C¿S­Ör©|¹PèÊugSYM×LÓ0M“h„#á ‡ŽKg3©lÖJ¥€.DÌXÖÐ ©lx­VK\QE™µœó†ß}Ý+_ùÊ—¿üå*Š¢(Šrμìe/[³fÍ×¾öµ}¿Ü5ÿŠÕÙlF ‡¡íØŒåÍ&¡8•²¢Ä9|èpD ®§:&c'•Ž¢Rj§SÄm' O˜àTî*sš¡ÅI@$ BÀÔ ÇvTÀEQ”YË9ûûû¯ºê*)¥Š…¢(Š¢œK¦iÞxãŸÿüçY] ÉPÚÕUÖuR¯×ZÍ&%8·îÒzµ‰™#7‰Â ô'…ª·šcZ††ahŽN(Ì9ã$ÁZ:m¦Ó6t z)SPÑVEQf-ç\»v­Š‚¢(Š¢ÌÎa˜Ò—¾ô¥>ú(HiÚHÉH¢S’Ëf #[×)%àÊHÍõ=É‘FŒ„1?Œ€…œqM#š­‘—„>!ØÐ5ÓÀ¹LÊ1 –Ä:¨óœŠ¢(ʬìúûûÕINEQE™-‹-€ƒÝ=]©”C ÃD064] *äònË‚†n†à\€”#ŒKâÐ÷0TÊqL#mY¶eR„ƒ0@K„TœEQ”YË9Óéôñ¯³m{µV›AC…BþâÕ«U@EQeZ2™ ŒŽŒZ¦©ìØ’ÀâÄmuZÍfF:ÕÒ©LO·¬”äØ1Ó¹\3Yo¶ª)€%qÚ´³™t.2MÂH"Á˜ bÁUœEQ”YË9OxÝq;¾>/ˆØ´Z1ubxMEQE™™ýO?Í“˜à ËÅ2ŸÑl>½wßàÁƒQä3ùE‹Í3wþƒ3@’8fJp`âÀ¡¡CµJ5‘f“žb©Ü]Îç³ Ýh Fò%kN¢"¬(Š¢ÌZÎyÂ…µŒóïlÚç… '_sŠRS'7_a«ktEQefR¶íuܱá,dàûµjõðà`½Z¢p0b9¹b¡„a½Z74Ó÷<Ò6t3efrN.•ãpxäH£ZO‚H$" ãv­yØЦyù’¢¼°Üó¥{àmoyó ±WÏÏÎ+ÊÎ9O>9ùñw½b }ç»ßSç9EQ”!ÆØÈÈHww·¦iÇ “$íéé¡”N¥‘®R1ƒF­Á‚8“Éš†)™&D̲él©\„ºžkš¶ä@ åŒñ„QÀ¶a¤§»XÆR¶ª‘ÃC­F“"ªa‚¨ø¾«r©æREQf/ç<¹H¥ŽŠ¢(Ê NÇ»ví€eË–éº~.W=:::88X©TV®\9¾ê8Ž·oßƸ¯¯oò·vmËêîê“tªIL0³$Œ+ÕÝÝë&±çù‚WlÃNÙ‹,¥Nˆ¡;'¥a\j×›qòí±.0ÂD2¡¶å<¦N*ÊÙpèÐaÃ0J¥"Æ8çµz= £yóæN;ç<1ÔRˆ™™¤”*YUEQfE’$;vìð<vìØ±bÅŠãO9žmåryttÔ÷ýmÛ¶­ZµJJ9žpZ–U*•N{p¯@)™ß?¿Íâœ@¦aâ Ò‰†¢DÌכÍJ\ϧ³ ç- ˜P‚mÓÐMÍ6Fµ:xd Z¯Æ,Ò(54ݶ­l:‹±Á®7Ûj#QÎcÇ_ž*¥Ü½gÏÎÝ{\×M9β¥K—-]Òét¾öÈ£”Ò›n¸~üËAñÀW¿†Ñ¼þº¯}ãxéë³m»™LzÍ¥—Öë]»wGq\Èç¯Xy±P˜¨qôÛgíÙ»wûÎ]®ë¦S©Õ«VžÐÉ={÷îܽ»ÓqÛ^¾lÙ²¥K¦òÑ lÛ±£ÝnSª]rÑê%^¨†[9g4]¢h¬Ré*—¥”c•*KMŸÉáŸ|äc3¢NEQeVÄq|,áÏóvìØÇñ¹;*kÚÊ•+Ç ‚à©§žÚºukŽã¬\¹r*©ïø´»«»\*—ŠåT:ÍâDJÇq’pËr¦N§ÝnGQÇQ§ÕjÔêI[º™r²:V980p|¯víÞóó_l*äò7ÝpÃüùý¿xâ‰Ý{öNå³üø~¢kúë_÷ºë®}m£ÑT㫜K]å’¦iIœŒU*•j•% Õh©XœAS'žç”R2>“Ù€¤*íTEQνݻw{žç8ÎxÚ9¾°{÷îU«VË´sùòå¿þõ¯`Á‚Ë—/×4m*GÆñ:óç÷s&@ÈB¾ø~E‘L&£zäÈ·Õi4˜„\&—)d{{zLjÖ…p[ÍFµZoWýØ)L]ÃcŒ0&ºaP¢' c1“L=ŸSyñ|!쀕+W躾j劻wïÚ½{ù²¥«W­<´{ÏÞ¥K–Àxò¹bùŠco¼ìÒKu]?v1üe—\¢ëúܹs ÙjMÞ8ìØµ Ö­YcYÖøÂ¡ÃCÇgpÉÅ麶jÅŠ_ÿfÛÎ]»–.9ÍIË;vÀúukÇ€õ—¯S㫜Kã®®òØX%‰ ”v•ËdFߢRÊc—Œù8ŸÉìv*áTEQfB(N/]ºôÉ'Ÿ€åË—ïÚµküæ“sIÁ9G!„8çS¼QåXµT*xàœjcÌÓMͶ-J)Õ„ˆbF¡/•жe‹˜KÆ1€N‰¡i€Œ$ ü(ŠAŽ1åœë¶™OƒN4:<¦¶åEÂõ<°LLÓ?0x¨Ï÷öt{£mY@~ûÕaÛöø×Ëñ¿r'j:Œ'‡à¤RÏê•ëÀW¿þc%íNç´ŸÅó}H¥ÓjX•Ù"¥<öÜ„Ž>Kó äœBJÆf’s •s*Š¢(³aåÊ•Ï4M[½zõ9îCEÛ¶mcŒõ÷÷{¹jÕ*Ã0&9ÿïÚv»ã¹^œsM× ‹ $"3ÁÆr¹œi§lËa ¯U«Q'pÛ-Á¹eZ ³7”B°„ $ujX–eX¦DˆqÆê<§ò¢áØv»Ó Âбí0  õÛ<ð¢Õ«FFGwïÙÛ××Ë9_¹bùl.…RZ*U4EQefX’ØŽíØv:åsÙB.×ÓÝ•¶v«½sûŽ‘Z#Õ•ë_¸ ì D™Ä(á,ŠBõb©l;iÆd³ÑªŒV½v¸`GAű•ʨ+Š¢(Ï—œóòµkÇŸd=­û3 !3˜ûKQEQ”qœs0M3ŸË÷ôts¹ž®îŒ“J›ÎèàÐÈXÍï¸} ;}©vµî7ZÄ ºeè–i§ÓºeÌÛÏ‘¬×j±ºßq£0âqŒLÛѹMy¤"¬(Š¢<_rN•@*Š¢(ʹÇI£Ñ¤˜d3™$í¶dÅ·}ÇÈÐŒC”XýóçTÃé4· /ðŒ´“#ÈÐ5à¢ÙlÔFG‚v‡¶-+¤ØÐbW©ÐÝŹšçOQEy>圊¢(Š¢œcÙl6‚NÇ>2 ‰(äòÑÒVš# rëíÝÞöVµ^*•úæÌ©TÜ¡±‘F»…¤d,fazuÒˆâX;ð­”Uîë)”ËÍzSEXQEQ9§¢(Š¢¼x ×õ’˜E!÷¼ÐÔÂF½,ÃCƒÃÕ±º · G ¸ÈæsõV³Új†qd„AµÝABJÉ`)±ÀBš†M#D¾Š°¢(Š¢rNEQEyñŠc†SBA"ÆÀsÃØœ‡^Pm5ÛD’”¡Ûº©!yض!ΓÀ— )¥’—!0 CËØN!›Êe ÆêÚŠ¢(ÊìçœÅ¢šuVQEQεZ­6¾à»¾¡›¦iñ˜Ia˜p,4B Ã6M§%;:ÕR©t¶˜Ïåòál*].[¸¸.!$Î@¾ïEI„Y†aäÒN.cš&°m[…ZQE™åœSQEQ”YdV¹Üe[N§Õæ1\Ø©ÌܾyùLvðÀß üvG¡š²Ý05¶MÛCm’PjD2.ñ„°)1,“*3 +ŸÉ«+Š¢(*çTEQ”¯•+VõõöeR™ÊXõÈá¡Ñáß ‘€b¾Ä#¶oïþÑá‘ÃCC­vK3ôîÞ^žD±ë‹(14M'© ôAB'™vÚÉ ùBA7 Ý4 MÇ&Ÿ|í±^xË—ªjEQ•s*Š¢(ÊùiÅŠ•ÕyóœFµÉ¹¬×ëCCCù\®T.覦ۦôˆø•Ñ1, ˆ|¯ÖìTë^è ,Ã$¤–I¡§íòœžùýýš¦ÅIœ6팓i mòµÈn5Š¢(ŠÊ9EQå¼¥kºÄ‘©[súúc÷í8þ‹RPS×-Ó°,]×5J“¨ˆ £ñ€G‚ÇH#™t!“˦áw<·ÓƉÈYYǰ·mÛ6Ɉ IDATÚw{—¨y†EQ•s*Š¢(ÊyŠ%œRJ0‰£°Pȧl‹b8°oßXucá—\3u'“Ng3¹lÆÖ(‘ ¥°\ËQÕmF’CÓt]Q¯ÕG‡†Ýf³n§y((5Þ÷žÿw’µ_÷znY–>EQE圊¢(Šò¼„AW©L,R«T4BóùÌ‹aC‡=¿%!ÕiFÏòÅ\>ŸÍå¥í†NtÍñڭГ< ãV³9æ{cCÃQÛmh†ÛLËyê©§Ž­kÍš5ǯzË–-Ç¿œî_ Ã8K-¿ ÿºq#<òÈšzž|òY]»öhÉt[>öÆé¾¡-ÇÞ¨ÆhêÑX»¤<ë¸ç[4žŸ½zþõØ~w¶×;ão†Ê_Ñø,íêY)Š¢(Šrî…ï¸ãŽEKW®Z±*å8‡ £°ÉR‚êõêÁƒ†ny^Ä¥n8…\¡§T.¤³ˆ1×mWjµf§Ù :M¿ç £8òÚ­v½á5[2a ":ºk×ö³ôÔyÎSºür¸ývxÕ«ÎXƒÁ̳:ã7¾È©¸©ø«Í@m' Îs*Š¢(ÊóÁÖ­¿ÂÏíëCBOLÃÌfSùBºV%&#&±¬T.Ê @Q‚€a™€BPL@bœ%‚û±ˆÛ´œœ‰1nya£é¿®á‘‘í;v:<Ä9O§R‹-ºø¢Õš¦@«ÝÞò˧ AËf/_·vá‚“Ô?_ýüçðÞ÷ÂÏ~6Õò“íÚW]u>ÿD>Ï27•a*/æýT圊¢(Šò¢p`ÿ 1·¯Ï¶MÇ6³Ù‡‹¨Q«7ë’cSp)EÂy‚"("2! )Æ5¤·ÛAà…žËƒ£TËd³ùBaaÕ›íã×µé‰Í+–/Éúõ–ey¾ÿÔÖ_}ÿ‡?zí5W·Z­o<úÍU+W®¹ìÒ”ã4[­M›7/\°`¢úçñp|ò“ðž÷L£üdèºÚ®EQ° ¢(Š¢Ì:Bpï3Æ@ ŒAÓH:mϙӽdéâ\&‡„„0%ØÐ¤N#$<û,N8£˘Em/jyÜ Q"š¦ç ùÞ9}sûûŽ_×®ûý%^à8Æ8J­¿|ÝÐÐlÞ²åâ‹V_vé%ÙL†R,^{õÕ“Ô?_íÝ ;wÂë_?Õò =káøòãKŽ•õ«°t)X¬] [·-Cø‹¿€în(—áŸÿùôÝ>a½Ç¯è”ísÿ8,Z…¼õ­àº§ißóàOþzz »n» |ÿ™?}å+pùåÉÀ‚ðŸÿyúþÜw,Y–¿û»pðàiâ0I;'[²öìyVÉ®]°téiâ?­¸ÍVü‚7½ øèGášk Ÿ‡ÿ÷Éâùæ7ßüÉÑåw½ Þò–Óo‡§lÿ„šÇ^NÒŸ‰œ²ŸãMÝy'ô÷ƒã<³©OŸ‰Ú™(nõZûÝ$ý9eÿgk;™dœ(,§ìÿаqãÑåŸý V®œyTΩ(Š¢(ÏŸœ“r·G†[­B8J†A0N9ö¼¹s³™Läûn»E±Q ”$BÄŒ1Æ8ã‘ç³0’Q‚™00vL˶mÓ4-ÛvÒ¶a™§\©¢ÝnoüŦ¾¾>8a½Ç¯ë”íÿË¿ÀcÁ~ûö¥ð៦ý|†‡aëVغ‚}ìhùÿù?ðÿÿûÃð0ü÷ÃÏ~úþ<ü0|ó›P«Á† ÏäEõs’vNvíµðøãÏ*ùŸÿ×½n²øO7n³ÿñÔñ‘Gàcƒ÷¼¾ým¸ãŽÉâù¹ÏÁ÷¿_û<ü0üàð¹Ï~;œ¨ýéög";|ÿûðÃÂÁƒðßÿ}úøLÒδLk¿›|¼Nîÿlm'í“;¹ÿ7Þ>xtù¡‡àÆg¾ÝÍlÕBŠ¢(Š2[ŽÍ!´c÷þB>oYöòeK.X¼hÑ‚þ\ÆÆÀyúnçÇ?þÉæ-ÛÜ@äË]}ýý‹—\Øì´VFGÂN'vݰÙâq”A gˆ'›íž;§{nOª˜«Ökw|ì'¬úß¾p×øB>—{Ãu¿ošæ¿ßõûçͽbýúL&ã¹îÆMO8Ž}Õ•WNTüåy6‡Pµ kÖÀ®]pÂÇš¨|ÂXܯur9BpèÌ àûP.ƒç,Zßý.\x!ÀîݰlÙ”n›zûË–Á·¾‹ŒÁºu000YË À÷¿ÿL~ï÷`ÿ~€Å‹áþûaݺéÅaœçAW×ÑþLÔÏ©´sÌ÷Ü_ú¼éM ipï½ðæ7Ã;Þ¯|å—ÙŠ?B†€1èúÑÇ8ž0žð‹_=-ÿÈ#°~ýéûyÊöO¨yìåTú3•qojÿ~X¸ðYu¦Ÿڙʈßÿiíw“ôç”ýŸ­íd¢ýq¢8LÔÿßü^÷º£§‘çχoV­šITΩ(Š¢(Ï£œsûν…R)•Îôt•—/]ºxáÂ9½e“â ÝlÕ*;vî}bëö]û€êK–­¸ò%Wî;p`pð`«Z ÝNÐnÆ^Ç Dpæ»? ÁÅžžþ… Š=e§­ýýßÞ~òÚ…íNç©­[ã8¾zÆÿ¸çž›o¼Ñqœñ¿úAðÀC_}Û[ÞÓÝ~¦Ûÿ‰ö»ÉÇkZ çYÝN&Ú'Ã)ûÿÆ7ÂCÁCÁßx¶[•s*Š¢(ÊìËçr\ŠV«¾¦¦iŒ ¶夜LF–nÌëí»páâsû-ÝÔ(Õuݶì|¡Pîé6t$  $ï$qÃw›¾[i6Ǫµã×õè·¾}p` ŠcÎy³Ùڸ鉮r–/[ú£Ço4œóV«õ??ùé &©þ¹çxík¡TšjùYõ‡ï{ŒŽÂð0¼÷½S}ל9ð­oMé‡à;ß ïxìÛQ7Âuצþ 7ÀûÞ##02ï}/ÜpÃÑò¿þkxÇ;`ãFð}سn»í4ýñ}èêÛ†ƒ§‘ÆOýs½îuðw·Ü·ÜþðÑ›9Ï`û³ÿ‰Lϱ1x÷»áî»áî»áÝ±¶É%ðÏÿ žƒƒðîwÏ<2Ó÷‰â3Ýv¦Ûÿ‰ö»35^g{;™hœÁ8ÞxãÑœóØÍœÏ%*çTEQ”Ù7wþÜl.;66¶{÷ÞÁÁÁf«•Ä ÂIJөT& Âv£)bfë¦Ni½RmÔêAHŒtËÔlS7  „cŒ-ÝΧBV踸õf³Ýî¿®µ—]¶c×®{ï»ï?¿ø_ßùîw ]¿æ5`é’%óûû¿ó½ïÿß»ïyä[ßΤÓ/½bý$õÏ3BÀ§?}Š_c•O×DóÙNäC‚¹sᢋ`õjøß™êZ>ñ øÓ?]?ý*þò/áå/‡×½r9øó?‡·½í4õ?ö1(•ࢋࢋ « >úÑgÚyÿûNõùêWÃÚµ§éÏ=÷À?é4¼êU§ŸxŸëµ¯…¡!¸þz¸þz‚ßû½)ÅêíÏVü'ùGÉ)ãù§ o;¬[ëÖÁ[ßúLz6ÝíðsŸƒ¯ŠEذþðŸÓ?t¦5îÅgºíL·ÿíwgj¼Îöv2Ñþ8ƒq¼øbÐ4Ðu¸è¢3u?§¢(Š¢Ìšc÷s.¿äÒF£¹cû®C‡ÏïŸÿ;W^ù²õ—Ïíë‘,iüη¿»ÿàሕÊh¦]kÖ+µº©šaPŠe{aäUGkÍ:Òh¡TJò±,IBÏ«ŽŒýô?9Ká¼¹Ÿóá‡áÞ{áᇧZ®(Š¢LU!PEQ”YWȊŲe¥ÆÚºuë‚9sºËe Ðq=ÎOx%$ŠY³ÞŒÛ)Û° Œ‹ˆK #J¨¡);ßUNç²Õf»íyQkš®"|ZwÞ wÞ9rEQE圊¢(Šò‚!¤Ìg3Ù|> ¢ýð±Ý»÷ì\¸haÿ¼R¡@©‘Jg…ì´;z"RB Õ ÓJ9˜¢„E cq’0'Œ!Œ ÝÐMC‚ £p<áLláÓšèAvS|À¢(Š2u?§¢(Š¢Ì¾F³^o4¢8Z¸há²eË@®]»öì܉è3¯¿¾iYQqÆR©Ô¼¹sçÍWÈç ]'˜PL0@G,J4D ª‰8©ŽŒ5+UÄEOWï¼¹óU„EQ•s*Š¢(Ê‹W†¾ïy®›J¥.½ì’eË–º®÷˧¶nß¶M$cbÛ6Â8ŒcιišN:eè:Æ#¤âX¶†ˆŽ±cZiäLºµfìú¶fu»Š…’Šð]|çÍßyóÙkÍš5gµþìç¸3^yfxà 6¬=a†¢²uëÖmذáP;òb ®­UEQ”ç)Mä˜è†ÞÛÝÛ}ÍÕG~âÉÍ–®Sæòù®žî˜IDp6ŸcB†q¤kFÒw 'ÅtÎ05) S­­a¼`§ŠÙÂDøybË–-gµþ¬tu¼æYÍ9ïºë®;ï¼sõêÕçÍ–°iÓ¦§žzêøÀM7ݤö E圊¢(Š¢œuCCC…|±\*S„LÇ*æt—Ê{­{vìøéÏÖ?w®nÝ==1—¶“Îæó~6;­„%H‚N5†‰I4]#pÅ2ˆQ˜èe Û $ˆÙñëÙ¾cÇ¡ÃCœót*µxÑ¢‹/Z­i´Úí-¿|êðÐP¹löòukÇÑ9®ãº_ýÚׂ ¼í·ž¯ñ«÷Ü?­úã'E§û®ãKÕ4M+•J/{ÙËn»í¶l6;ƒ¦î¿ÿþûî»ott´»»ûÍo~óT’™5kÖL5·üÀg~̸à=çêNáz½~ñÅ?×VŽ=—Bž^N§}Œñe—]V¯×Õ·Ÿ¢rNEQEQÎ…ƒ”K¥R±„tOÿÊ]%ËBÏÛþë_çR7 Sò‰F 0u]|WrN"ëTãQ%1ç\Æ ÄL èIO€ÛôÄæË—¿dýz˲<ßj믾ÿýöš«[­Ö7ý檕+×\viÊqš­Ö¦Í›åœBˆïÿà‡—^rÉÏ7þB×™5žõqΫÕêƒ>ø7ó7Ÿýìg§ÛÈw¾ó|ðŸþéŸ/^üôÓOä#Éår¯yÍkÎX/?ðÿü+@/ÀÀ?Ü ðȹˆ=ÇçfŸ ¢³ÖÑi¶B !0V7»)*çTEQå,«U*OïÙë˜Î‚ MÝŒâ8ŸIõ/èG\TÇF*µ*ãR3LÝt0ç®çBMÓŒL3 89¤ ýÀs;‚s X„—(h–ù¬kkßpÝï[N§Rë/_÷__º6oÙrñE«/þíó¿‹…Âk¯¾ú™LuófÓ4/^½ú|Í9¿óøó–ãå×­üÇ÷mÑ©öþß}Û†%ëO¨?•³ÇÎgNt^‘ÒÝÝý¶·½íꫯž¤~’$Ÿþô§¿ûÝïJ)ßñŽwÜyçã¾úÕ¯¾ï}ï[µj¬^½ú½ï}ïÝwß=žs~ï{ß»÷Þ{8Ífo½õÖ׿þõÇ·ÚŽõ³ã–ü3@ï¹Îùüã®®®ór«ëêêzì±Ç^ñŠWBNÞZfñÊjEQ9§¢(Š¢œoã¶íÌ7W.%—RXVjþ… 7yå_y¨Ñh¶“ÊÈDȶç&œ‚A‚Â÷} c„”R1~RȱBuH0Æ„8åJ…®ëþrë¯úúúàðБ¾ÞÞû|¨Ýn;¶}Á‹×\z)¥>üô¾ý7Ýpýy<ããD½dÁE7\üª·Þ÷wŸ|ì‹ã9çñõ§rmíiozäœW*•/}éK+V¬˜¤þÝwß=88øå/™RúñüXùÞ½{W®\yìåªU«öìÙ÷ßÿÃ?ü·û·K–,ýÒ—¾4žsk†‰Í·^1“÷2“ôáòË/G}ìc;/·º?ÿó?ÿûß/¥T饢rNEQEQÎ.Ó0áè‰J×6ír©ˆ0IÓ(í_²xÉò%›6n‹b^(á0IŽŒŒ†^(ä(Q½Õn¶[qpÁÉçRé¬fÍV«á»'¯ñß¾p×øB>—?ó†áÁ×¼úU™LÆsÝ›žØ¸iÓUW^éûþûñ†W¿Ê0Œí½zÉåSíœùðŽOú»»¿ð…/L–ë}ë[ŸùÌgÆÏûýÕ_ýÕüãñrß÷mû™Û+Çñ<î»ï¾Ûo¿}<]°`Á‡?üá3ÐãþÀOfòÖé&W7nüâ¿xÏ=÷\{íµçßvu÷Ýw¿ë]ïzë[ßú£¤(*çTEQåt9§®c@R ß$ƈŒ1B LC[µjÅ®{†ŽŒHÀ™\ÁqÒ8‰Û—h·[Gv5$8B¡ºcÓà ›íÖh½vòo{ç­Bˆv§óÔÖ­ÿä'WoØ iôw®ºÊqÈf³/¿êe<ôÕ«®¼ò?zlåŠ}½½/æÒ‰vö?v?çØØØ½÷Þû‰O|â3ŸùÌD•ÇÆÆz;===ÇÊmÛö}?•J¿ô³9ŠE圊¢(Š¢LO&“ Ã@JÁ)1B ¥”a$¥t=/›Éöv÷$LX†¡Qjš&&8 Cß÷’$A„h† Î8 o5Œt™¦¥éüÙ÷s>ú­o¯^µ²··—Òé¸[ýë®r–/[ú£ÇÙK^’Éd\×ݸé‰ñIkOH/UÂy¼¢­ù­ÁæH®ç96%„¨×ë>øà…^8Iµk¯½öSŸúÔ‡>ô!MÓþõ_ÿõXùõ×_çw~ô£]´hÑþýû?ùÉOÞzë­pË-·üýßÿýßüÍߌßÏyß}÷}ðƒ<>ƒýéOzå•Wž~êÔ{þà|ø9Mý:ƒ„ cŒ1>«ó»ÎÊœ=ãŸè” ¿šCHQ9§¢<Ÿ…Ï~iªˆ(Šò‚P*•jµJ„FËk{’F$Fkº† ÆÄI9Œ ÃÐçœ1É’`꺥S$žèB<ÏM☠Á‚ évœBÁ¢iMÖu¡k/»ì©_ÿê‡=&„L9΂ùó¯yÍXºdIÇßùÞ÷;ŽmÛ‹.\·vÍ‹g¦;í¸¿¸êæÏýìÁ×ÿÇÿRNqÞÚ“Ó‰ñJi>Ÿ_»víí·ß>Iý·¿ýíŸþô§ÿèþÞùÎw>þøãÇrÑf³ù|`tt´§§ç–[n?_zóÍ7çr¹O|âétúï|çñ½úË¿üËÛo¿½R©!N“á¼>ð‘ã ¹s1:]]]›6mZ¿~ýsJ;ѳ~ûÍv» sæÌy®½œ ý‰Î7žr>Þ3ÖEyÞ@µZ ŠÅ¢Š…òÂÏ0ON2U ª(ÊóÚøQøŽ;îèéé«Tª#ãùlaýúõk×\ÞÓÝmh` ;ðôþ_ü|ãŽ;5ÍX¸øÃqvíÙ{äÈP³Ù@ˆÛ–nh$‰ßï92Z«ÆœŠå\©˜-uM¯U¾ùõ¯Ÿ¥`Y–ÇÙ266öŽw¼ãÑG=ã-Oë–ų}ÿ$<òÈ#ŸýìgkµÚ“O>yÆÿÊW¾ò/ÿò/÷ÜsÏÒ¥KÏÙØ­]»¶X,þÙŸýÙu×]÷|袜Uê<§ò‚N2ÍIj˜*Uå…£§¯7›Ë! Q6­$J@ –H™ÍÀ€IÌÕµT:­†çùv;Žc‚±®Ñ´ãóÙ0p;®&LjI™)tÛR&ŒzâüùåCúЭ·ÞZ(>ÿùÏ¿â¯8«˜Vöx.½îºëNÎÍΔo|ãøÀÎq‚7Iò<+ýQ•s**ɬRQ•s*Ê #É}úXÌN7dX¯?ˆ“IÊ$ @I‚Ä(¹Ä a.̱Ërl0 Bá°ZCRŽ„Áè¸êÌæ³çÎUUׂ Q«³zõÊ4¢(ðx½e'OU×Ô„B!½N—?|XfFƺ764H-:Ÿ³R/É(ŠJHH¸ûî»çÍ›§ÓéÚÚÇüòË/¿ð >øàMÊÀç«péÓþp³V";μ¼¼–Z¿°  `1Àìö¶¿ñâ8>dȧӉ%Òœˆ®¢*¯«ÐÚPCø¦Íi’fÚ%5í#A;>~ÑÅ 1 Ãq,ÇÙív¿ËG‘¤^¯ãX¶¦¶:Ädëu¥Bçtxê,6– c€S” @’DB81Ì`8†(ò,Ë…X‘ãå8!à $§Ýéry¢ã*=v<';û΂…BO>³ÿ@єɓ<ÏÎ]»äæ2X­R¹=žÒãÇ332Èì*DÆA°Ûíï¿ÿþ³Ï>ûÚk¯µ-¨âââ‘#Gß<͹`6À€d€€—¦ü÷fÄ,Š"†a-µþàï[†”<`x¨ýìo]¼†a&Š"ŽvºF ͉è¬"ófé¨kEfcmÙ9ôÚ@´ŽŠŠJ’ T*•Ãf÷{üÆøø¼ÁyU••ÕU•gΜÎî?€–iX† 3¬$ˆ2™LFÉ@0^¢„à"/ð ˳,.Jr™\†ÀóA_€cÙè¸~>õúkZ]?ü-[àxYYÞ yƒEnâã§LštûTÕï\¼{õ·ÖЉýF\ó³# «ïøäܸ/ç“8×®Ûl¼†ó¯{_ß÷mI?Sú?x:A¥{Rˆ IDATõ³& ÿ9\øÉù#¼(ŒïSð‡±Ò”<†=Çq+W®Ü¿¿(Š3gÎll@DbbâŒ3&MšÍ/† ‡Ã«V­Ú»w¯$IO<ñÄŠ+ê †)++Û±cÇôéÓY–•ËLÏСCŸ~úé;vx<žyóæ=úè£Á¶yóæ;wú|¾Ñ£G/^¼X©üqtrÏž=¯¿þºÙl4hÐ’%KRRRbUÀ—Qׯ$ߌzá‹/¾0™L-õ°`9À ð€51µ\kíoi¼&“éàÁƒcÇŽ%"Ú=ÒŠ:á mÒœ$2›ðI7ïÒœªlÔf¯/Óddç‘vh^.hHUUµ( &£1Ìqjµ2%5%ÑhÌHO+;~ì›o¾f‚LïÌþ¡Ä0QRP%“±,`’ €ƒ †6̰RXÀ$%0åÃa¿ MF*Š¢ßï?yúLD T×Ô¦$'¾ÿ×ëU)•½{g <˜$Ix{ë6†a E|\܀ܜŒôôîW+í8Y}áÏãf‰’í¾©tçÛÇwÿyÜ,Xz`“Z®œ3â× ­¿)³¿)séM«íxùg±Ž3ÙTºó­ã»þ:i®œ”ýù“ÿ¨åЧG?Ã~Æ f³¹°°PÅ¿ÿýïMŠ(›Í¶eË–œœh~1äæÍ›+++·mÛF’dƒpJJJrssSSSsrrJJJÆŒ}kýúõæ¹çž‹hÎíÛ·Ÿ8qbýúõjµzåÊ•ëÖ­[´hQĸ¨¨håÊ•‰‰‰;vìxå•WÖ¬YÓŠúø`l[ê±ÉeŸ1ÄR~~>†a/¾øbK#8uUÈE¸`A»ÚßÒxçÏŸ¿xñbI’¼D ͉è"³…!þèÒhèòF\s!D Q¦5´ã% ’ ÜE‘r™,599#-=1Á”šœœd2 aöÈáCß~û­R¦N4¦‚$b 8Fà˜(J,Çü>Qà1  £HJNñl8Ìsa>Ä2@RJ¥LÞĸYý*Í8½>2òÉ0Ì•ŠŠ‰ãÇiµÚ€ß´ôØÑÒÒQ#GÖO¬eYÖj³-)u8CîfUp¬ò˜Ôo„°¬è­z÷]gEÜ#šs×7‡Z¢9ëíK*¾Žm Bß'`ï·Gckν{÷®Y³Æ`0ÀÂ… >ܤÜJLL|ã7biºO>Y½zud|ï©§žúâ‹/êoGtæØ±cë¯#<û쳩©©°víÚˆËG}´zõêÈk‹ùóç?öØcõšsùòå‘‹iÓ¦mܸ±•ñ>ÀB€Ãm©ÇÖŠ¥£G¾ýöÛo½õVKŸñ"ú ` @€§]íoi¼›7ož;wîã?~ƒ¥Š@ ͉¸©"³Y¢u&IßiÕ@ˆ6 E£ â–Â…y†aAì™––™™©¤r¹LIËr²û½Þ£_–ÔVW‰a I…Œ @AeÉð¬Ïï³ÛíÀs8Ž©”*Ip “ÁÃùŸ\R ´VÓ8ÆysžEÑëó:}ºøðáI&P9fÔ(•J:nô¨»ßûàÃQ#GÖ{‘Ëå={ôÐNÔ~øw?Íéù@K«¸[üŽhw‹¿E›¬ÔÛ»BÞØ–‘ðGþgVä_³×ÛÞf³%%%E®“““ A¬VëÖ­[—/_¾zõêæÂ±Z­õÞëQ92gÎ=zô›o¾½À¯ñüX³Ù½æ³ÞòÂ… «W¯>þ¼×ëmE5„þ ðÀ'}oF½Ëd²_þò—6lh©-€ 2jkе«ý-·¢¢âÿý¿ÿ'“¡Ó•Hs"n©Èlù,Y&æÙzÈܲ¶O7«e™¾•ŠIPâ¶€ç·ÛëõúiZ¥Q©œD‰¢å=ÒÒ4´2̰Î}Ï2—{ôH7%¦2YˆåB ãõº½~O ô»J9 a’Æ%‰Æq^¯Ðª›ŒÇq½Nw׈ïlÛ†xCK’Jà8HR÷«­¶Ü>6(^›;“:¾Êmñ±AI’ Q}W”$Albêr½½^ñ“àWÉ.Äòœœ”5ÿÈïÞÔÈU-I§Ñh4›ÍiiiPWW×DDrrò¼yó&Ož#“ÉT[[›‘‘Ñ œòòr§Óyÿý÷×»|ýõ×õ{º6Þk'%%eÓ¦MZ­¶ûâÅ‹gΜ¹lÙ2Fãõzï¹çžëçí"ÀtÀI€„6ÖckçÖFÞ°47ÿ¼ î(xøê¿_ÜÑ®ö·4^AÚ¼×1´-Õm(2£?ôµŸVÔ@dFh’†k?tÔ'Z3ѯœ˜F nsúÚäý˜È«Ÿk²ÖThÑ.L3ˆéÒ ýi$è’ˆ¼Ä1œÇí­ªª2[l^¯eBa–9A«Õ2T.—UT\¾ðí¹+•í.›Óí°:l5ÖZ«ÃdƒnŸ‡åÃ"@àIN⤌V) Š ±×|?ìúäÓ+,Ç ‚àv{Ž–3Ý¿_Qq±ËåÁãñ:|$²iíîO?«ª®æ8Žçy«ÕöyÑÁììþݯ òÓr`ï·G÷^ø*ÚýþœQ÷}ß•Àý¹£êµ"”×}àûcC«·/HPïØÏ”¹%ÁO²vjîØPò.tÉQýܧ×ÙivòäÉ«V­r:v»}ÕªUM´%Q´Ûí[¶léÓ§OŒpî»ï¾ýë_‹ÅétF¯´,..ž3gNÙUfÏž]\\#œ_üâ/½ôRuu5Çqååå .üñ—‘aâããiš®­­]¶lÙõ+`+À0€û>m»àŒÈËÆ\§7Œã8Ž‹¢Ø¢~ °à0€àÀ3ó£îbX+ì‡ÚÒsGÛ5Þ¦¿…DÇñ&·ðmE:ˆ¦@ãœÝ^a6V,íÏ\ÁU%Ù ‡Þ®Îþm°úôVE º a–IÉf³Ÿ:Qæs¸tjUÏÔ”Ô¤$µB)§È”=ââãÎ|ýÅi³¸l¦”TJF³k6›íV ËÔ ©“8NIÁ‡ã%ã%‘x·ÇÊá踆 rªü̃EQR«Téé“'N€~}û²÷Ù¾ý>ŸO©Tfef6²û÷?~¢Ìátâ8¦Óêrr²³ûõë~UðÔèGj<¶U‡vL¸vßÚ' ~îgƒ¯õ!<6tʬüç‘þñžÇ–½=ÿÃe£³†4íœùÒþïJóRú.5½Þñ™q3_Þ·áoû7>ÿÙ:¸ºÏí¬‚%v=´ãäÞŒøäÙ×ÙZtöìÙ+W®|øá‡A˜5kV´ Œ¨’$ãâ↠¶téRˆ÷k°õèÌ™3W­Zõë_ÿæÌ™SNqqñ+¯¼RæØ±cŸ{î¹ šÝfÚ´iðÔSOÕÖÖöêÕë‰'žˆ¸¿øâ‹¯¾úêŸþô'“É4þü={ö\§€%K¢]ú›Qû&“©´´´  àúÇ„üÀ0  à…ëmÛ¼}dÖqd}ìõi¿x›œGmrÿÞÖ¥h Ìáp@d%:¢Û‰Lº}µHã5tSqÓO1mJCãô7ár½³[®ã½c §ƒ_: ˆ&ò+¼lÙ²’Ó៎ "oÐé q:16ÆÇ%*9ƒh0Ë¿.?óÍ7g4“Rpœ`ù°Ãáp»\Ï% z­“DŸÇírºÝ.¯ÛãÅIJŸ—`à„ð‡¼ÛAYP(¨»:V«õ‰'žØµk×M‹±¹\nܸmü÷¿ÿ}íµ×lj'nZ!¼ûî»+W®|ë­·úu‚—8Æ 3 ¿ýío§NڙӉ袠qÎn+2ÛKƒEkªczMH·{ºÛ ÝN¾®»Gn¬U¬×JôØú<†RmMvè˜ô'щˆ×BŒßïó0,ãrI~Çn¶Ô¨*Ix•VÍ aœÂôJ}bJ’>Áàñùx•©hƒÜˆƒDS&#„°ÀŠ|0ÌØPDZFa2BQ •0¢1ùË_ž|òÉøøø×_}ìØ±73êV©Ç›°iêÔ©Sk­ŽfçÎÏ<óL'r1Äv§J'iNÄ-Ñ™í/˜;¹ä6'–,ïÛxdÕ/Ñ)ÈHÏ =Vk-¢œ$¨¸8š$$Ià˜ZAc°B˜PÈjMrÏJ6Ès|ÀOÒ2B+#0ÆïpqL$pÇD§” M\œZ¯W(B%ŒhÌwÞ9wîÜp8Z¡+hZ¥’<Ȱ $&` `:•.!ÉØ3#Mgˆ÷1œ$A?AÊLÈîrÉü~ê•J9-Ç0àEŽ¿vßZD Nþãž‹ïß½[›™Ùá‡B¡­[·nÞ¼5¢³±hÑ¢Y³fMŸ>¦Ñ/>iÎÛLd^WƒÒ-™¼?*â¦JЛ8­ÿD n,Ã0 #ácBFfúùsßÚޏ8CŸ>} φCA†çyI '“L‰é™qFP„ˆCJrŠËãôû$A)ä´$I¡@L»=€“DÐ玫Îl>{î\Uu µ:«W¯¼A)Š×[vòTuMM(ÒëtùÇEŽèlνûá­¨Mzz…_TT4`À€ôFá·v„³£ÇE‡Ú;÷¼°  `1Àì›W¿˜/À_>°¦ü ÀØ•ò•žžž››[TT4eÊôŒ@š³›‹Ì¶‡Û² f;N‘ Z¼%´Á­–OÄm}úé[‘uâvÁëõº]nŸO£Ó«SSzØmξ»ì°;AÔê´a† ÃIÒ ¹J£¢”2^/“Ëž“D‰–˵m0P)Iˆ‚ô‚@Àçs{]I48ä½ôØñœìì;  E ¯Ç͇Ã8Q”<:®ŸO} þZ£VägËV8^V–7h`Þ A‘[†øø)“&ÅpïflÏÍmpYÏ)òü™•+¯ìÞ-IRæä=ý4N’ÑfYÿó?•ûö…}¾–¬ÿ<þüüùó£]"#–¢Ç-#îSsÇ_,“‘Ôâ{gLè[ÐÀ¾%£¡Pèßÿþ÷ÁƒàÞ{ï]¸paýÌÉ}ûömݺõòåË:îÉ'Ÿ|ðÁ!ê0ÌŽ:s-Àr€10àk~Òœ‘H[ãÍÌ—ÅbÙ³gÏgŸ}VXØ|Q—| €ž/ô¼FãuÂ|5æŽ;îØ¸q#úBF ÍÙEufÛ{ätLÙrÔÀí ?›V¡7O‚¢É·DÛñ¸Ý[à™Œ úÙ¬^}œôÕW_*‰6l­ I%H¢ ““‚(È0L¡P2* Ølžp8̇ù0æX– 8&¼`ÐëµñqJµªÉHEQôûý'OŸIII€êšÚ”ääÂ÷?ðz½*¥²wﬡƒ“$Ùœ{7«‚ˆbŒV›ÎmÜx~óæaù œøÛß(µzÀÿþo´G Ã:xðÊ®]-‰Ån·×L¸Œ(Æh%̓þ'oÜãÛ_øçÁ·#š3Ú¾%skׯ_o·Û %Izùå—ßxã @aaáG}ôÜsÏõíÛ×b±lÙ²%¢a"Š¥ås5ë¥N4±üžº*8#ܰ -õÕÑùŸÏwàÀO?ýôÒ¥KcÇŽ]¸pa,뇖üáê8ç €_tÒ|ÅÀh4Úívô…Œ@š³k‰ÌfûßÑ«+¯´lróP´PçRz]G…¶¶å0mÏ5š|‹@ÜÀï1%“$ ‡y…B¡T*sr² ‚8uêä7ß|§×§õÈàEÞë÷º>Ìóa—€"pZ.kãº76D.âôúÈÈ'Ã0W**&ާÕj~ÿÑÒcGKKGÙœûmR5—wî€ôI“"šóòÎ 4ç  H…¢÷¯~Õ±ï›Oâ$X|ζ…pàÀµk× øýïÿ»ßý.¢a¶oß¾téÒÜÜ\ÈÈÈxþùçÛ~«¥ŽÀóÖ$xÚZGçëüã™3gîºë®3fqk&Dm¿fbíMÎWô‹€èñÏæÜ£_  ocÒœ]Bj¶kûªZ`ÈDÜ" zÃzM¾E Z„Àó§Îj5&⌢$jµšs)ŠÜ»÷“c'NH"NËhœ"0AÂqÁ ×ï …B’ …‚!ŸÛã´;¼^7Ë„ršÀÓ¨Ô:µ¶qŒóæ<)Š¢×ç;uútñáÓ&L (r̨Q*• t:ÝèQw¿÷Á‡£FŽlÎý6©š Å2îÇ­Ö†ßzññ--!!Ájµ¦¥¥µÐ^FP7˜~‡Ã‘””¹NNN¶Ùl‘k³Ùœ••u T àHXö«óQ;Y¾$IŠh°–ʰÇ >H0,ø ÀÇ·&_õ2²ÁøgsîõX,–„„ô…Œ@š³sêLhÉxf[ÔæU=@wdê‘@ôfIPÔèˆf%ð‚¯01 NP*R¥×ëûõëÇ Ìɲ²Êš*C¼”‘r…\ 'pÇ9†ñ¸\LˆaBŒÍbu;L0$ 8ER ò8J­læäÇõ:Ý]#F¼³m;â Mš5ç~› 0™üUUœ× ’J“©¡Ek††²³³ËËË[®9oƒÁ`6›#1ÖÕÕÕ+Ф¤¤K—.åää4é Ã0I’Z"·Z=·ö€b€‡¯þûÀ1_+V¬ðù|ŸþùæÍ›Ÿþù{î¹gâĉÇoÖÃ~€=¤ü GgÌWlΜ9“¾íŽŠ õJ­þCG}Zä-º^ï­þšá™Èx†&iš¤[:¢5¬›/A£?‘æýiE+¿~¾~jì·(»Dç… Á@Ðï÷3!Æïˆ‚$Šèãtùùù}ûõõxݕՕŸ#0E‡Y†a!ŸÇëvº\vWФHR¯ÕÅëâHÇ1\FA×®O>½RQÁrœ n·çhé1“ÑÙýû»\.A<Ï¡ÃG"›Ó6ç~›9u*TîÙS¹woý¿mfôèÑûöík%©Ô@¥Û|]ËqãÆ­ZµÊáp8ŽU«VÝ{ï½÷Gy䥗^*//g¦¢¢béҥѾL&Ó‘#GDQ¼nøeMËÃoðx`þ5 ¶I{óó桇zã7¶mÛ–ššºbÅŠXÖÞ¨Tü ¿“æ+û÷ï=z4úBF´;hœ³å=çúNs»†{+8A bHÐM´ýZiƒÅ˨å#8 …vgeUuJbø8QDI¹œ$ºwï¬K—.UT^Q*•&“I­Ör 1eØ ?àvºxŽ“S2ZIÓr>¶Ù¬<–Éd I^—;:ªaC†œ*?sààAQ”Ô*UFzú䉠_ß¾,Ç}¶o¿ÏçS*•Y™™Ã‡ á~›ûä“aŸïëuë ÿo~“3û†N“7nÜ«¯¾zåÊ•Œ«º½µûÐFøÝ¨ik¿|ÿÁ7Š’Û~îܹÿú׿~øa3fÌܹs#îÓ¦MÓëõË—/¯¨¨Ðh4sæÌ‰öµ`Á‚¥K—Úl6QÛyßÚ_ØfT¤¼ðÓ¦µ^¯RSS[ÌÍÌWbbâŒ3f̘˨àÏw]=Ÿs@á­ÏWsylÒýòåËgÏž]¾|9ú>F´;˜Ãá€ÈJeÄ JÍæ¬›Ø%èj?éLDǾÕh÷t¶uG"º;äh"¿ÂË–-s¹äw•R…”=07ÏdLJMé§Ã0‰¤ f÷îÝ{èÐ!–e33232zYmv·Ëãõú}^ŸËé°Ùm‚ Äét$!&ðù=^wÐïKOO3ŸoÇ{tP ªÇV±yóæS§N­^½EÞ}÷Ý•+W¾õÖ[ýúõCùºù,X°`ðàÁ3gÎDMÑî qÎé×Ý\³?-Ï0-î©#n·vFßX7M±ÅXÚd«¦[”l‰O"1Éäñ×]ºôƒN§ÎÉH+•$%DQpœ¤¨áùÃD‘¿xñ’LFü~§Ýnµ9|^ÐðxÜLÑjÕC<ϱ¡`P‡ ç^ž’Q¨„;3gÎDÝú&Ù¹sç3Ï<ÓÍgÊz‚@šóföÿÛµ¿‹6žEtk¢[u{ŒÞ#ñ‰¸}1Œ™B/ cY–­¬¬LIéI8A`8N`8&JB|||ï>½CL¨òJ¥ÕbeŽeBÁ€?8ѳGF­ÕhÜn'P$ J…( J•R«Õ” •0¢ó³}ûv”/iÎn,2[ѵѾætÂȨfGn<‹@tNýÙK@‘øDÜv¢˜’š¢RkÍ÷?\LKËLINÖ¨’‚ çAÝ.—ËéV«µ˜$I‚H‘d\\\¯^Y’ÏãáFD‚ #õqq2š–Ñ´LŽž @ Íy ¤f‡üwôBMÔïV"­„С⳱Ü¢[м뷺¥QÛGÜXmöô CZZAJ—/Uþpñbfz†!.N’€çžjª«/_¾T[Sãv9^že$V—š’š”˜èóyík˜åH’Ä0à8RТ$±Ç *áòÞ{ïmذÁår8q•@ ÍyIM¢ KëFóo›Ø·ú‰OD÷Äl±$§jÒ=TjÚns]¾tùr¯Ê©=ÕjY˜»ÍzéâÅ çÏUWWû¼^¥RãñxÝnB®4F£Qày&ÄpaN&“S2’çÃþ HQχ=>?Ç ¨„[Ȇ V¬X1pà@T4g«t&Üàn@ÐL@Hj"mП76ù‰OD7Eå2yRb2NB]­åëò³gÏžMIJÊÎî ….\øöò•K.—Sà†s,ã÷…H‚ì‘šš™–®ÑhœN' ©•*•’İ?  çžx×UÙ|öܹªêA4juV¯^yƒR¯·ìä©êššP(¤×éò‡ËÌÈX÷Ɔ‰•Ëd³f<Þ-ëÁétæåå¡öˆ@ Hs¶P*ިΌΌášv ¼%Ým¢ =Š šîu'ß65ɶq8͉O=(ˆ®N௷º¶ÆhŒïÛ·/†–:뇘­VQà~øþ;£rûDÑn±UWÕ*(ebbRVVŸ8}|0Ä0$Q©RBØí }>QäI™LIÓ˜ ŠpÍÜÚÒcÇs²³ï,(P(`ðÔé3ûM™<Éãñìܵ{@nîÐ!ƒÕ*•Ûã)=~<3#cÞœ'£½ïþô³ô´´n*üE ÃPkD ¤9[(͘ øêy'h`q[©ÄŽ}\›ÚüZñˆ5ŸD×C’x¿×Ç„X…B¥+1 $«­5[­ö¬^½zgåöL2*d¸Õb–8L)ׄy$I¥RI’8`¢J«dyu˜c|^?Ã9Ž‘Ée´\Ɔy– b×jΟO} þZ£VägËV8^V–7h`Þ A‘[†øø)“&5HgEe¥ßïÏÍÉî~U Â_|a2™PkD ¤9oj'›¾¶+Œ¤&qô'?ž3Ä´]|¢GÑÕ¿‚ò} §da>LR„œ–‡yÞnsâMC ÎíðrŒ ×Æ'')† †‚EbFÊH‚ÇM‰ »Ýn³ð§P((’dClˆcy1¬ åMF*Š¢ßï?yúLJJ T×Ô¦$'¾ÿ×ëU)•½{g <˜$Éhû¯JJGÞy'Žãݯ òóó1 {ñÅQkD ¤9[¨"é¶yƒ^±‰:ˆ۫Ýf_O^i4íèN$&›Ü^»Ía¯³Ô‰¢h³ÙºZî IDAT]n'Ç1‚ÈÛlÖo¿ûÖQ[Ëýj•*ÞG+qœÇq\’€¤d$Á©4*§ÃåCAF¡P°g³XyQTÄiuZMãëWiÆéõ‘‘O†a®TTL?N«Õüþ£¥ÇŽ––Ž9²ÞË7gÏi5š´ž=ºe=zôí·ß~ë­·î»ï>Ô iΎ׬hs R‰$=͈O¢›‘Ú33óUµUa¡HÒív;lŽP(€cBm]¥¹¦J&a4EÅéu¼(á$IÉd€¼(‰aÃ’’sLØãöºœ¿Ïϲá@Ào®³ŽeèõZ­¾qŒóæ<)Š¢×ç;uútñáÓ&L (r̨Q*• t:ÝèQw¿÷Á‡õš“eÙ“§OýüºkÈd²_þò—6l@­@ æì¨Nvôt>$5ˆÎ÷uuõ©DÏ)¢;"‘Ù'Óf5ûüžšê¿ß§×ê&bëªkå„|ÌØqIÆD§Ãa¶˜¿ûár||¼J£")’" ÀÁjsÔTU^¹rÅåör ãóB¡ $á8†I"xÓ?÷8Žëuº»FŒxgÛv0Äb¤ð؉}z÷Öëõݸt:  seiÎëÓº‰µLT/6Ʊ¨o‹@´íil¯'è§Åš×Ž|6¥ùtà€Üääd’ |>ÿéòr“ÑÙýûß}çZ­Öï÷-=–™‘ñâr¹.]º<ýá_uïZÀqÇqQ»å‚U@šóuˆ£fë¡þ)ѵ@㜈î„Ûë–0#Àît¦÷è¡Q©\nˆbïaÃï8Èít›-f¥J£Öhi•JÄ0Ž8Ÿa™P(èõzl6›IÉX>È A$I*iZ¡Vª5Z–»fWçaC†œ*?sààAQ”Ô*UFzú䉠_ß¾,Ç}¶o¿ÏçS*•Y™™Ã‡ xùòhɰ¡Ce2Y·¯“ÉTZZZPP€d'@ Íy:~ÕŒôY™(wÔE Ä-A± ËÈd¤\¥"HIÉå´‚"II”´jUVfFIIY0ÄöÊê­ÑjqŠ2AŽcAŸÛãqØm^G¥TÈi™Às‰¢L.‹Óë(íð¸¢ãJNNJNNj2ƒ 4`@c÷û§üì6©ˆ¹sçþõ¯u8'Nœ@Í@ ælNQÆRŽ?lÖÏÍëÀ£<Dû¿Çiñd]4½ÑÅÑŠÈù(éºxš¢ô:]¤TBA’”ÛåÒj´¢(˜-µj­F­Uc¸ätÛ%IâÂ,ÃýA?Æ”*Z¡¤å2RQ¿bäæÃ¨„[ÈÔ©S§NŠÊ@ æ¼pÔÀ&@ •RI+”Jmˆ‹W+èd£Ñ¯–Ó„$†™E‘‰I&«ÍÁr¡`ÐǰŒÍnQ*AÈä¤Z­xF&'u‚–‹‚ðùÃ<Ã1L€ñÓ2‰ãÑO@ æ¼µB´M·h/”Ju\\< ÙÍö¬‚á½22¥–ËMñzIä2…?ÈèjkEIòûÝá0O B¡€(‰J•œ õI&Sœ^‡IË04MÊä¤ÇéÄHB^ÄET¸Ut³õñ­›JG#I‰@t9Z1\ƒ&Î#º †‘¾¿ðý×_SSYKá`Ðëeívû]Çããù0AbJ¥<.NŸ`Œ# Ìé´UUWÔÕUƒþÄDcB¢A¡Rà¡T«’S’{ôH¦hÊðø‚~ADçt.òVLË[1­ýFo$Øæ:th-äM›6=õÔS79_G0aBËz•ŽHL‡ÞŽ,X°`óæÍ¨=tïöp[s2<ƒö½D º$ <èÉEt;‚>(Â\vÇñÒR -ï—Õ›"èóú½ÞÚšJAäã´Qž „’$hµj‚Qä2Š d$Éïõñ}:Ýa‡H öpËÛÃí¨9:å}%#¢sà°Xd”¬ï>:¥Ênµ/-ó:½‰ Ï3¡ Bß>}i9i±Z*«ªÜNg˜ãâôºC\˜óþøã—_~ù…^xðÁ;s:‹ŠŠ žžÞãÚÚÚ×_½¤¤Äív÷ìÙsöìÙ“'On[¼—/_|øðóÏ?¿k×®6Ç #¯oºh¹Exçw{ì±ëýà>€Ó.€O,±GÙ?ø;ÀFÀ€þï§›ãÇ?tèP«4U×meeeeee_~ùå›o¾©V«Ÿ}öÙîЖ<pÀ ð)@EÃö€öB ] ’fÐôZD·ƒÂ$ž <®>½ûfôLõ8ív›Y¯Q'&šâ ñ€Ïaw„CA—Ýų¼ŠV³ ò3àZ½^¯×“‰MËí6Ï ‡ãÉb±2á0Ë]sVÊϧ>P­Q« ò‡¿³e+/+Ë40oРÈ-C|ü”I“ÀbµNš0A&£@­V öζí¨ÊZ‹Õï\¼{õ·ÖЉýFD»ó¢°úðŽO΀ûrî^0j:‰pu¢lô¤ÙÈu„¿î}}ß·%ýLéÿ|àé•>F¼¼(üçpá'çð¢0¾OÁÆ>JSòöÇ­\¹rÿþý¢(Μ93úÃ0eee;vì˜>}:˲r¹¼^<ýôÓ;vìðx<óæÍ{ôÑG@ÅÍ›7ïܹÓçó=zñâÅJå£{öìyýõ×Ífó Aƒ–,Y’’’Òî¥}þüùùóç·$_ëׯÿÕ¯~õÈ#DþÍËË{íµ×  ýûßÿ>xð Ü{ï½ .ŒŒí7—¯z¹ˆej®Üš¤¹x`ß¾}[·n½|ù²N§{òÉ'#C¦ â…žœYYYyùòå1cÆ\ÇîpÔu:ÀßbWãZ€å‘PÇü` ÀC?Þ¼ãŽ;6nÜØqO_§j‚HLLœ1cƤI“ºC{ø2ê:àU€äkîãè7@t_Ð6Bˆ.CŸ^‰†¸€×SW]I€¨U)„0ëv;ü¯ÛçþúëòC‡Ÿ9]îvxôÚ¸9ƒ† Éœ74oÀà¼wd÷ÏIJJé•™•ž–©ÑèAä8ÃHAívgÀù¦÷EÑëõ-)tú«kj)Š*|ÿƒ7ÞÜ´mGaéñã<Ï@fFÆñ'ü€(Šþ@àø‰²^™™¨ÊZËÊC;NV_X0jz_ã5ü6•î|ûøî'GüâÉ¿xûøîMÇv¶$´þ¦Ì£¦Ÿ¬¾°êÐŽØ–›Jw¾u|×oGþêO÷<þþ™ýë~Û~Æ f³¹°°°°°ðĉÑ·JJJrssSSSsrrJJJÜZ¿~ýîÝ»¿ú꫈ËöíÛOœ8±~ýú;w±nݺz㢢¢•+WÛ=5çu&ÖÖOÃûÑ ’ ÝBP¢ÇÑmèß·w¯Œ4Ž |}æÄ•ËßslPàY›Í|á¹ᄑàr¹(’R+5*…Z£Ô$%&÷ÎêÓ§w¿ää …*ÌK$!¯«³:õõ7ß\ð¸ý*•NA+A¤(y”ôI=Ç¸î ¯o|s[á»f³yÜ=c€a˜+Ç›5ãñû§üÌår--€Q#Gš-–-Û¶¿¾ñÍ-Û¶›-–»ïºUYk9Vù Lê7brÿ»¢Ýw=qŸÔoìú¦E3 ëíK*¾Žm Bß‚{z€½ßm¿wïÞ§Ÿ~Ú`0Æ… Fß*..Ž wŒ;¶Á4ÑgŸ}6---..níÚµ—>úè¹çžKIIÑjµóçÏ/*úi>öòåËÓÓÓišž6mÚ©S§b§§¬)ÚPþÍåËív7P#8±OHHøýïÿùçŸ_7_Í£ÜZïöíÛ—,Y’——§P(222žþùŽh¥n·ûË/¿|àZê ²¼ÓÒ `€Èpc€'* kIlÑ/npÖ[Ø"ÉÎÏÏ¿ï¾û<¸dÉ’îÓ"¼°`å5nhn-èzR“¹v)OD7 ðý^ÓQU]™`4iµ:AÜ^_u]µ.N?ò®»ÒS„ kµX‚Á F­Å)Âíõz½>–cQðW®\¶;ì<ÏÅÅÅk4ÚººšPˆINJNJJ …šðŸ7çIQ½>ߩӧ‹ž4aE‘cFR©T ÓéFºû½>5räƒM&Ó¤ ã E(:yú̃_ülÒDTk­ë½…| ¥î²bñ;¢Ý-~gKB«·w…¼±-#áüϬȿf¯#¶½ÍfKJJŠ\''ÿ4=NÅ#GŽÌ™3Fýæ›oŠ¢X?úÑx~¬ÙlŽÞ/§ÞòÂ… «W¯>þ¼×ëí¸ÒNHH°Z­iii×Í—^¯·Ùl©©© Bp8Ñö6›-v¾š#v¹5&F¼YYYÝJß}÷Ý|0öìßkÂW^˜ c] àHXv€¨}s,KBBÂuc«ÝÐÚ=r:O{¨Ï… V«uëÖ­Ë—/_½zu7ia€?¼ð @ßÛ[s2QV@ : —~¸T[[]UYÅó<æ)9•aÊ`XÎétÞŒ^i½RÒý.Ë2PÀårò’ä Ü^7Ë1‚ 8½®ÚÚ:† ê´’$|>·ßï3Äë’’T*Ë6=ÉÇq½Nw׈‘õ™†xC“fÕ55?úk™LjµzDþp´ž³ èhµ=àö±AQ’¢ÝMêø*·ÅÇ%I€Duü5ŠE’š<^µÞ^¯ÐÔ;ªdŠbyNNÊ„äwoj䪖¤Óh4šÍæHï¼®®®Þ½¼¼ÜétÞÿýõ._ýu^^^äºñ8UJJʦM›´Zm÷ŋϜ9sÙ²eÆëõÞsÏ=±ÓÓä@ÖuõFvvvyyy´Æh._Ÿþùã?Þ ƒÁm_¯ˆšËWsÄ.·Æ4oRRÒ¥K—𛇉a˜$I--l–eÿûßÿnÛ¶­uÞ(€>ÿèÓì€b€‡¯þûÀ?ÝòÈ#/½ôRyy9Ã0K—.½æÍ…ÉtäÈQo¤‰îÚµëî»ïÖëõ-²°ÀÀ|ð'€èC(1€zç·‹ø€Ç†N™•ÿã<½?Þ󨲢·ç¸ltÖÆ¡3_Úÿ]i^Jߣ¦×;>3næËû6ümÿÆç?[W÷¹Uð Ò®³‡vœÜ›Ÿ<»à¡Øéœ={öÊ•+~øaAfÍšU/Š‹‹£÷û;vìsÏ=éŽ7É´iÓà©§žª­­íÕ«×O<qñÅ_}õÕ?ýéO&“iþüù{öìéˆÒ7nÜ«¯¾zåÊ•ŒŒŒØùJMMݰaÃúõë7oÞìñxÒÒÒfÏž sçÎý׿þõðÃÀ˜1cæÎ;_14g«Ê-F¼z½~ùòå&2Y·ž ,]ºÔf³‰¢Ø¶õ®¢(nß¾}åÊ•-õ°àŸp=ø(¦ý/ì3*Ò^øiÓÚË—/Ÿ={vùòå-OmkóØyÚ\º'I2..nذa äbWm]mÑ«S]W+æp8À`0tå¯ñÖM•E's"Ý€úãRZð0£ÙôˆÎKäWxÙ²eÇKiuÚAw ìß¿jž©={°S[[cµZy–;úåQBÛ'£^§÷x½UUU^Ÿ/µgc¢‰å¸+W®|ñœÀHc™A`&“1)%ÉnµYí¶@0(IøŽÂ÷:( …Õ#¢²yóæS§NÅX)×h¯-n<𢢢O?ýtÅŠ7¿,X0xðàó öÐÍÚC7М-êMFï5‚4'Ñ=4gkd$;]sž(=®Ñª3ze2dذ¡I)É5µ5—®\!5)ùðÅ÷Ô(Ô9Ù9Z­®¢¢‚ sýûçÄ —ó»ï¿¯®®¤• Z­Ñ¨)ŠýŸßáp’%¶½ð]¤9DsÌœ9óé§ŸŽ±ÐÚÀæÖ"ˆ®¦6¯½@RÑ=À1,æ._¾”Ú#ÅãuÓj…Ýi¯¬ªt9œ¯71)©_¿ÞŒ?„a€ ú¡ Ëåóa¯ß³‚ ©×k Ç[]u­$I,ð8ú¹G ±Ø¼y3*Dǵô#„@ Ä­‡$I9%§d”(ˆ^Ÿ7t…ýî‡ï.^ºÈ†˜¤DÓàAwdõL««ª B¢J¥"Ä„<—/àg9$I.—8®V*1À|¯Ëî‚"Žã‚$‰~îqËèêûÖ¢ùrÄmÛC§où†´h÷ZDg'Ì…ù° QkAp:W®\©®ªæy>95¥¿þYYYÃóó””hR(ä*µR¥V‰¢(ða ™ŒÒëõ2™ ,èx½‘4­Œ”É)¹Z­Q«Ô¨„; Ûss·çæ6v·;öÉÔ©…yyMÞm’M›6=õÔS ›}:M·¢ÿÕ¥5g[ºšh!@tBh¹Bx³ÙLÈdŸW¥Qefe4(»¶\F3Á  '2™\&cBŒÏã•0L¥R¥õè!JPY] 2qqq˜$jTjµJÏœ,ã¹°Ç…=@t\ufóÙs窪kAШÕY½zå HQx¼Þ²“§ªkjB¡^§Ë>,3##;qâÒå+¡PH£V0`@nª²¶ñÈÙ³Mº{+*@“žÞÂpŠŠŠ Þûú.#EQ wß}÷¼yót:]_XX9·011ñÑGýÕ¯~Õ’Ø;´Ýdø»wï^·nÅb‘$éš»õ'FJ»•t¾t~üñÇ/¿üò /¼ðàƒv­'®Û*‡}.ÒÓÓsss‹ŠŠ¦L™r›hNhE—‰":3‰‰&Và–©¨ªŒOˆWh”:N§Õá8!ˆ"EÉp H’¢iZ.—ã8®‹‹ïÙ#M’0§ÃɯËÝ»W/)Ã1Iày.Ä8©Qk|€Óápz<Ñq•;ž“}gAB¡ƒ§NŸÙ hÊäIgç®Ýrs‡¬V©ÜOéñã™_= 1Ü7E­V{½Þ/¥dT¿˜ç˜#Z‹À0€á-]ôtèС‰'¶Ð8Ò¿Án·¿ÿþûÏ>ûìk¯½ÖÚ~öÙgï¿ÿþ+¯¼’••õÃ?,Y²D¯×·< 7“þóŸÿùψaØ57¤k{ؖΗÎâââ‘#Gw9ÍÙ^í¿”C;>ãÇ?tèP«4gW_ω@ nw‰D$¢{ TªHœ¢• ’ ‚ÁP(ÄÊd´F£•ËiŒ IÃA’DQÂ0L¯S«4/AŸßæÂ™™™*…R£Ñд’ó^¯W’$’ÀA}/χ£ãúùÔúöé­R©pרÕùÃkjjàxYYÞ Cß¡Ój ‚0ÄÇO™4 ._©3z”^§# ">.îÞ1cΟ¿€ª¬µDVr6^ÏíÒÜjÏÆœ?¾Á1×] FDbbâŒ3NŸ>Ã>¯X±b„ ãÇß±cG½Á‡~ø§?ýiÀ€ …bàÀüã?øàƒÈ­}ûöýæ7¿5jÔý÷ß¿sçÎèô@‹—¨…B¡W^ye„ &LXºt)Ãü´¿µágee9ΆkDL8Ž[¾|ù„ Æ·uëÖè[ Ô••-^¼øÄ‰,ËF7¹-[¶L™2eäÈ‘õ^DQ|óÍ7§NzÏ=÷,Y²$ ÖÛïٳ硇ºóÎ;çÎ[[[;=?üðÛo¿m±Xn<ýíÒþoU9tÎçâŽ;î8wî\«¼t]͉Æ+Ñ}ÀpŒ”Q ZŸ@`¤Ï믩®­«³ƒ Ž‘a6, ’$a’8Nh4ºpX°ÙìP.“Lýûö×ëãµ-˜×ãµ[mËò/ "†a‘ÕžEÑëõ-)MII€êšZŠ¢ ßÿà77mÛQXzü8Ïó€a ߀;œTe­å‘³g›œXíÞœMcìv»ÑhŒv)++‹=‹U³Ù¼nݺœœœö›7o®¬¬Ü¶mÛ{ï½wâĉz÷ï¿ÿ>7J0à»ï¾€ÂÂÂ7.Z´hß¾}kÖ¬)//ož²«ÄÎÑúõëív{aaáŽ;Ìfóo¼qomøÁ`Çñ¿ýío/^ìˆzÚ1Ü» 6l0›Í………………Ñõ%%%¹¹¹©©©999%%% n­_¿~÷îÝ_}õÕïM¶o?qâÄúõëwîÜIĺuëꋊŠV®\yðàÁ#F¼òÊ+±Ó³hÑ¢ªªª_ÿú×sæÌùøã}>_›Óß.íÿV•Cç|.ŒF£Ýno•—Ûen-Ú³è†Ï5I£Úˆnƒ\¡ Õ* “H™,È„x¯«³ž?÷­Z¡I1%IH.I8NàŽ·S”Àh2šLZ­V§Óƒ$q,çr8ÌuuN‡]xŽaÂá°BA“Míô°î ‘‹8½þçS†a®TTL?N«Õüþ£¥ÇŽ––Ž9²Wfæ¡#_Ž(ÈW«T^¯÷«’RžP•u!¢ÅObbb}·µIB — IDAT>ùä“Õ«W›L&xê©§¾øâ‹ú>«R©¬7S©T@ Ò·^ºtiDŽfdd<ÿüómKäÖ®]k0à÷¿ÿýï~÷» ´!üÿüç?“'OV*•üã·lÙ¢P(FŒqìØ±ö*ÌæÄs'ܦUìÝ»wÍš5‘ò_¸pááÇëo3ÆŽ[áÙgŸMMM€µk×F\>úè£Õ«WG^cÍŸ?ÿ±Ç[´hQäÖòåË#Ó¦MÛ¸qcìôäçççççÿùÏ.--Ý·oßÚµkóòòþù϶!ýíÒþoU9tÎç¢ ƒ¥h='¸T*š"è´Ä'$¨ÔJ†c•œ–‡Ãa«Åzår¥N­Ííß_NÑ8Ž &‰8†Q v»ûŒ¦é3gÎüõ¯]¼xqbbb'ÐôªÍf‹.ÿzwQ92gÎ=zô›o¾)Š"~uáqDSEc6›£×:Ö[^¸paõêÕçÏŸ÷z½­•7…#IRÒß^íÿV•Cç|.,KBBÂí 9ÛÒk¤Ñ¦µ謨5j’¢X^ÀqÂhL4™L—/]>ö܉ã'Ó{¤”GÓ4Ëp øC6ÔJ ‰“8à”Œ²ºÝuuuÁ`@¥T*år–cE¥"Ä…: NQMFŠã¸^§»kĈw¶mC¼¡é¾IŽ(ÈQù÷ô™ò©©¨Ên-ÙÙÙååå-Ôœ‚HNNž7oÞäÉ“c˜™L¦ÚÚÚŒŒ ¨«««wïÝ»÷Ù³g "ÿž=ûÿÙ»ó𨪻qàç.sg½3“Ù';Ù !€VAi”‚ ò{«¾Ö·jxyjµnÕÇ·}[i+Š­€—Vú–EÔnÖÄR•M–;I&Édö}æÎÝïï‘4„€„²$áûyxx&gNÎ9÷œ›;÷;÷žs›ªªªrçåÍÍ͹û{ E9Ÿ«"V«Õï÷ç¶ÈçóuÑöµ|Ç@IIÉ“O>ùàƒ>þøã}ZéäüÅQÍÙÒ¿ñ»€~Ân·wïÿ®ôÆÆÆh4zë­·v¥8p k.ñ™#›ŸŸÿÖ[oÆéO?ýô<°xñbš¦“Éä7ÞxîöìÚµëÓO?ݲeKYYÙ·¿ýíÇœ¦é hÿÅÚÿ¯T?ôÏ¿‹ýû÷WWW÷éW` !àÊ1™J&RII–YžÇ ÂåtÙíöT"õÅçÛŽ=ÞÑÒ D†Sdij¼È+*RMQEÁ²ÖÛá;xà`GG»,+E ‚(MÓF£ÖéUªÓ¾bþà£[=Žç%IŠÇÛwîrØí¡êaC7oÝ‹Å$IJ$ÿüü‹!¥¥¡ ?Í%&“É=ûöí?p`LÝh²+ë†nظqcŸ~E–åp8¼jÕªÊs®9ýôÓn¸¡O¿÷ÖW^§¿“TQ#m³Ûh­")»ÃYS-«027î?`7[‘(ó'K A¨(µF¥R“¤JQ°tšñv´ýY–4•,jµÚh¤õ: Ã2YQO?ã3zô¾Æý›¶l‘eÅ ×—–”L¿¹!4´ªŠãùõ?M¥R:®|ȱcêBU•>ýG2™Ôj4…·Ïže:ãË{ðº/H›{}žËíLô׿þukkkî‚ êvý-÷¢{À“K!I2//o̘1¹ÓÓ³åà–.]úÝï~!4oÞ¼®ë™3gÆãñgžy&¸\®{î¹'w½èî»ï6›Í/¼ð‚Çã¡i:wóa—GydÑ¢E¡PH–åsÇ`óçÏ饗îºë.„Д)SæÏŸŸKïkù?úÑ–/_þÐCɲ|ýõ×Ï;÷õ×__¾|9BÝž‘{ÑoŸÒy%ÚùÐC½üòËwÝu—$Ißÿþ÷»Æ}ëÖ­Ý×¹™:uêÿüÏÿä¦öêî»ïF=úè£eee>ø`.ý¹çžûõ¯ýãÿØáp<üðÃ6l8w{Þyç‹Òþ‹µÿ_©~è‡---MMM]³RÏw§ŽD"¡ÜÌÔãgdÁ½µ 2ôG S:A?’û^¼xqG§_«ÕWT5šLV«Í¨7×z²ùËÏ¿È&Så%CœVIª8ŽkïèHe2ùùîü‚’$ÂáP›§5 ªT¤"‰Š"›hº¨¨ •L#!_8œ¥Õï½}‰6A«ÕÂ8^+W®Ü·oß9f¦ýû‚Áàƒ>øÁ\ô’ûÕTÆ~Õ˜ Þ„^¶tpe÷ÿýwñÈ#\{íµ<ð@ŸJ»Z®s¢µ J°t-4„ᤊ T<ÇË’L¸"‰Ë(Š`¢µ!o{ÐßIʈ¦iŠRÄ’ ­—){Ú=áHXÁdŒÄ„i(µÕf¡Æl6#pB&ÍdN>'xྞö§Ÿüä'sçεX,¯¿þúÔ©S/Eý*‚¨ \æý@ÿ]\Ø÷\1æ„kœP«µ†gY–e³˦b‘ÎŽ¶T"^]]nÔi¢¾H,Â)¿   ¨ÈôóŸÊÄ}_›¯Í²y&Z£× zm4h†aÂd„0‚D¢ Î_îiõ‚ Lžm4F"Žev‡5ϪÓê%EE #HÃXIb8–å¹îuùüþ¦C‡Ú;¼’$ÑCyYÙ¨‘#T*ÕŠ7ÞìÑ*5E}ÿþûB‡ihlL¥R4M_;jTõ°¡0d&v=G æT`þƒö¯–®ƒ‚Û툄ÃL† G¢m¢×ë´Q­Ñ‰’’Ͳ-O§ß'Š¥¡b‰Çsv‡­ ?Ÿ¢(‘µÎH›5Z­ŠTI<Ï Ëñ&˰٠“áx¾{];w}US]=qüx­V›a˜} û?Ý´yÆô[Ì›Û=Û‡¯/).FlnÙ³oß´§Ú¬ÖP8¼yËgzÈ©ÇB‚ó'Ë2†ÁEgÀUP­½ð°NIÝUx‚èoÔi0è,yFCét* §“iQ”1 O1Ù@(ì 3,‹\”¤X†ìBκpÇqY–¡+W×™ÚÕ°‘°h- 7ð%ÐH2"UjFʰ¢â÷f“(‰"ËfO?Ò|ü˜Ël6¨5¢ ‰‚„4HQP»×ÛÜÒ¬×é Ôh¸Ýë=Ò| ñ’@›®|—3ß%#„p$ˆ§M¿3zô¾Æý›¶l‘eÅ ×—–”L¿ùëk¿Ü¾cL]][gˈp»eëÖT:M cF†¥\0‡Ã±sçÎñãÇçÖgˆ9p9´¶zT*õЪ*§ËͱB4ÄÂ*Ь­©N%SŸÿó3¡Z^%‰ŠJ¥Æpax8ï †lNd'P(ü⫱dœ¶æ•Ú¬yV‹ÅnÁU¤Éd4™M¼Àu¯Ëív¹Ý®^›qëŒo÷š^S]]S] Ãôï›?þÏþóH$²{÷nè ÄœW ¸ÆàŠËdXO[‡Ýî,--™¡H4‰˜óÌ£¯YUYµiãææ“Í#˜Œfœ $Å3\Cmy„VŒÅ¼oJ v«Õšg4ѽ^¥¥ K1éL6ÓÑÑ=ÜOÌž={öìÙЈ9û!¸ÿ ГæôcšÝé&IU*D%•fZZZ²Ù¬Ãa+..¬V% ÒáÆ£mmíFc*¿°€¶˜9Y6Z­nµJÆ”,Çà:MéÐr’"õz½V«¦(•BÂ:½A äóC€˜þø“ÔÀÌm0 iu’$3™l8Kg˜d:c6ÑE……6KÏek†W#8zè„$+2†j5ÏsjšÖàr†Ëò"FèÔd' j mD±ÃçÃŽ…’©›…¯e@Ìy.ÿÖEN8 œ#V…Û(@?‘L& #FpÁpˆá8M»Ýù‹)ˆc9³É^5´Ç©p$†D$gE>Í2h$‘Ž Š„p…x£ž&Õ”ŒP–çÒ™ c:½N¥à™xzø*QWW·gÏžK—ÿ"¶3÷âŠÔÞŸÄœ¸$ü¾³Õjq8¢©X’I™í6›ÓI¨¨L–w;iLFVGž‚áªvM‡¯³³½“…X:î t&™”J­¢´A¯uÚm)©dRä›Åª¡Ô*œˆ…Â­Ò èá«D_£¦+eõŸ/×’ºÓ€˜T2©¸„Da¤ÎíO„,y6gIqAé½JÃ2’Aƒ!Báe>–Žxm¢,vF¾ OKJŠÝ„Š4šÎ$S‡Írn‡³´¤D«Öž8vÜÓì‰'ÝëòùýM‡µwx%I¢ †ò²²Q#G¨Tªo¼Ù£UjŠúþý÷!„ºÞZ0o. ÖÀÒJ©T*›Ívýõ×/X°Àd2]@QëÖ­[»vm p:÷Þ{ïwÞy>µ_ÒØ²×ò?üðÃ+VEQN{;õB£]Äœ¸˜’©¸€Ëœ_&õj­^«Ñk ŠT©5jžÉrÁpXBr‡¿£¹õäÉÖ™l&–LŠh±åä»tz}G{{{k+Ëdq ·Òf³Þ$0<—`#þP,…ӞϹs×W5ÕÕÇ×jµ†Ù×°ÿÓM›gL¿¥G<ùáÇëKŠ‹»‡šg¥`@ÈE/’$…Ãá÷Þ{ïÙgŸ}õÕWûZÈúõëß{ï½çŸ¾¼¼üĉ?ûÙÏÌfóÍ7ßÜ·÷Å_\¾|ùˆ#0 ;í åôÈ1'ô ,#4!–ç˜$¯òùôF£¢È†ñAKEFÝÖî‰Å#,Ï$ARd^žÙ`¢m«,I‘PˆI¦´Eb8“Ê„ƒÁT4iÐéÕ$•ˆÄ0Q1hôÝëº}ö¬®×´Á0~ÜØ?®ZÝ£=ž¶¶t:=¼žÉ9`|ã¤D‚ œNçý÷ßË-·œ#¿ K—.ýä“OEyðÁ—,Y’Ëðç?ÿùÇ?þqmm-BhĈO=õÔÊ•+s1çÆW¯^ÝÒÒb2™æÎ{Ûm·u/ÿ_WzEEESSS×MMMUUU¹¸´¹¹ùl¥a¦(çµJ¬Õjõûý]õÚl¶®¸·Oåã8BO>ùd xüñÇg̘q»±®7—a»€˜³ßaOýµVg6[t­È²j\å¶Ø+K† ).5Òt"e!“ÍD¢aO[ë‘#GÂá°ÓîºöškGÖÖæÍñp,‰« u&™9zøØÉc' ÕV¯,/·Z­e%C†VUu¯ëƒ>nõx8ž—$)Olß¹Ëa·çÞŠÅbÍÍ-cáA…ƒ‘,ËápxÕªU•••çÈ6sæÌ—^z)D£ÑW^y¥+}Μ9K–,ijjÊf³MMM/¾øâœ9sB÷ÜsÏÂ… Y–õx<‹-êÁ~ñŲ,có¦M›¶téÒH$‰D–.]zÓM7åÒûZ~}}ýÂ… =Çq&LhjjšÚ§òY–]¾|ùÆeY¾þúëÝnwSSÓòåË:ã))Jϼ³%/Öv!„’Éä7ÞXPPð÷¿ÿvx1'Äœˆ9è[Ìy$Ԧ𢎤†–•¨©¥i‡”8“>ÖÖÅÄtÖ@ªó]î‚‚Žã³Ù,DzÏë4“É$p|2ßöÅ—Ù S]5tL]Íb…Cˇã‘ã­Í‹^~émÄœƒX0|ðÁ?øàƒK!÷‡EqúUcÎáwÞyùå—ÿð‡? :vN0° Î5„4p `@‰Çâ6£9Ïœg·:L4­Öh’éL2“ÎpY5†³©4Ÿfè<Êa³Õ «a˜L4õ´zB>š$U™J$[›[2©tIqqMMÓîe‰¢(†ee ²= ÎßO~ò“¹sçZ,–×_}êÔ©—¢Š~Ý ”Å`ßÿýgžyN1'.D,uš,n‡Óh4 ¼¨(ÙL& …шL`n›C2ðvsž5/O¯ÕX̦ꪡ&‹DñD<ƒ±hÔf³ 6´ ?_AŠ(òI$™4' œ$@ƒó7qâÄùóç ‚0yòä @‡ôk×®…Ns^tp‘pÙhà˜®¬x4ÒFªò펚aÃIŽÆâ> Ã×™ÌdÆL7çŽÛ¹ ÓÞÒÂ0L(à7çåÙ,–ŠòòD,qôÈÑH(ÜÞæ•DÑd7 4©¦R$„S©Ul†cXVôÁÌ™3gΜ ý¸bÎ+Z½NŸL%j2™ÌZµ–ç¸Lš‘DÉd f‹WY.>•ÂD–‹…£8Ž[Íyz­®-“Ñët† ð“--ÁHH§Ó´š$9Yˆ¦ÑTzøjsž+â\¢…sþfç^\mó<ûÛ@p•Äœã‚Ã.%`àk&0èt:“Ñh±Úýá"cŽkTj‡ÓUZR:røHBÆ(tzÎh”$G˜AoH&’¡`8‹iã5£®a96…#¡h[T¥¡Ü.—N«îðw†ã1žÆ ΢Æ9ý§I¹–À³IÄ1'\fp{-¸’LF£ÅfSëõ)Že2¬†¢ \FW~~iI‰A«Ã$ S(F›UkÒiÇ0ŠP%b‰P ¨HraaaAa!†!–ç‚Á€Ïï …ƒGŽS©Œ"tF½?í)>¿¿éСö¯$I´ÁP^V6jä•JÕã(!5E}ÿþû::¼M}>¿,Ë4MW”•]3j$IÂ)ÄÀÐ2©T*›Ívýõ×/X°Àd2]XiûÛß~ñ‹_üïÿþïm·ÝÖÏ·úÌØõÃ?\±bE På´w»ž¡¢ô—ö”~bN`À°ÚhP² IDAT¬ZÚ€’ H†‰¢,"EFH¥dŸ?Àd’TáI‚ˆ!¤V«Ó©ôÆFoG‡F£É˳Ȓ‰D‘p<‘D‘6Ò…ÅÅ…­Vk’Èf™îuÝ>{VUe…^¯Çqœ6Æëõz{´ÇÓÖ–N§‡×T#„î¸mö°¡C Žã4M_7a¢×Û CÖßð<ÿ /Ô××O›6mõêÕgf ÂétÞÿý ¡ºSzdaÉ’%õõõßúÖ·Þ~ûíîX–ݳgÏÓO?½{÷nŽãºÒëêêV­Z5cÆŒI“&uU-ËòïÿûÙ³gßxã?ûÙÏæ_;ᆠî¸ãŽÜê¸ß°/e³Ù矾¾¾¾¾¾~Ñ¢E,û¯£ûÆ¿÷½ïMž<ùÖ[o}ÿý÷»“kó™X^^F{œýo¼.C?÷:ô@Ì ç‡Ô âM0†L6Øá ´uˆvꄉ3ëo¶Mí-­mmE‰‚ # 'U²‚¢ÑXcãÁÆÆý¼ÀÛlVÇN6Ÿðû}©LšT‘¢(úþNo‡Ín½fL]~AA"šl>ÖÜk¥²,'“Éí;væçç÷Hß¶cçu'âx/ç ž6O¾ÛCÖß¼ùæ›~¿ݺuëÖ­Û½{÷™$Iòûý+V¬¨©©AíÙ³§×™“+W®lkk[³fÍ»ï¾Û£œ;v >¼   ¦¦fÇŽ=Þzíµ×>üðÃmÛ¶åRÖ®]»{÷î×^{íý÷ß'bÅŠ]™7oÞüòË/oÙ²e„ Ï?ÿü¹·ëµ×^ ‡ÃëÖ­{ûí·ý~ÿo¼‘K_·nÝï~÷»'žxbãÆ¯¼òJccc.½k»öœ’KgÇñ_þò—'Ož¼ý_×› ¯+ÒÏ\Ú³³~Ùª‹³€:¿„ºNNaW=˜Ò ®.–P±¼Ù@׺Šâ'ÚK‡ ]UÍ"ÛþùO›É¤R‘ťŒ¢(®Öjh“‘øòª ƒÁpäȧE­ÕV×6 ÃÁD*™å=mˆEâ‘@D«PgÖØ5{3Ïl¾}ö¬îol:d¤éâ¢Â3ëdsó—Û·ß>k6 YóÉ'Ÿ¼òÊ+V«!ôØc}þùçÝá®×N§³+lëÕG}´lÙ2‡ÃzôÑG?ûì³®·¶nÝ:eÊ„ÐÔ©S»^ç<û쳡ßþö·¹”¿üå/Ë–-Ë}ñðÃÿ×ý×O<‘{ë…^Ƚ¸ûî»÷»ß{»6mÚôÛßþ6·]?þøøÃGy$k-Z´høðá¡ÒÒÒŸþô§ç.gùòåÓ§O×étO=õÔªU«´Zí„ víÚu±ú¿¯Kc¼.C?ùbNè[˜ØD` C² ÒZ½Ž¤48É'3f½¡ºj¨Àq‡qçç[VŠ¢0œàEÙ”gÉ/,È/(ˆÅ¢L6#œF«ŽÇ¢¢,e¹,¥Ri4êh,²,Çðytžõs.˜7W–åd*µ¯¡aëçŸßR_ÿuôËq{öÝ>kVü²,ïØõÕÉææ™Ó¿m6›`Èú›P(är}}ýÙívŸ`H’ W¯^ý /,[¶ìlåƒÁ®_ï*0·|ñÅóæÍCÝpà ¿ÿýïeYîºÞãR9BÈï÷wŸ‹Ø•óÈ‘#Ë–-;|øp2™<ŸíŠD"Ý·+ u•_^^~þý³aÆõë×k4šýû÷ÿüç?úé§Ng?¯+ÕÏ@Ì r‘d<“bt´1žNšó¬±D\­Öä»óI’lnnþtÃ'5U]]C¨HÇ ’pº\F£1™ˆë´š¢¢"£ÑHÓt*d2L2•ȰYAÕjµÕbµÒÖh(Ük¥8Ž›M¦ë&Løãšµ]‰»vﮬ¨0›ÍÝs&’ÉlÚ¬V«¿3ç¾Õéìv»ßï/..Fù|¾33áv»,X0}úôs”ãp8:;;KKK{”ÓØØFo½õÖ®”Œ5*÷úÌI’ùùùo½õ–Ñhì‘þôÓO?ðÀ‹/¦i:™LÞxãçÞ.«ÕÚ}»l6[W<ÜÜÜœ»OøL†)ŠÒ½U8Ž’’’'Ÿ|òÁ|üñÇg̘qû¿×;iÏq9ñlãu¥ú€KjPÍçìZ8$÷axž‰šSÿ€+%ÏíRѺ@2ͤ9$‰8’0¤§ å#ªkÙL¶é@SsóIŽgõ-I8ŽË²„ã¸Õb6tèˆ#Š zC2ïh£´Þà´;‹ mV+E©»×õÁG·z<ÏK’'¶ïÜå°ÛsoÅb±ææ–±§Ÿ=;~üOùkIqñ­3¾ g¿5}úô¥K—F£Ñp8¼téÒ33Ȳ‡W­ZUYYyŽrfΜùÒK/h4úÊ+¯t¥oݺuÞ¼y]“$zè¡­[·ž£œ9sæ,\¸°££ƒçùÆÆÆÇ{ìë³5–µX,¦³³sñâÅ߸]Ó¦M[ºti$‰D"K—.½é¦›ré÷ÜsÏÂ… Y–õx<‹-ê9ñŲü¯§Õ××/\¸Ðãñp7a„¦¦¦É“'_ÄþßÓ› ¯ËÓϰ†€˜þ-RÃÂ2B` ©3ºfô5%^ qѨ3Ò*5¥Õêj‡Ÿ1c† òGŽ ‡C:ަõŠ"‹‚@à¸Ùd.*(,*,$ ’Ig¢áh:™Öªµe%CŠ ŠmA’’$v¯kÌèчŽY½ví[ÿ÷ÇõŸ|¢¦¨é7}cí—ÛwŒ©«£¨ÓîÅÝ´å3žç¿Ú³gÅovýãyF­_y衇œNç]wÝuçwŽ=úÌcâĉ÷Þ{¯×ëÍ…g=ÖwíÊüÀ”””|÷»ß½óÎ;ÇŽKDW,Ô}báÔ©S»Oõ<ÓÝwß=zôèG}tÊ”)‹/žuêníçž{î•W^™øà|pÙjì ûÃ"7ýª1Ñ;ï¼óòË/ÿá:t(ìäàò€ùœÀ•·{ÏުʪaÕ5‘PD­VËŠ‚“$E©EOQ*.ì­%UX2•EAR(Z‡”D"áñxÖ¯_ßÑÑ¡ÕêFŒ5rĨÒÒ!’$eÓ ¦AñX<Cƒó÷“Ÿüdîܹ‹åõ×_Ÿ:uê嬺_Ewƒuq×÷ßÿ™gž€@Ì \]d^èló"«ÕêT2mPét¦`'EE¦µZ§Û©£µz½ŽeYF“e2_àÈá#»¿úªéàAÚ@—WUTZó¬<+ð"¯"U,Ë3i&™‚…+ALœ8qþüù‚ Lžzä(………UUà ò Ô*“É(Š"‰rÀç?Ù|2Cƒó7sæÌ™3gB? æü—®iœš3RW§Ü2B0¯ \2­Ò#A}'=yjãðáÃu”F䊢ò].…Àe„’Äq<“aÒ©”¯­óèÑ£'OœôùüŠ¢”–––WTØmV’ dY!0\’%†ÉäVûdYø`¼òÆŽk6›çÎ{çwBo æ¼²ñ#œ#®pÄ Ç"pù%aDsjJ‹XaÛæÏÔ!²¼(+„Š4˜Œ‰t’ iQä²ÙlnçÁ†ƒY†a2 I’.—Ëér™Íf $©ÓëñD"‘d9–$U*J=|Åíܹsß¾}Ï<ó Äœˆ9p¹Ù tžÙJâ*5†§3ÌáÂáH~q±ÃíÚñÕÎÖ6Û¨áà ZÊïë<~ôXKK‹QKÁÎNŽá…Z­–¢T#MÓFŽB±H§¯3 3YF9ýñ>¿¿éСö¯$I´ÁP^V6jä•Jµâ7{´JMQß¿ÿ¾³å‡QëÇGF¡+sàr‹†"JS4¤bhE¥ÅaO¤S‘dR–Qä³ Ç²‘ÍÈ< ø#‘(A%ùy&“)™Hi4’TÉHÁœR«%EÇ£áp¨µµ%ô§RIJC9œŽîuíÜõUMuõÄñãµZm†aö5ìÿtÓæÓoY0on÷l~¼¾¤¸øùaÔú Ã0 ÃdYÆqx@:à*‡<Àà”›Ò ý –eXŽ#)Ò@ë{mmíЪJJ­ Û¬Öh4ÖÞÞÁóbaaQUEeŠaŽ?ÇÕ ¥¦¢±h2–Œáˆç¹X,ІÒL#‰<«Åf·u¯ëöÙ³ª*+ôz=Žã´Á0~ÜX¯×Û£=ž¶¶t:=¼¦ú<óƒóäp8¶lÙ"Itàê×9€+OÀå“ìø,N»Œ+V‡Íâr:LÇNœÈ¦ÒQ”ΠՕWUT©ÕªýûD#^ŸIgÚÛÛyQˆÆã©LÚæ° ¢І“LR¥Qåº\®p¨÷ukeYN§Ó{öççç÷Hß¶c礉{\Ž;[~pþ~øá§Ÿ~ZQ”ÁúìGèç1çÅY´«0ààZ*žM·‡|¥|¥L` Ž ´ÞåtD£‘“'›[ŽG ^U5¬²¼¬° ˆã²%%¥………*’lkmmmóÄqQ–1§â,χ#‘h¬³³3†Â‘“'Nv¯ëƒ>Q;Üív“‘J¥v{î­X,ÖÜÜòŸwÝyžùAŸäV¬Å0 º1çÃv >áüÀ€ü,K²%ÅÅt¡1޵·zc±¨À f£Ñ=Äev:†TÅ‘ÒémO¦’Y&C‘¤V¥&e\%LB®æd±ù¤çpÓQ6Ãå—T• Óºš²š|[~GÀDz\÷ºÆŒ½¯qÿ¦-[dY1èõ¥%%ÓoþúFÙ/·ïSW×ãÎÏsä} 8·oßîp8 +s^ÁÈbEÀE; ôx ÇÐÏ)‚,s2s<ÃfÒŒÈKzƒÁærY\N^‘³¢PTà E‘$œÀ0!EYC8EP˜‚µµ¶7: …LyæÒâ²|WA:$1’ÄHN—gµt¯Ëív¹Ý®^›qëŒoŸ™xŽüàü7Îjµþà?€®@Ì Á2Bàrãx:LÄ㛥Ô:»Áj0t:-DZ<ÏGãÑÂB§Å–' A`ER*†)$I`žÉ¤Û;ÚÛÛÛ5zÝi·XóH’@e˜t2gÙ,Âèá+n÷îÝÐ ˆ9¯.ÝïÈ®,Qá“é¸Ä‹¢(é «Õ¬¦(^à‰˜¬È±xD’µZ%H‚$K´Q¯¦Ô8" gâY¯ÏŽeLt¸N·ƒ¤ˆd&Îò Ïfc‰h"›ŠFÃÐà æ€‹&÷]‹"5¦yƒ ‘ˆŠ¢„a¸V«e˜Ëéh£žˆ` ÓÛé¥HT^”_T˜Oâ¸F£Æd…Íf)%ËJ0ÐÙx¨¡¡iŸÍé´¹¬´Å ãæ91I„·kõ¶µ{;¡‡\)øÀm:{êŸæÔ?X@À@9S Ah£¡¨¸PPO[k2™0›Œ…ùBÇ:zôp<ÅIœTS ›•‘Œ‘DgÀ×p áàá¦x*S+² —0A&•D&áõ{Û¼og÷Öž‡±cÇÖ×׿ûî»Ðpqõ“ëœ0i ÀURSv›­¨¨¸´´$O¶µ¶ƒ> )FƒaDM§ÍÓÞÖîtØ :ƒ™6K²¬VS©T²Õ㉧’%eCÌN›ÍåP0”ʦEÌrÌá::Ú“édaq¡ÙlþF;wîÜ·oß3Ïzôèh4 {#@Ìù¯“Á+øëÀEd³ÚôÇqYVŒ´1o˜™ÖÒG ùƒV“­¤¸´ÃÛ‘ˆ§2™,†jµ.à e˜¬Vg0ZÌV‡µÕç EÃ,Ïf²™t&N¥HeµÛª*‡—¤™îuíÜõUMuõÄñãµZm†aö5ìÿtÓæÓoéI~øñú’ââ®eYþô›®½æšmÛw ÖQÀ0 Ã0Y–q‡}.–Á0ŸzõõdoRÊp¨ý]^žÕ Ó¸JÄT2¥Óèk‡Q;R«Ñû¼#mÒëiID'"D¨Õ:’T;]ùCÊÊ4§½3™Êøa¿?†£Ñ¸,+CÊ+ÆŒ7zô—« u¯ëöÙ³ª*+ôz=Žã´Á0~ÜX¯×Û£=ž¶¶t:=¼¦ú_‘êW_i4šQ#F îp8[¶l‘$ öI¸XàÞZàʳåYqçy!O˼Œ$¬¸°døð‘ZʰáÃõ;wì.,)2›m¦Â0‚gY ']N›(ËÇŽŸ<|èè¶];:CAJ£**-.(t’n6ÊJ‡H‚xìȉCMG{­T–åt:½·a~~~ôm;vNš8±ër_{Glj“Íwþ¿9ƒ~ ~øá§Ÿ~ZQ”={öÀn ƒ&æ„éR®vÇ«ªªÒ”"Êl–C2–ˆ%4jMIÉÿ¼÷ÞO>Ù¨ÕèÍæ<½Á€cE©2i&•öB¡½ûvïÛ+ØÄ‰fËeEÓiµáø‘^¯·³ÃŸN1gÖØ5{3Ïl¾}ö¬îol:d¤éâ¢ÂÜ ÃlÞòYý·¦©ÕêA?+W®œ?þ}÷Ýû$ ¦˜.¹Ü͵}ÿ~ –—Éþ={e^(//×i´L2 Õ*µ^§çã…¦LD^Q¤l–åy ßïonnéèôFSI·Û=¤ªRF’ ‰Š,k(µ†¢¾°§¹…Àp‡Õ¡½<+eÁ¼¹²,'S©} [?ÿü–úú\:Çq{öÝ>ë_Qè?6o^S“ïv_ áñx¾óïPû$@Ì ç¨Ó ‘Eðü^бéÌáÓñøu“®—Ñïó«)µV£SQjQ–JKJEŠ„ƒ¢ÀG#‘T*±¿¡¡¹¥%‘N™m¶¡C‡åvú;…LŠg¹l–y^â9£ŽvØí²Œ¢áp¯•â8n6™®›0ákÖv%îÚ½»²¢Âl6w¥x;;½_u»×tÅoÊ¥kB’$™L&Ø!bN„θîÀЬN( LyF:™H?rÄiµYíN„í©tÆæpªµºX2n³˜4Z*“N:tÐÓÒzäè!„aF#m6IÇb<Ï <ŸŒÇC¡"J%Å…ùù¢(·µ·3™Óî­ýà£GÔw»Ý$A¤R醯F‡Ýž{+‹57·üç]§= ²Gx9ˆÎÜŠµ†Á s"ÔmÅZ4ç7È‚þÏ ÑಜI§¿ü|ë¤É7”UTúC‘fO«Åf/R‰ó6EâÑh<óy;U*¼¤´Ìœgay>àïTpLBr<™ˆDÂÏÛò,U•UyFãÞ={›Oœ$±{]cFÞ׸Ó–-²¬ôúÒ’’é7}cí—ÛwŒ©«»:ï,•eyûöí‡öFd1'œ.Ç7 ŸËfÒ&ƒÞe³ø‚Û¿t8ÕÕU:¯÷èÉfSD‘kÜÏëÕ”A«5M7M›b·¹%ED)‰œhiΰÌñ':::vûèQ×:Œ$°¶“-'Õ¨HçÒîu¹Ý.·ÛÕk3nñíolê`½È9nÜ8«ÕúƒüöFd1'ôsp•\jQ˜ï*¯,7éõŸüã³­›k¢áu£‡Ž¨éðÚ<ÍGÑص#GŽyÝä)SœÚ¾mÛÑcÇÉTšÉDâ‰t"®¦TùNgQA¾%Ï 2©¤Ýb1Û,QûÍvïÞ sÀí`!Я±YVeƒÞPRXò­iß:|üX,9vôȰÚZŠÂ¼Þ6çœ.weÕ°ºqãµZ]*–ä²L( †BœÀGIL– œKžI’„ “1ùÅEZÚ ÈRç±cÐà æü÷>ªa!ÏÉÉÃ2¢Ñ`¾vdžÍf?Úr26ìù £HLQÆŽwíˆkÆÖ±Ù\"Çù:ým^Oss‡×+ɲÍá>´JB(Ë0Á`P«×;œNK¾+- ±@0#pÐî|à6]sê0Ð1¬‰&:½Áx|èH8f3 “J%Â-¥6 ’(Ã!oÀϦÓI§£™4¡‚§M^*uuu¥œíÛ·×××÷ZÚ[o½õè£^åýüƒïî½L5a—«ýmudX­yg.ÖqéÚ™sæ[Wö:ç…L‘‚åj}¥9ýè@?ÄÉJ$™<áiÍ;d¯ʲ\ÖïóGÂa>Ëéõ‹Ñèrº4jm:È¢ˆdiûöí~¿?ßí®¬¨ˆÇcûö;|xXm­N« F"GÇ('ˆpX”$N=|‰ìéöØÒÇŠ+~õ«_7®Gz6›]½zõÊ•+¯ò~~uÍhh'€ãÌe>.]ĦÂ|NÀUy’¶Û”ξ|oËKÎQ”ŸJÄcÙÌc‡#é8äyž+È/6tX<okö|µkg:•QSê,Ãd3éãÇO»iê¬Y·||ôÑöÛÛÛÚ(N‘•l*s¸é0Ë 8‰Û¬Ö4{Ú½µ>¿¿éСö¯$I´ÁP^V6jä•Jµâ7{´JMQß¿ÿ¾3ÓëÒµ—A]]]¯çd---×^{í™é›7o®­­-))9-CH9õwËú B!ô8Bç³ï™…\˜¯œƒûoÿ¾ DZÿ|°¸f”±ßß@içå÷«¦K~~tÎ=…eUú>7þÒlB×µD•Je³Ù®¿þú ˜L¦ (jݺuk×® N§óÞ{ï½óÎ;/ø8Ö»×Z2(bN˜Ì ` +RœJ˜DQ`e1!Y*tŒ}íÐÊŠcGŽþc˦¶VŠÒh4_gggG»JM–W–[RM9óóÿã®»ìû?¿ÜÆðœË¯1Ð_íÛ{ìÄI³Å¢(J&™ì^×Î]_ÕTWO?^«Õff_ÃþO7mž1ý–‘䇯/).† óò`F¥R™þÏþóæ›o>¯"Ö ô[„ÞF¨¡݇ ¡»Ææ¯ý}ÛC”!¤¼õJë/—ÕB;Aó­™Î|˜WUÖš”‹ú$I ‡Ãï½÷Þ³Ï>ûꫯöµõë׿÷Þ{Ï?ÿ|yyù‰'~ö³Ÿ™Íæó=æœ?!ô+„V äùœÀ ¡¡u·S¥Ó$Y&‹Jnò+¿– IDATs8‡”–U”UŒ>²¶ºCèÈ‘¦“'h혱u÷?pß5£¯Å1ĤRŠ$i(êšk®7vlIQ±¢(á@0›a4”:Ž´¶´&©îuÝ>{VUe…^¯Çqœ6Æëõz{´ÇÓÖ–N§‡×T_=CPWW·fÍšiÓ¦Õ×׿øâ‹<ÏwkÕªU3f̘4iÒêÕ«»{¹TWW·iÓ¦9sæLœ8ñÞ{ï=zôh÷ügþbô¥>|xÔ¨Q絯#´¡ñ隀Ð2„Vœzë„Æ!dD¨¡·N%b§¦ðaÝ^Z!T…¡›jí–ÿÏ EH‹Ð„¾©œ}}!Bj„Æ ôçoh>†#„0Eùú’¢ xL@ýà»{sÿúö¥ý,B?Dȉ¡_sÙ³½¶çlí¯Ahû©×_"4üÔk ¡_!T†¡ûJãœ}Ü{mÏ”B„~ŽÐt„òz !„P¡ÿFÈ…¡1ß´Ÿœ£}÷\ K*FHßmˆÏ±]½•3jŒÙïeƒþžë±ýà»{vÅŸ{²éG÷7,þÉ‘Oö¢—Î6C2‡ §Óyÿý÷744œ#¿ K–,©¯¯ÿÖ·¾õöÛoweøóŸÿüãÿ¸¶¶V«ÕŽ1â©§žúÓŸþ”{kãÆßûÞ÷&Ož|ë­·¾ÿþûç>ŽÕoz¡)s®Îó{èÐÏd¸¬¨H„š%e8AÈò\,ž…¢’„òÌV5Eùƒþd:QYQ>yò¤‰×M0™²$ŠŸÍ2L:MQTqq‰Ùœ‹ÄZš[´”º²¼"ßå¤uz½¾÷ûÁdYN&“ÛwìÌÏÏmÇÎë&NÄñ¯Ïþoõš×÷û?®YûáÇë[=žÁ: {öìyçwÖ­[çóùzL¡Ü±cÇk¯½öá‡nÛ¶­+óÙî.Û¸q㫯¾ºiÓ¦)S¦,^¼¸Gþ=§ôšÞ£¨p8l·ÛÏ«õíöãx„ö#„ZŽÐ/ú B>„6 ´íTåÔ-J·×9AèC„"Õ#ôßÝÒ×!´¡B³»Ý¸{¶ræ ô_µ"”@èe„þx®¶ßó`ñ›/7ÿ~Yó=•$↿ù_]|âøáBèÕ5£û¼ë T[[{ìØ1„кuë~÷»ß=ñÄ7n|å•WÏ};«}MA!,‰ „¬Vë•8¶_œùQpo-àü¹ùœ}?dÀ|NpIä>…/^¼ýà^•ŠÒhÔ"/’8¡S©]VûâÒâü"L’½>oKgKgØW]]ýÝ»ÿ³° GˆË²² ñ,—J¥“©¤§Ý{ððá6o'ˆzšF!ˆ¥U'‰7–.íQu×,Í<³ùöÙ³4šíá¶wtÌüöô¿Âq\0Ú¾cgyyYݩɇZ­vpŒE]]Ý_ÿú×ââb„P[[Û#<ò·¿ý­ë­¿ÿýï½þV³®ººº?þØét"„X–6mÚ—_~yŽüçN¿îºë6oÞÜ}tΊ@HèöD !5B"Bå­;=íîÜ“Í29ÊœÊÙŽP!B!!û©ô³•S†Ð=ÝŒP%BÎo~T‚¢ £“Û¶Fp»nªµª†îþî¾»÷B–ç9Ÿö—!ô B•!„Ž"4웋ÖÎs÷ç™í?€Ð­§.»• ô1B¹{{‡!ôBå!„‚EÈs~µ+çמ¾–!Ä"„#Dz¡GˆG¨¡O»õó·j>ýäÂ&Cvï·\!Í 9=Ïùl×éå¼¼ðÉCOÿj˜&»ø¯–0[T!ž—Ÿžßø›•×\Š£Ó™Ç™î?:Î7Þx£°°ðlùo»í¶eË–åf†·µµÝqǹ cǎݹsg×׋²,?þ«¯¾š={ö¢E‹º‡£çs¼ê%@(‹5¯s²§þ@Ÿ‘$^ØñCpI1é´ÍþöÎ<>ªêüÿŸ{gß’É$™ì!KIH@ö"Š‚h)" VQ@©Ôê÷§‚Kk­µJý¢c«_@«¶È"ˆ€€„-lY!!{&Éd¶Ì>sïýý1$d,„ñ¼_üqóÜ3ç.5*:R(Ò4Ås»]‹E¯×[­ÖêêÚ¼¼³å*?Õ¤‰“ãã)þþþ~*Æíî\âŠåËžZú䢇©=ÚVXž9›7qÂøÎ‰Dááwß5óÜù C²‚ƒƒ[/ÚÞê0ìà ‹íöëzttð¤[@Û5ÔÍ€G U¶Y‡ÙÎ3@ò6k Ñ"HHÛÛ»d ~ÄÁÀ—ÞÒ^Ì3nú륊+Ö‘>ÁoËûå¿öbáSš¬¯þב-×Q=ä=~vçOwþ$À µNOÿoY}T_ÇhëÒŸ~ä/m.\Mûv®ëÏ8ég¿ˆî”¾»zuŸ@HŸêdc‡œ<‚€PH;ì =¯<ÓŒ'NœØµk×ôéÓ×®]ë%qCCCHHH‡©Tjµ^«¤Åbñ¬‹Ñh4±±±à¥ pû¯­%“œ¡çEË?q‹|ì|‹@¸¹øˆ¤J•„'”ðø¾*?_¥L&§x<£ÅRR~¥¢¶:!)qῘ6Gól6+˲N‡Ólµ DÂððH‡ÃYTTTXX`³Ùý"ÂÂÔ~¾J»ÕV\XÔº¥°4M+}}ï?¾²êÚ‹ä‰S§â†W*•ݹʣipÜìFÓzÐöE Ìñ…um+`oHJJj]ÕÖ£“mþ<xöF^ê4´X”ÜÕ—ÅÞU¬S>‰ÀG@`6ôD76A¾ruÜÝsƒ>|OœžÇŸ‰ÞšÕ¯eŠ}õ?¨l£C0X~öÃÿùÀWÀWÀüöjJ×f*ÓßþêŽþåßÅ/:íÛ9¸wã¤÷~zïwª×õòšÏÔ™Ù?6¹QXöÇ Y±bÅ™3Þö«ÕêÚÚÚ«?³Ôµ*~ >-‘ò®‰z Š¢Øþý´ÑWÿ/õ@ðbiÒÏ~øÿ`‹æ|°}¿? ” ˜Ûßþò2®ú‘g~¼h ð"ð«Þ“ÞûÙ×~ï®^^ó‘ûðGŒñÉ9ª»ÎNîUôÞÁ²¬V«ýì³Ïâââ¼$›={ößÿþ÷úúzN·iÓ¦Vû¼yóÖ­[—ŸŸo³Ùòóóÿö·¿Í›7ÀâÅ‹ÿô§??Þn·WTT¼ýöÛý|Ž=¬Ž’ó9 @¸ðr¡8"($X¨©ªkÔÔS<¾Íé4š›R¹:$ÄÏߟGó]N7¦E"1ŧ}ýTn»S[¯-.¾tæÌY?U@HX¨\áãfÙFmc]¦®®ŽæÓ qq¦ævkÿÒSSóΟ;pèËrr™,:*jÖ]3=·Že礧¥ …¶é“Ož:ݤÓÑ4åëã;bDRRBÂì…äääùóçóx¼™3g.]º´Ç·Æ¶½<­îÙgŸ}ûí·Y–íÍGf̘ñÎ;ï”——GGG÷ôQ@ ,h9Ÿó9`‘§H ø-P ø¯·ÿÔZà7@ À¶L(mþ˜„¶õ®í:çó<°øeKݯ{Û -‰øðËh ‹—Ehë¹èy·d_ý xHààÛÁò³þ§´¬YMn;¤´lõ¼ÚßþêvÈö+ÿμ<ßâùýÀ[ìÞÇIïýìk¿wW¯žò™qoÐëJ'ý" ßKL&€.÷‡÷é9ã±ðù|??¿ôôt,ì.ý’%K6lØððÃX¾|ùáÇ[µ¨Á`X½zu}}}ppðâÅ‹=?·-\¸P©T®]»¶¢¢B¡P,_¾¼ŸÏ±ù€Xr3cõ3 Gë\¥çý\[ÛáSaèÑû¯yÛçF_$Œaài!tö§ŸÂÃÂ&Mœœ˜4bÏÞ½%—ìn·P&Éå‘1±QQáãӒÃ$"¡D*D.‡Õ¬7•äääVVVN˜01,<ÜárUVW]*.,*EEEG†…‡].+Ýø÷wnP†R ¡>œr>ˆ|òÉ'yyy7n$ßáVàÃÿ-Ëœ¬JIWöïã_|ñÅúõë·lÙ’p“~¼khhxòÉ'wîÜy#ž¢ž‹ÎÏÒÛožSÜÍ‹cï?E ­†¥ÙTVbUHd ™œcÜǺ\.1EúÄDG‹E|ESEƒæÓ°àpnÆh0Õ×7ØlŽ1cR“DbqEu•¶©I£©³Ûmê  …Báv¹Í&iáÛ—%K–,Y²„´p‹pçì ÿl«î·æÜ±cÇêÕ«_p¾öÚkË–-S©T›7ož6mÚ(ÂËÏv·Ÿæ$3–a!OÂ-‚L.çÜLyù¡PØ¨× ÂP_?¡LÎÜ6›_ˆ¯L!Kø4 †h¡@bwÙ,›ÃîòWLš4E*—546TTU•^)3!¡¡áa¡<>m04ÙlVÒÂ0 ‹—ý¿×û¯·nÝzSÜž0aÂSO=år¹&Ož¼bÅŠA.ìç$?kõH~Æ"Ü"04ȧùe•åÍfKròØi3îä ÅÙ9¹gŽçÝ;‹s±|ð…<h³Ùj1Û|}ý"¢¢ÕMº¦ŠÊª‚‚üêê*©\–””$ò«kª­3Ž´p ÐÂZê»Iº’@ ô‡Ù³gÏž=ûf•>ÄãÖ’pµ@¸=ð :­Qo´6[ìVƒI/“ˆSG'OŸ8IBÑûwîÎ?sÞj¶Ñ|!Å4ë`ÌF³ÛåV©ü£"¢Ýn¶¼¢*¿ °¡±Q*“GDD‰¤bc³‰å±D(Ÿ˜oÅÝlú÷vnö•E]ý÷³ÀäKLnÖBŠƒœÌI ú‡˜/&­†ÂßO×ÔIJn¹B&”HêêÿtL*$>Îýß~û­¶NcÐê|¾|Eñ)•ÊŸa8›Ýn467éõ—.]ª®©„J_©TR_ß@Sœ@€D `œ.Ò„.¢'­ÞÀzyr&JŒ@¸-4'@ Ü~Z•„®%Ü8\à(‘x2‰‚/ÔÖ5;~ÌÖl»ç®{ÒSÓÍFÓåòK—J.ù©üýüŠ¢(¹BÁ0œF£©¨¬¨ª®ºt©Äa·«$2©Á¨×t#’’BBƒ)pžè¸­Ôi4ùUÕ5 Ã(äòØaÃR’G ‚|˜ÕÁ+‘PøÄã0šL§ÏäU×ÔØl6¥¯oƸô˜î¸9~/¾ˆcÇzk¿u ¨!+# C˜·düÍy½tÞsÕ›³äÝ@ ·f§CêççëãÃãñDàI¬ÎºŠÚã'r)Ð~JÕ˜±cëuõõ õ Ú¿ÀŽe)†r:Í&£¦®¶¸° äR‰Éb  ð•ËlN»ÕdT*dÑaJ?¥NodÚÜ{â䈤¤ ™™‰Äbµæ=·ÿÀÁ{gݽbù²¶Évíù.*2€Ñhܱsר‘#ÓRÇÊe2ƒÑ˜{òäÐÖœû^x¡v@ x&M@ ~Έ[þ‘íß„›‹ƒå*ÿá#FFÇÅ+ƒ‚##Bc¢)‘0ïâ…Ý{÷0`F$É2c³‘ñn°l“¶±¸¨ðüÙ¼’â"«Ùä#•†¸í6£¶ÁW*½c\zLD„T,v8]Ó¶¬æÞ7\&“Ñ4­Ë33ÆÕÔÔtð§¢²Òl6‘àäéÓ)É£SÇŽñHb•êÞ»ïÂ}qé qÿý½µwÀnÿö·ïÕ6¾óÎÿ´½EQܺu/DFVÊd–¶·¶n]_"‘Ø~ñ‹ƒååÑâãKJJâÛ~¶¨(1!¡ØK¹­› ;o8üúk$$@"Az:Ξm—¾óѼ<Üs !=_Ýs‹}ñ22àãƒèh|üñµü;¸×özÝ:DFB&Ã;-ÇŽìì«×ÇŽaäÈ«× ƒ·Þ°aP©ðØc0›{p¦»zQT×íà…?D` ‚‚°r%ìöžËíòϾúo±àé§Œ  ¬X«µŸþ{)wëVÄÇC"Á/~òòú±»ñÓWÿ½Œ“îÆm—~v×^ò!ÍI 7IjòÅv7˜„[IsZìq¹ccbcbb“FŒx`Þ¼_?±$m|fiuõé‹ç}UʱécÃÂB,F#-à1|ª®¾®ìò¥šª*ŠcçÜ{Ï£<àï_S]åv¹SÇŽ‰‰Œ6õº¦&@À »,”eY“É”“ÚÁ~<'÷Ž hšP]S+¶ÿû«ÿùñÿmÛž{ò¤ÛíÂ}ñ÷¿ã¹ç@Ó½µwàÍ7_Yyî\ʹs)‡Mïpwÿþ™Ì(/Þ»wV«ñ›oæíÚ5§©ÉæÌýO?ý€Ù³w><µí™2gÎ./årÜÕU…ž‹¶+ ·oÇ÷ߣ±sçâ™g:¦ïÀ¼yxôQ”—ÃhÄúõø×¿z¨ï»ïâÏÆÿþ/êê°w/ŽïU#ïßP^޽{¯Z|ÿþ÷Õ믾ƒ^½^¿‡áàA”–‚ÏÇïßCÎÝÕ«»vðÂîÝ8çΡª þs?‡S_ýýuÔÕáìYœ=‹ª*¼ñF?ý÷Rî7ß`×.45aæL<ýtÏýاr»ó¿»ü½ŒÛ.ýìq)1áàáÃz½ža£ÑxäèOC5hí–-¸÷^ôÖÞ%‹m{饵õõAuu!/¾ø·Ó[­RµºA*µ–—G?óÌ{­ö9svýáZ¼xëâÅ[ÿû7½oæl%, »w_—0»ë.|÷Ìf8°XÐ~ìtÁsÏáÉ'‘ «%%X±âª}̼ó,TVâþ§WE?øàUÍÙº™ÀòåxòI”–Âá@v6æÎ¼ñðÒKÐhP_—^Â÷»•’‚-[Úµswõí«ÿ¿úÕÕr5¼ø"~õ«~:ß]¹V+ÔjH¥(/o÷ƒBwýØWºóß{þÇmw~ÞèñO šód3'@H$!­ƒÇ“ DR¡(ÐOÅ*¯”ç;~úä)mS“ŸŸ’æÑ.·»ººæüùó………N—+.1qLêØÀ µÕjÕÔk¬VÛø;&Œ“ÂR¨®­ihh¨×4ÔÖÕ ø_?%¯ý¤RzjjAQÑç[·~ü鿾۷O$κk¦çÖ±ìœô´4aû˜C ññQ‘‘ß}¿ÿ£O¶|»{BqÇøÌ¡×,‹ ºPGÝÙ»ãµ×þ^œ|~ôè S§î…Ð}üå—ßV(šgÌ8pÿý;Zí÷Þ»§¦&lÞ¼oæÍû¦¦&ìž{¾ëMék×â7¿PØsÜÎq>[yþy¬Yƒ€DFâ?ÿé9ní³ÏbÕ*üö· Âw"=ýªýý÷ñßÿÂß3gbÑ¢^5]J …HNn—ÿ”)˜3J%V®Äã÷³^ý`Ò$Œ‰ädDDàå—ÛÝz÷]lÜàZÝÕ·¯þ¿ñœŒäd¨Õøãûé|wånÙ‚—_†B3Úaî®ûJwþ{Ï¿ó¸íÎÏÿ„Afðcõ3üFÛðDs„~?€ZŸ$W--Ï“^Ç #D@ZcßxXdT```}CƒF«Õ™ÍFƒÜÏoÒô©¿Z¸Ðår6 õ55e¥¥ƒñÁy¿?q‚D(b9®¬´ìØÑ£n§köÜû>Šü‚üܹEEE•UU!¡!ÁÁ!7SYUõqÖæT…!Cè›oðùçøæ›ÞÚ»{³ºÁn’…ƒáöƒOš€@ „›Ž¡Ù$ñ‘Lí¯Ñð._¦õæf­¦þì鼸áñ¾~ÊÆÆúÚš*ŽãÆK?i‚X$v»‹Ùlnn–Êd © ‹¥NS[YU©mllÔjÅbñˆ‘£­VkSm-;¤6(֭úu}°hN@èdâ’psi4é*55ÃL†äq©Š€€Òò+"™¬¢ªª©®îü©ÓQ‘f›Ùíf"ÂÃGŽ%KX7+“I¢££BBB._¾\S[SYUYßÐh³9âãã7k±X•¾¾dr¬7tw°d/œ$ÑœÐfIm«…/ö,¯íËÚZaà1Ù-KŠXOê«H=2<&*"*ª¸¨¤¼¢Â¢7Öp•b…4zø°ÑÉ££¢¢Ün7MÑ<Å”J¥X,nnn¶Z­ MZH(Ž‹ilÔR4ÂÃÃ| Òƒ‘÷pÛjÎΛ¯@2ˆä²º&­éÌ)–O…D„GDDòB ´L"Õ5ékkjÃc"£#£â”J_—Ë-‹(@(д‚æñJŠK,V‹ÕbeÆÏOå篲Ûz½>2"ÒÏW –%-Ü'RÖ-pî…íõYÑCÿ²íŽ´´´Ó§O+¦$ IDAT߸¦èeþi-±Ž}º—²÷)ûMVVÖºuëNœ8AÆÞ-Bnnî_ÿú׬¬,Ò?OÈÚZð3U×®='¦„›ÊÔÓÕ!A/\,/-ûv÷.š¦'O˜$UÈn—Åa‰Šª(¯ˆŠŽJˆ“HÅœÛͰ,Šc·Ó àòå±Hêëçgj6WVVŠÄâØáñ"¡˜åX°í|jêëÏ¿P]SÃ2ŒX" ;fŒÊÏïvñ:¸bù²îì¤×n):OHÞˆ)Ðÿþ÷¿o¾ùæþð‡û{<¿â`#ppQÀBà@:H­¡ÓéRRR®7—ÍÀ: ˆVKûUßΑŒ¹~å³üïÎÞ¼ì@à^àÏ@`·ÙÓ4ššªÓéÈW•hN@ 7³É4jä(•¯ŸÕl‹Å ÚÆ3΃¥šÍÍþAêp™”/¨üU`9ŽaÁãÇgœ.›Å¬kÔ65j}||üýÕ, ¦Þj±‡†GFDòy}zÛ¶m‹-r8"‘7?q¬Íu4ð2ýÈ0Ì?þ¨V«¯7£÷µÀTÀ4à¯À&¯š­¯õíkþ7Ëÿîì9À×€/ xˆèÙ)µZ}èСiÓ¦ñx¼¶vÏß½âš@4'@ Ü|<;Þˆî$ÜtÚ?•L¸9^§7¬NGHdDBÊH]S“ÅÐìëã#•H)€¦y )Mm]ÞéÓ¥¥¥ 1!É͸õM•.‡Så§ ‹=ÌåfÄB‘PÐõŒOëŠÙØa1¿˜6­í­+åå:^.—'ÄÇõÆ>4Xdۙꢗg<ÁríB.}œ»ãÓ“»^žñ€·|,I—Ÿ×cn‰ê˜DuÌÛ>ÞpdÛ›÷¬ð’òãÜ[NîüãÝO‰øÂ—w¿+Iž›²ØKú¬¬,F³}ûv–eßzë­ÞTíàÁƒëׯ Ú¶mÛ_þò—M›6µÞÊÉÉùàƒ Å«¯¾êÑœ^òÏÉÉ9rdXX؈#rrr¦NÚ‡öÝ LëO¿´j÷ÛG÷â$##ƒ¢¨7ÞxãzD^‹`ó0xý¬o( ÔÀ(à7ÀÜÈ0ýïÒþKàuà…–yÎu@Ï_ ¬\¹rÕªUÇyI4'@ zD|=AÑ„Î4i› •¯_s³Ùh0EÑ£érÙåòªJ?__‰T*Khšv»Ý¡ÐiwTVTÔÔÖºwZàïáâ†u=Jîã#ŠU~~v»C.—snº [»bù2§Óy<'§°¨ØÇÇg|FFë­Sgò¤ŽÓa \wö¡Á‰Ê‹îNÏkniµïÌ?â±{4ç΋Gz£9[ÓçT\ðžÒ“ÿÌøLͰ¯8Û»æÜ·oߦM›üýý<ÿüóGõ.Ϭ]»Ös±páÂ>ú¨í­W^y%,, Àûï¿ßcþ‡öèÌiÓ¦µ^÷ŠÏGûÓ/}'ÙÙÙŸ~úé–-[fÏž}]Âø{t° ŒèO}[Öê€À*à"ðÊõå?˜þwgßÌl3·9®‡…µ>ùä“§žzê±Ç»Î^&Íy#!A>0DÑt:£>N”XSQe6[r…ŸÂÏio(8›ÿÕçÛ/~880H¡Ppmµ9D×XßP][+‘Êâââ#ÂÃk«k._º<<>~âä)r…¢üJ¥Åb•ˤB¯Ùêt¹\]* 3Æ+,*.(,jÕœ•UZ­V&“%&Ä·MÜ}È`°5ðË:ØëÍMmíõæ^AiM¯·™¼§ôä?ñÝ'<jLMÞÓ766{®CBB¼¼¸{$hQQÑÆ M¦.ª ‚Ϭ°¶ei¿ë«fq@&ðJó¿Yþw¶?d_Á€XüøoÙWTT<øàƒB¡<ó‰æ$„ŸçãPL~Ø"ÜDÂC„¾ŠF“Ž¥(‰D&˃ÕÁÁ~AΞÿqÇwAR¿9óæùúù[í6ƒÎàt8ÊËJ뵺„¸¸ô´±ŒË™íç¯JMKõ÷SZÌV…\êf\b‰Àb2[ÌfÃt;ðy<m•Ãé3gŒMIé°áª;ûÁW,×Z Í+˵ ù¢–«ª õÍ+Çq‚䪶wYŽcØ.š·5½Rrm¯¬L(±8m·SÄvÈÿ§ßþS!’õÆÏÀÀ@F  ®®®Çô«V­Z²dÉš5k …Édš>}zÛ»cít—ÿùóçu:Ýœ9sZ-.\è!6l)°ðÎýì—¾®­àëëËt?æ{Ëà0ðPËŸ?czúHoê+ÀÕuýÈÿfùߥ}?Px¶*Goá=;Å0Œ¯¯/??nŸµ1ä]@ CXsŠD¢ŠÊªâË—""¢bc‡›MæfqܘÔù÷Í+-*¹TRRUU]«ÑÔhê Š‹Œ{x\\Tt´D"Å£iz„ aQ‘ 8«Ýêv»h ,ç¶»ìN·Ëfkw>çÎÝ»««k\.—ÓéÌÎÉ0|Ø0Ï­ªêêú†©D’””Øö#ÝÙ‡‘#ì+ÎÞWt¼­}ΈÉû÷%9挜ܪœ¯»tàR‡@¶¦ÏŒÕjLPGynqm"™Î9@VÎ,N[YSõ«{Þóîç¬Y³6lØ Óé´Zí† z¬—ÝnW©Tb±¸¶¶vÍš5=¦ï.ÿÇ/_¾üt K—.=|ø°·Œ>Ò9Àžþ N´æÙÞniš¦i–e¯k@<¬Žfà°XÙV¬w:¥»úÞìL€8<Ürf‰×üÓÒÒº[)=Øþwg¼ T. x ÈèÁ#ÏÄx—!… ¾¢9{Ë?@ n BCBÀ²6«…ÏãWVV(ýü&L˜˜h³ÛÅRIphˆÅjÕh4 Zm£Õf R%% £iÚét‡DFF (>ëfX"eÎídX†³Øluõš¶e¥Ž{öüùýßÖýßVM}}Fzú„ñ™WßïóòŒIIáw˜äìÆ>”øÝ”Å)¡ñŽl+j¬hk2óGÓîÝ|üëÍÇ¿~4íÞ'2®Fý}qú£2åʯ×)Ëëœ[¦lÑm)¡ñÏN^Ôj\=cÉèáÞÿјu‹<¡n<‘yÿo&>xðÒÉiï-_µkã”a©Þý\ºtiPPÐC=´`Á‚ÔÔÔëõÆolÚ´iòäÉO?ýtov`v—‡ œÓ¦Mûñǽeô(`^è…C†AêMµZ››{]²s>°X¨€'€?ôT¶»ú> üBßí!Ï*hÏ>Û›ïwö퀸w6`{‚3;;»ËxÂS_­ ÕÔÔÀ³SüÆ+ÁþOT¶žØ.î]IÈÄ(@èý èëL$Œázñü/¼fÍšzc½¦¶Î¤3 ùb>O”š’š™6N,•^º¤Ñh‚Ôþ¡!r?¥Óí²Z,a¡Á)£Fú)•ßa³55jcP` Óét:]§Û][[ëp8jëêÊʯ•}¾õ_7¨ ‰„ô#¡u’ª7Á`ú”¸|ûí·ï½÷^SSÓ©S§n»Æüâ‹/Ö¯_¿eË–„„„!3BÒÓÓýýýŸy晹sçþêKèÙÏI ÂÍÇj2‹øBu ÚÒlðùù4ËIN‰]ßTo¶›¥v+×L;\N>MGEFøQ 9Ž£y<‰D"•J‹a@1nÆm·Û].¦¾¡ñrYY­¦–' ÿÝn,}Rƒ¤tîܹµÍíÂŽ;V¯^=Ęñ?$ëK¸-5§½›9ɼ@èïCQlïÛT'004aáá‘ÅE¥<šÖÔÖçËsºœéãÒC#ÃJ˯H,>n0Eû«ÕÁÁjšæ¹œNŠ¢¯ãfhŸ¦ùÍT³E§3LZmÓåËeåå•…$H¥$-L Ü.lݺ•Ô—@4'@ „Æd01LxHø°ÈسgÏ©”z½¾èRqieÙÌM™h±:NGPPPBBœÒWÁ¸@È1 XŽ'à3nÆípòhžD" -³åâÅ‹¥¥e¾*嘴±NÖAZ˜@ Dsö™t ÂÆjj.*(€‹½÷Þ9ñqñM:(Îɺ–1YÍÁÁÁ6§ÖG®6,&<< ˲|>Dz ÅQ|>¿QÛ(ä‹@Q»½AÛTßÐè«ôKNN¯ª­$-Ü'<~ν°} >Û1¨ßÙvGZZÚ ]ªÚËüoµýœ_~ùeVV–^¯¿÷sIƧT*—-[¶`ÁÒDsÞ8úiƒÄž%·0bFˆ0P(drEkêê~ø~Ú¸ŒÈˆH¾P –IDÇ1ò/H$²ØØØðÐP‘PȱË2KÑ<hšã8ЋġP§3\)¯(++“ÊdII#C·»º²Š´ðÍÅ£3Û*Ï¡Gï¤'å =#++kݺu£G&cï!777//oõêÕDsÍy«BNæ$ƒ©#É–NÂÍ@.–², çÎ¥h^BR¢B®Púû Å‚²²ÒóçÏG„Gd¤gÈår—ËÅ0ŒX(à8–EQ4(Šã8–ãôzÃ¥’K¥—/;®ô´ôàÐP‹¥YÓPW_W×¶¬:&¿  ªº†a…\;lXJòh@ð³:x% Ÿxü1»Ýž{âdeU•Ín—ˆÅ‘™ãÄbò¹µè~> Ç0,+ v‡ÍjeF(àsx|Ǹ9MË1 S]Y}©ä’Þh Œ>L¯3Ö76ÔÖÖ8l¶¶eåž89")iBf¦D"±X­ygÏí?pðÞYw¯X¾¬m²]{¾‹ŠŒ°ÿÀA¥RùËûçJ$›Í–wîüþï›}/鵟Ë0ŒV«ý÷¿ÿýÊ+¯¼÷Þ{ݦ~X lB€àM`!ðí`øÉ²,EQ×›ËWÀ[Àg@*pxðïéˆKΫ˜‘y=þ¿ < ü PµÀZ`!°¸ LVÂbàµÍÙ]½º“äEQ˲4M“oÑœ@ ›È¨(}“¾¢¢J¦P¸ÝL³©¹Ùhâ(Öæ´¨'MnlÔYÌV³Ùì¯R8ŽºúÞFq˸ÝnÆ]WW«mÒÊd²˜aÑ.—«¸¤Ø`h²YLb¡°mY̽¯õZ!—gfŒû×gŸwð§¢²Òl6‘ ¾¡áî™3…B¹\ž9.ý_ÿ7ãL6˜u«vm,n¨¸+a|[»›e6ݶ»à'³GLzvò">ÍCû}›÷pþqßæï‹sÔQ»ï¹™·¸Án–y÷èöÝ…?¹YæÎ¸Ì¦="ˆ¼¤w:ëׯ߿?˲K–,éMÕöîÝ»yófF“œœüú믇††zìiiiÏ=÷ܶmÛŒFãŠ+yä‘ÞäÏãñ‚‚‚üñ»ï¾Û[©ÇÚ\Gï!ƒÑ Ãüøãjµúz3zX LLþ lêIsÞRôÕÿ£m®£€?žaòà€ÿ×r+ùº~8P«Õ‡š6mÇkk÷Ì¢Â!:¢9 aðhÝ+.îtA ÜBÃBÃÂ"ƒt£Ýæ‹$MZmm]µ“qN™6eÊä©çÏX¬6½ÎÌ…´Ãî(°,ëv› ƪŠÊÊê*Ÿ7,vXllìå²Ë—KKœǰ˜H¥Ÿ¼ËBY–5›ÍgΞk!­öã9¹'LðLGÄDGŸÌiµÔ¶!äaÅòe,Ëšš›óΞ=|ôèÝ3gzì‡ãÌÙ¼B:¤V«ïžy§g?癳çúñž»ïb]`°5ðË:ØëÍMmíõæ^AiM¯·™¼§ôä?ñÝ'<jLMÞÓ766{®CBB¼¼¸{$bQQÑÆ M¦.<é0ÅÝ›ü†ihhøüóÏ×®]»qãÆÂ¼ | ì⣅Báüùó³²²zÿ‘®Ïnñt@p‹¾Ò¾7Æc0 ˆ2û©9ÒpåÀ_€§€¯9° þŒé¿æ¬¨¨xðÁ…íWûˆæ¼©¸íà‹É<@¸AJ±‡|±½ey upãfôF£R鯩kpÚ‘á‘"Àji®¼Rai¶¸Ü565 0P(1nP ÇÙm6>ßb1šÍÍ"¡pĨñ ñÇ–^)­©­é²P𦕾¾wŒßvæ‰S§â†W*¯mA¬®©y쑇=¯‰r¹||Ƹ!¹ŸÓW,×Z Í+˵ í¢–«ª õÍ+Çq‚䪶wYŽcX¦sn­é•E«Q&”Xœ6‡Û)â ;äÿÓoÿ©Ézãg`` F£‰ŒŒP×Õ¯ XµjÕ’%KÖ¬Y£P(L&ÓôéÓÛÞík§Çüy<^HHÈŠ+fÍšÕCÙ¥À"À8ô³_úº¶€¯¯/Ã0½/¢ëÜÆ‡‡Zþüs#ÇŸ`ûùÑö_Ä< ô¸†a¼Å:& ]HØ(@èˆÝMÎ& 6‰#ƒCC9ŠjhÔ57›‡>uò”Ìq¾þeåù 4 ÃQÏíæ7Ë18Že»ÝnÐëšt:m“Öh2Š%¢Q£F¤§§Je’ªêªÚÚš%wîÞS^Qáp:†1ŒÙ¹'Ôž[z½¾¬ìʸöoùêÀÀœ'Íf³gÿgîÉ“­é‡‘#ì+ÎÞWt¼­}ΈÉû÷%9挜ܪœ¯»tà҉ιµ¦ÏŒÕjLPGynqm"–Î9@VÎ,N[YSõ«{Þóîç¬Y³6lØ Óé´Zí† z~ Ùí*•J,×ÖÖ®Y³¦Çô=æÏ²¬V«ýì³Ïâââ¼eô9Ìöô_pzUgzx»¥iš¦Y–½®ñ ° 8 ˜#Àj`e[±Þ‡x­]s°0Vàðp»³LÒÒÒ®÷üÒ¾ú'°ÐN x È,òpXÑÿ@Jžˆµ]†€únmnÑyÎÖÅjã|Â`= Ƀ‡0xøûR“ÑR][ÓÐÐ eÙˆˆˆ‘‰‰|P;vïr9\³Ùi·s2(pPààrºŒFc½FS~¥Ôérúøú†…‡GDF¦‹ ˯”òüˆˆˆ¶e¥§¦æ?wàÐ!–åä2YtTÔ¬»®.¬=–“ž–ÖaåÛÌ;gäž8ñÍŽoív»X,ŽŒŸ9cÆÐë‚ßMY\clÜpdÛÌöqkŸÌ|Àì°n>þ5€GÓî}"ã~ýÅé®9øéʯ×L‰Míœ[¦lInJhü³“µWÏXòæ÷YÞÿÑï¿ûZâÜ>‘y?ngþ‘mgöE«B–föðF¿téÒõë×?ôÐC Ã<ñćöžþ7Þxçw^zé%µZ½råʽ{÷ö;*àóù~~~éééo¿ý¶·Œ¼¼Þƨ”ƒÑ›jµ:77733³ÿÇrÌ´À ˆþÐ ­Eµ¿à¼ÚŸþœ„Àp`ù5ÍéYíÙgÛúêÿëÀ߀Ç'Ü|x 0@00x³§úv#8³³³»Œ'<0õ%ÜÚPMMM<;ÅoýÜìdo@ˆ¼ú„ÁÁŽ–µý7øG ðü/¼fÍ¡˜'H*Ê« :¼ÚªZ…D:cú´ùó~¨Ríܽ‹'’F Œð÷ó‹yà€Ëá2Œ••åçÎæå;;,&&###:&ÆÅ¸;vâäI‹Å’2&E(>òë_ß *H$Ò„®·Dâþñí·ß¾÷Þ{MMM§Nºíó‹/¾X¿~ý–-[†ÌIOO÷÷÷æ™gæÎûs¨/¡ƒ3ÏIbl„Û‡¾…Ë&7ÂÀ o2™šëÌf«o°:83#óÌ©Óÿݵ³¶¾î÷¯¾šš™iwºTêÀ?¥@À Ð —Ý©oÒU–WT–WÄÇĦ¥§ÆDGÑ4¥­×–_.ÌŸ6mzúØ´òŠJÒ„JŸÔã );wngms»°cÇŽÕ«W1æEüÉúnŠæ$à Mm½Þ`‰¥> P BÃÃy<Ã0ç.\üôóÏ222‚‚CÅBDzk³;…Ýn+½téÊ•2sssòèÑQQQ¡Q`˜‚ =šñ|R||Jr²€ÇÓku¤… „Û…­[·’úˆæ$„!™¸$ >FƒÁåp ù"ÖÅ8íöŠ+å<`TR’;.În³]8ÞîtFÒÑ<ÍÊÜ c4êëëišŽˆŠŒQ(|\nWM]myù•úúú   ãï‹$…ùùI hN@¸U°åIt z#ÇÐÖå6ê &A&GEF&%&J%’’Ë—+ÊËi>-òy|žËí¬ÓÔj4õ"‘ &,$ À?0H͸݆}}]½ËÍÄÇÇGFF‡„T×ÔWTU‘î)ë¢%ÆÏ€|Öcôпl»#--í†.Uíeþ·Ú~Î/¿ü2++K¯×ߎû9‡$ãÆS*•Ë–-[°`i ¢9o-ÚžG ƒ¡6É3‡p“hn63.Æ!u¨”~V“Y*•(èuº&mSÒw(ýüòKŠt:ÜGár»v{CcDZjµ:22B&“rŲ¬Ýé°Úm _åÈQÉÑÑ%ÅÅšzÍa§ù<ÒÂ7Îl«<‡½ž”7ôlŒ¬¬îhû IDAT¬uëÖ=šŒ½[„ÜÜܼ¼¼Õ«WÍI4çÕ$Ò@z•<ÖŰ˜˜ü ùc³B" ‘K$r™Ìf¶d?¦m¨øñÇ‚#Bë5MMW*Ê4ê€À¤ÄÄàà`¡D>q:y"¡Ì××?0@dd˲U5uv—;,*‚´;.¢N£É/(¨ª®aF!—Ç–’Z[[»yóæœœƒÁ±téÒY³fu›ú`#ppQÀBà@:H­¡ÓéRRR®7—ÍÀ: ˆVµ;?³ ×€=@#Ü üðd[ ü 84qÀ[À]ïé ìÎëÖ"¸ë«o_í]AÓtjjªNGö–ÍI á&1鎉AþêS'NÕk4½.$$8""B¡PD"«Ó±ç»= #ŠkjÒ644øùùedŒ T«Y†q¹\Tëùîåïï/ yBAm]-O ”ÊåÝîõ6÷ÄÉII23%‰ÅjÍ;{nÿƒ÷κ{Åòem“íÚó]Td$€cÙÙ6›ý¾Ù÷Êår“Ét,;[ $ÄÅ‘^ûYQ[[»lÙ²‡~xÅŠ*•ª°°ðÃ?ô¦9_–›€ xX|;®²,KQÔõæòðð œü½q¹HŽA@=°Xü\¦+?á@1ðð@'x70{ ‚k¯<ûWß¾Ú½H`Š¢(ŠeÙþšJ š“@ B¿1êMÑQQ.‡ó‡ýû|¾H,â »Í×O mqØ._)s1.£ÑÀ²\dd¸Ê_EÑæ y<Š¢8–c9$2)Ç7[m:ƒI,•JX·¦©¡¶¾®mY̽¯õZ!—gfŒû×gŸwð§¢²Òl6‘àJyÅCΗJ$T~~¿˜:uÿƒCOs6˜u«vm,n¨¸+a|[»›e6ݶ»à'³GLzvò">ÍCû}›÷pþqßæï‹sÔQ»ï¹™ÒK¹n–y÷èöÝ…?¹YæÎ¸Ì¦="ˆ¼¤w:ëׯ߿?˲K–,éMÕöîÝ»yófF“œœüú믇††zìiiiÏ=÷ܶmÛŒFãŠ+yä/ùðÁ ,X¼x±çÏ”””÷Þ{Ï[©ÇÚ\Gï!ƒÑ Ãüøãjµúz3zX LLþ lòª©r€¯_@ð&øð?ÀÿkI–Ü•ðÞT¿¹©_€îêÛW»WÔjõ¡C‡¦M›Æãµ[ðïYh=‡ènäg@h‡¸å0˜œ;wöò¥ËÁÁAS¦LŽˆŠtº]5 ueÕUu5|‰88<Ôɸªª«ÌfsDDxbb¢@(àñh€Oóh–e)šv¹\ !–HÄR‰@(¤ù<—ËݤÓ])/¯¯¯ï²P–eM&SvNn«iµÏɽcÂÏtEuœ)iÒ5 ½.XdÛ™ê¢g'/ŠŒjkÿ8wǧ'w-?oÙøyŸžÜõñ‰½É-QóìäEgª‹6Ùæ=åǹ;¶œÜùÌÄ/Mìßçöýµ÷ôYYYfûöíÛ·oïe€œƒ®_¿þСCãÇÿË_þÒN(åä|ðÁ»ví:~ü¸÷üsrrî¼óÎþ·ïn`Z>—Ö^Ògdd¬Zµê™gž¹Þ‘×"¨Ú×¹¯ìììO?ýtË–-³g_ßZUàïÑIÀ& 0zM¿ ˜Ù2· `ð@ ì¶ÃjàEàE`S›¾Ä÷Üì/@wõí«Ý+Ÿ|òÉSO=õØc]g/ˆæôB‘ÐCá–•¨äáD@FuñâÅü‚|™|Æ]3}Uçò/r45*y´ÌÏ·°ôíbcbbÂÂBår9ãÙÅqn€Ç§Ý ð¬P,t»Ý£±¦¶¶¼üJII1˱|>O&ï"rËŠåËX–557ç={øèÑ»gÎôØÇ™³yÜwM…Þ1~ü©ÓgvíÞc±Z}||FѨÕ½.0Øšøˆeìõ榶özs¯‚ ´¦×ÛLÞSzòŸøîž?5¦æƒƒƒ=×!!!^^Ü=´¨¨hãÆ………&Sžt˜âö’¿R©lllôÔ>à^¾vñƒÑB¡pþüùYYY×›‘ ‚[ô¡¶eÝlw<d_Á€Xüø/ 6žfüÓFsꀷ#·À »úöÕî•ŠŠŠ|P(’g>Ñœ·Ü;y³#ƒù´!n ‹9sü¸+廿ÿ®¶©á—óæÝ}Ϭ&ƒž£©:&/ïܬ_̘6}šB.ojÔš›› MÓE»\n‡Ý)–Š„B¡Åb1™LZm“F£Ñj›(šæS´Ûîæó]JÓ´Ò×÷Žñãÿõ[['NŠ>\©¼¶‘ÏçÏÌŸyu9ÜÙsçÃû*3rT«1Aå¹Åµ Z:wäTY9ÿ±8meMÕ¯îyÏ»Ÿ³fÍÚ°aƒN§Ójµ6lèùIh·«T*±X\[[»fÍšÓw—ÿÓO?ýÅ_lݺµ¾¾Þétæçç?ûì³Þ2úHæ{ú/8=ò²3=¼ÝÒ4MÓ].)ïÏ«€£€8¬V¶ëâÁŽ^*P ¼x~¥Y <äà2°¢M Bàkàõ®•ö =¿´ ÿ»«o_íÝã‰XÛeHá^_ÂÍævˆ[K¶taÈC£ª¶Êd5‡EF¤KIij¥¶¦Æd4†…„Ê$K³¥ìrYhHˆÒWIQ”Ýjãñx<¡¢(ŽÇeY£ÑX^^~åÊ•&]“\.ãñ(–eCä2yÛ¢ÒSSóΟ;pèËrr™,:*jÖ]WÖËÎIOKë°ò->nøÞý?˜L&‰XöÀÜû|}|†^ünÊâcã†#Ûf¶[ûdæf‡uóñ¯<švï÷{ì/NtÍÁOW~½fJl ¼@S¶¿$7%4þÙÉ‹Z«g,yóû¬?ïÿè÷ßý-qnŸÈ¼Ÿ·3ÿȶ3û¢U!K3{ý¹téÿgïÎã¨Ò…¿µvUïÝIwöd'AY‚2ˆ#Šê8#^GAå2ŠãÂ§Žƒ "0Žã £¨ˆè(wPQ„ QY"K]ÙÓY:½wU×úýÑÃLd{Oåô©:U§*•~ë,õ‡yóæÝtÓMªªÞ}÷Ýß|óMûùŸ}öÙ¹sç>öØcn·û¡‡Z¹rå©m?--í7Þxýõ×ß~ûí@ ™™ù‡?´ûBÆÛ`Æ‘1•ïpK`7s»Ý7n,((8õ×rÜÐ p@@&À3'›”u)À—~?ç€ø4Æwø®¨H¸àùëLxæ8ïöË{G.è§t¼M?qÀ¹~ýúãÎ'ÜeÇ‹Î`„×ë€øHñî×éN²‡(‘Ø!Ôù;ÎQÚ¹ˆ‡ŸmqØ<Þ—Ð/ÿ+5Ÿ~úéßÿþw¯×ÛÁ©}Ï(~øá¼yó-ZÔ»wïsæ 2dHBBƒ>8~üøóáxÑQ~åvNœ!ô녚܉ƒO„Î8Á2¬ÑdbYZcºª…üÁP‹O••p³ßesPvJ×4Ф£‘¨Éhd4P5@'t]«©®öxêYâyͺ®)Šl·ÙÌF“·¹+u«NE¿Â$¥ãÇ?6¶9[,_¾|úôéçXÖNðN/:½1'B!„ŽC’cf‹%;3Ëét–Øô —`¶ÅÄXéwë,,wé¨QY™š®K1IU5ƒU$ES  &ËŠ"[¬I‘|>Ïs‡ÝÌ›’ŠE¬a„ÎK–,ÁãEs"„ÐY†ëÒluÞbÊÉÍîÝ«Wsƒ7ŽDCa`Ôd›« š“÷íØÃsFEÑRÓRMf“*É:ÃÐ-kZ4ñùZ|ŸÙhLMMö¢(ÔÖT;¶>}ú°$ D[¼ØÎ‰Bè´9Kæ­¥9QÁÎq¡Ž†Žx6>˜SÄ^¸èôÉÏÏKII­««ÿñÇí‘pØj¶2ÕÜ੯®Íï? ðòQ¾ïªÿ~µñ‡19ÆÛ$C$ ‡ª««këêŒFcVVV8©8xt}ÄÅ—Œ)ºò‚=yÎÐÔ੬8ˆ5ÜA ›6­?~i~þ’þý»©ˆ·Þzëá‡>ú˜31ÎD¬tM™2åí·ßÆz@çq̉BÓ’’#¡ðÁýåaÐdàû÷ë››“+D£;vüŽ„‡1üÒ‹6¾É×èõ75xê++îøqû¶-[š›š’ÜI‰ .YQjkjCáp¢3¡÷½Ò“SíPµúºšPÈ5ÜA[^|1pàÀØÿüç–;»cû‚ ,^¼xêÔ©XÕèLó¿ÿû¿‹/E|úŠºÞ¯ß·§Bð>†ºXcC³ÏÛBèD²Û- BLÍf“3ÁY‰x}Í î‹Ë"S²×ëõ[ŒFC]M}$¶˜-)©©‡Cc MbLJLpå俤gd1 ÝP[WYQéøÍÖ#Þ•Rïñìܵ«º¦VUU‹ÙÜ#77?o Ã0¢(nÜTZU]-ˆ"Ïq™Ær»vïÙ¶}{(²X,æç÷ísÎÎö¬¬KVV7mÍš5 È:fûñ÷¦t\¼Q´³kuÜàÁƒ»q¦ŸÌ¨Èxà¿ÞùíÆãjx à‹ÃïJ ð×Ùt\YYYýû÷_³fÍØ±cñžŒº¶s"„B§ßŸö·4·˜9cÏÜžº®WVVF!;'çÂ!ƒi#DÃV»µç=ÝIn Ðàñø~“ɘ›››•MÑtuMmmmË2³²Ò3³8£) íÝ»·¼¼œ (WRRÛ²6n*ÍÌÈüýoo¸ûÎ;Æ^}UTV¯€ÕÅkHŠº~Âø{&Ýyý„ñ$EÅÓ”ܼuëe—޼ëŽÛGüÍ›7¬¨8WO„*Š@ÝõéÛo¿½òÊ+Ïëkýc€Þð¼ð,ÀÿÇu3 ð=@à{àæÓ¿S­¯¥é`úW\ñí·ßâ u¹³f!ŽæÄ¿¥óØ7% „Bg²OƒÑ`0±ŒÝæHINijllö6'õÐ?o ý~?g7M&Ç×V×µ46§$§^pAïD—R’•šú:¯¯%99%)9Ùl1‚=»w—ýø£/Hp%ôî¯më²Ål.6ôÝ÷@Cc㘢"–eÀl6 òîûK`ç®] KMI€´ÔÔ‚aÃvìÜ™“}Ž‚¶8ãËñ¢”Í›Wñù纮ç\{mþ#‡ë3ž­Ço[µj• u¤;îîÝ»zè¡¶)m‡q¶m·Œ§ï?ê››Yšy|ô¤¢^GåïHk§ ¯¼òJII Œ=úÑG·]ÀªU«/^|ðàA›Ívï½÷N˜0¡m4Ò]oÑ| `6À(¸ àE€W®?"êH‰¿æq544¬\¹òË/¿\ºôÄU½àd<qtŒw¦×± ôæ›oâ ¿1'Bu“Ž?ÏB¨ûP©©JsSó?þ8hP¾ÙlÞ±cgc³÷²Ë/ï7 _(&*µõ:© Q! 9,Ö¾}ú&$¹Eõ{½žÆF’¤œ ®—Ëd¶‚á­[6¯Z¹²¡Þ““•Û«· Úq Õ4-oÙV–šš 9ÙÙ¥?üŸŸgäù¨ ”•mÏÍÉ€¦ææxÀ—––úÝ÷ߟ{§ 1¶6ãv½ùæî·ßòÔSðÃ_þ˜ÍþçÚ®HÄõ%%Ÿ}Ö‘Rš››]®#:\Æ#ÆM tqvÞoó ï\òÌK%ïÄcζù;Ò·öõ×_onn^ºt©®ëÏ?ÿüÂ… §L™K—.]¶lÙ“O>Ù«W¯†††÷Þ{/ÃÄ#–Ž÷Õ®?ýéOeee—\rɤI“ (Š:É ¯µiÛ ðßÓv\m´mÿÉËË{ûí·ÇŒó /”––¶·Âj€ç2X€L€ŽhçžöVxàq€µa€o¦¯ÿÎ;ïHÏȪ¨ªÜ±{×ν{ÖmXÅ•E¹=rA×ìVË¥_²k÷®/>û¼¹¡1´÷އ_†çy<òöÛooݺuÁ‚XGùðÃçÍ›·hÑ¢Þ½{ãqýú¦L™rá…Þu×]x)¢.wºÚ99üÒ†:Cp‡ãȶ?bÀ‰~ežæ¦~}ú¦geþû“jk ÊãLÆšÚºŠšª´¬ŒÞ}úPªð¶T•ܳoOscó……™ébLhljôü4ËØíÖ¯½WÏžƒö|ß|ýµ Š$Ahª†5|æ¸ë®»ðkýq-_¾|úôéçXÀy>Aç^ÌÙ¹ï‚?ÿHsØÔ‰BèÜÓìó¬©¾à‚ úôïÇ™Œ~¿_ñy[Š¢iŠª­®4²¬Õf±Ú,ÕUFŸ——çp:¶nݶ{Ï®Šêª° &%'ÉJ,&Å(š ‡C›6nðû}š")ª“pÌ2: ,Y² !Œ9O|cB¨ûnø A9Cmƒ'1ÙwÑ…Q¨¬®ö¶xfSNܬôLO]=Eè&Ž3™M«¥_ß¾™QA8pàÀû[¼Šª]Ðç«Ýæv»yÎp°|S£Çn·6ÇD‚ЖÁF!tºX¡ó***2dVBu«!„:ížOHN¢ Ü–íÛm6 o6ÛìöH8\[S#Fʱ˜ªJ--Í&£qèECúôéŲíÛjjªIŒ<§€Öìm]B'I°[m&ŽÝ^º•7ò©é >aî°7ÞxcΜ9Ī@¡s æÄi„B]|OéþÕñ®…ºí6Ü.‚¢4’ð‡Ã›--=]•e†¢++*¥X¬ÙÛàøzöè™™™A€¾~ÃúÝ»w…B!‚ H’°š­¼‘ †IrbzzDñªÕ³iÀÀ2‘Ÿö¶-«ÞãÙ¹kWuM­ªª³¹Gnn~Þ@†aDQܸ©´ªºZEžã232 † å8þ±ðøºÜwï¹}"ZZZòóóñ‚D¡s#æD¡®ÔÙñœG æÄÑãèôòª¦±çp8<ž«¶Û,–ž99)ÉÉAŸOˆDëêꕜ’”’–Š„~Ø\*ˆ†¥¢‚(«ª7ôìу]E|( IDAT$HŠ¢tU«¬¬Ú^V6bøÅ6‡Õð}DCçÆM¥ýúö½¸ €çùH4ºu[Ùêâ5c¯³ºxÝn¿~ÂxžçAØZ¶}uñšk¯Ûj¶Fžç*MÓ‚À«!„ºÖ™ÞÛ†;ü!„:‡54zšý~_$1[Í6‡=*D›½^ESDIª÷x4U·[.§Ëd0•—W„#Q–ã9£‘fhš¡í{ZzZŸ~}œNGK‹·¶®.++‹1°MÞæhLPuµmY׿¶×=M&I’³¹`ØÐÚÚZhhl,:Ôl6Se6› †ihl<Nªª%%%n·¯F„êZ8o-B!túišJQDLbRÌl69ì ‰Wbkb}!ŸN$Åh h‰”ï¯Ü±cw0*ˆ1ÉŽÝ£Gþy̳(ÇškšCÁ€¤ËÎW0a ƒ7èkiöž P-oÙV–šš 9ÙÙ¥?üŸŸgäù¨ ”•mÏÍÉ9NÁ°aÂxöÙgñjD¡ó+æD¡:µ'S8c-:C¤¦¤ØvŸ¯%¢‚f³Y32ÒSÒRY–5‰`¨&½ÑÈ™ƒþðúõ›ö—ïEQƒá¨;Ù=`Pþ…ƒò7oÛÒÐÐ ˆQËšL&¿¿…ã hÁPXŒçJoí(ë°Û¯-Œ1â³+¶¿è]‚n—+Þ±ö<±~ýúwÞygÑ¢E×\s ^!t^ÇœÍô•zØ:Šê8êF™&³1‹66‰:(É)n»Ón±Y“Nd40F§sÓ³YšÝV¶í`e…+É­jšçÒÒÓ{õéc¶Z”—‡#a“Ùh5r4ÇFD!-3£¡±QR$‹Å|l‰Üw¯¦iÁPhë¶m߬];¦¨¨¸¤Äív)º">žs˶²â’¯¯såyr X–½ñÆßxã ¼B¨k5³§ŸÚ;ôðÍ{¡ãߎyt…£ÇÑéÕÜØ( C³Fž·Ùl6«- nÛ¶í›o¾Ù»oo}ƒ'-#íòÂË.<HBRd‚ hšÎÊʺð 322¶lÝ"ËŠ+Ñ•˜˜¨D¢B z;\¡pXcÆpü/$i·Ù.>¼ªºjjk †iÏ9|ØÐÚººóê,Øl6UUñjD¡ó4æD¡îÐjâ#*tz©ªê÷µ„B~MÓEilj¨¬­ñ45úþêšš}ûö¥e¦'§¥ÆI«Ý¢S•ÞÄÛ61&áÁÆŒ¼|T .0pMÓ½ûônñ¶ø¡H$"ËrÛ²>[ñEEeeL’TUõûë7nr»\àv¹6l* ‡ÃñqžKKãéçÑ·"’$IRÓ4¼ B¨ é}k[ÛÄî_ !„:].¹øâƒ•åUU•Š¢4áó‰Î´´4g¨®ªðÓm «=5?îÙéijÐuÍÎ8Ù=²݉²¦¤¤¥Ê²DšB¡¨ÑÈ(/ßV¶Ýëõ’e2³mËrÑE[·——”hšn6™²³²®º²Š®(ܸiӲ埊¢Èq\fFzQaa|•ÖÁŸñ…sø-n·{ãÆ$‰ÏåBè\ˆ9¹n…ã9B]22Òê=u‚(„#QZ¤Ív‹Ñd²;ì1)æÍV³§Éãõ6ïØ»CTDƒÁ@²”F€¤Ê¢3–9”W–746´ø|E2®²¦FˆÅx£É™à`ŽìÖ”’’œ’’|ì>yþòQ£Ž»{çpy”ûï¿ÿÿý¿ÿçõzøá¼,Bèˆ9O5TíÀ4B!Ô¹ V:­¢Ñ(MSV›Í ˆ!Ñ–àp8ì¼ÑèõùAÌÉÉEÂÁ€? :݉N§Ól6ÕÕÖUVUfde¦e¤›83SÏD¢Q ƒW%*Äl;Iii)ªÃî ñãÇ?ë!„ºÐYÓo§÷@!t«¯¯')*9)Ùb¶hºÆ²,ÏišÒŽ„ŒÌ,ÊÀHšÊ¹”ŒÔž}.p$8T]iö{#B„7òh  ¢HP”¢iM->IV œÉæp¦¤¤Z,V¬a„B§ËYÓÎ٩"„ºãÞ‚P÷inö*šE³Õ#‘h¤ªºÊè3#a»Óaà ÍM¾P@%4Q‰Õ5Ök²š”–š•™™œš£?þøãw߯ ‡£&³™¦éP(FU³îv»‰‰Ñ`k!„Æœ!„ÐùËb1ÂA‘$ “Ḛ́I–Ãá°Á`ˆÉRL–tŠ`Yoà8ž¢¢S­v›ÝéFBë7løá‡Íiié ɲ®é6‡ƒe9Ö`ÐuM–%¬at\ùs&@Ù´¥X¡s8æìÐ4BÇN?‹C:BK‚áPcSsKKsT8ÞH3TLŠ‘4e²˜ ,ë b²¤NÐg2Z¬Öúú! †C5µµÍM5uµ ‰ ™ÙY,ÃF…C£:ÀÀs’$·ø|XÃ!„ÎÛ˜³Ó*BýBmŸXuø®"âusÌc‚º3ÁáNJ2Ù,:AHšL’¤¬*¢$Fc¢D9FÒ”3Á©ƒÎ²,A’ž†úÛwè#F\Ò«W¦êš’¢8ΠjšÝaS5ÅÛÒÒ¶¬zgç®]Õ5µªªZÌæ¹¹ùy†Eqã¦ÒªêjAyŽËÌÈ(6”㸚šÚí;wÔ×{4M³X,=ssåçÑ4v•:u¶Ý²³-œ]Õ.:xðàÍ›7ÿòã=v;=öXNNÎ<ÿqÞ¼yçÅ_<½ç厷«‡ô6‰ÿX°@Ș0 ÀÐðÀM.€±pá¯ê^øî)„Ðùþ‡Ð镘àHpÐ4M3´Õau8V›Å`0(Š †b1IÕ4€˜,ùIQìvGRr²ÁÀƒA¿ßg³ZûöíÓ»g/·Ëe4rID"‘@ ¨kZL’‘HÛ²6n*ÍÌÈüýoo¸ûÎ;Æ^}UTV¯€ÕÅkHŠº~Âø{&Ýyý„ñ$EÅÓK7oÎÍξéÆßÞ3éÎk®Ž„Wã)Cg¦éÓ§/[¶lïÞ½PVVöå—_NŸ>ý,Úÿ'žxâ£>REùè£þüç?ŸdýÈh3nÀõe~€/*&ÀÍ,À÷A€ïX€›ñªAÝîìxH‰ !„Îm}úö-¯8xààA¯¯%1ìv&&yIÓ1Yö‡‚’,8ƒ‘5IRLŠI’¢8] šQU5‰òoµZH’$4àDz‘H¸²ª*à¦$»FN:r<çuã¯m]¶˜ÍƾûÞbhhlSTIJ ˜Íæ‚¡CÞ} \?áçw‡X,–K†_üÎâÅxÊNÁg;¿}oóU¾úD“ý¾‹oß(šº`í+v}×ôûÍ”‘7Ó$‡[Ç÷õÍÍ,Í<>zRQ¯Ø×T5ÿÛ%;<¢’ØÇ}×°ñ£/Úš?®#­‘mó·Íy¢r;»ý½{÷¾úê«;wîŒF£={ö¼ë®» `ðàÁñ ­ ­­y+W®üç?ÿéñxòòòf̘‘ššÚšó‘GùàƒÀxð Íf»÷Þ{'L˜Ðþñ×sÏ=÷é§ŸN™2¦L™RXXøì³ÏžÊŽ®k³œ 0 6|`€ €ç2~ÎßÉ.i‚Fèì‹9ç–D!tNSA“Ùh6©„îLH°;œ,g0ð<Í2 Ër&N#ušcu]W$™fXJ]‡H8B’’âoñ×VU †êºÊòò^_‹?BÕUN§]VåãªiZ8Þ²­,þå>';»ô‡òóóŒ<„²²í¹99Ç®UYU™š’Œ§¬³>Ù^üܪ7~“3èï7ùd¯^½Þ{ï½xÌÙÎ~žAÇ]þEVÄkâz€Ó’æÜ€¿è¼ˆ99(…ê,|…Î1MÍÍ¡HÄît »x8c`U]c9C,ÁžèŒHBTi†æxtˆÅbŠ1X†¢%A¬¼-^º’Ùµ{×¾}{)šîÑ£ÃÜ.7EVÛqÞÏù…oÄv{¼ås䈟­X±ýý%ñt·Ëuí5cZë@yùºõ믻v<ž²ÎZ¼ùKøÓåw¸Ì˜1æ¾xúg;¿€1½‡ÇcÎÏv|Û6æ¼¢×0š¤ !thPnTàMŸ]Õç’‹³óf{¸;ööØr;‹ ˆòòr·Û™™™——7wîÜ“®2{öìøÂĉß|óͶýùÏNKK€×^{­#¥1bݺu“'O>iÎζé¿öÚk 0uêÔÉ“'ÇcÎ%K–Ìœ9³ÿþýôÓOŸZ½=óÌ3ƒ Z°`AAAÁ‚ >ùä“3füõ¯ýE§ó߬€WŠÚ´møï©×BgQ̉ßSB¿âMàT¦¼Æçb¨ÛŤÍ2§33+«¢²ò`ÅAÆ`HKOcFQÕ`0(ƒ AR”ªhQ5JêÀ1,M3BTh¬÷èºÖÔØ‹Å(’ìÕ»—ÝîHNI6[Ì,˪ª"„ÂÇ–øÀ}÷jš …¶nÛöÍÚµcŠŠŠKJÜn÷˜¢+xža˶²â’¯¯se<¿¦i6•(/¿æª«ívž²Îª 6@ªíèÙZÂ^°r¦Ã?ã±sTþ¯™üÒ×ï­Ù_ºf)K1Oýa€Q]¾·Ç–ÛY ,xï½÷æÌ™SQQa4üñ¢¢¢vòïÙ³gÁ‚»wïïu²­ýl;"‰¼õÖ[?üð‚ .½ôR–e»°f¼^orò¡vþ”””¦¦¦ø²ÇãéÑ£Ç/ßþÌ™3þšNÓ7ÝtÓM7Ýtꛓžø`@/¸ àc€dÀ,€;þƒ¿ cN„Bè\çUM5¸P8ކUM•„¨Ïï7šŒ$ETUUÒ¼ÁéJàHR’$!&9¬V𢠀p0P[[m·Xe9úNgJzï¤ä$]“ÙFeU6ÛÍÇ-”$I»ÍvÉðáñq›5µµwÞvkü ºÙl>l軇Û<Áà‹× †ßÝp}ëè5Ô)©VW¹·¦.Дí<"|r›Õþ†P,ªë:$™íoghfÿîxÑ ~òãš¿­]:÷›ÅÝsþr­m}ªª®^½úÅ_ls¡ëzÛŽ£?þø]wÝ5kÖ,‹Å /¿üò¶[;QÓc· .9räwܱsçÎE‹Ýwß}íìggûÖ&$$x<žÌÌL¨¯¯OLLŒ§'''———÷ëׯãûÙ¾.hr<p3@À€ÄÉ«jâC\3^HÇßNÔípÞZ„ÐY‰;ü¯SÄ6ÿ#tFĨ(‰áH¨¶¾(*5#ÝátJªŠ‚p4$Š"yÎ@IèÇ2É.W¢ÓIz‚ÓžœâJJv¥g§d妹Ó9;C™H…U$JÑl²úlÅ••1IRUÕï¬ß¸Éír€ÛåÚ°©4ÇÇyn,-§ïûé§—ý_Vf渱WcÀyÊn½è*˜óõ{Í¿/œ½æxú¸~#૽ëWíÛãúl;~òâNϳÁX9xÆpDDd´@•ßÓMGÑñíÿñ\·n]4•$IE›íˆ¶q·ÛýÝwßišöóýYN'Çquuu³fÍêàþ»ÊÊÊ+V<øàƒ0uêÔ¥K—ÖÖÖ¶Ú«ü………óçÏ÷z½^¯wþüù£GާßrË-Ï=÷ÜöíÛEQ¬¬¬lÛ\yÜýìv‹†Œø¢MÀ Cž¨ªžvD~Ü ¡_è¬içäÎ°í „B]ˆ IŒEEQghwRŠ=ÁŠ„›AI“N—C t" YÓb‚`IMëÛ»WJbBÐל•™šžJs¬ÑÊLœ’LI*¨*#ËjL¥mYC.ºhëö²â’MÓÍ&SvVÖUW@Ñ…7mZ¶üSQ9ŽËÌH/*,€â’¯ tóæÒ6ßÅï™tg×vY<çݘMRïoùòš7v­­ƒ6ï)¸.‹þóûOàöÁcï6¡ýíL¼p̼o—”ÕýD“Ô Ô^Žºµí§“GN|mÝ¿'üëQM×;>omÇgêøöo½õÖwÞygÚ´iÇ 8ð¥—^jûé”)SfΜÙÔÔ¤iZ<Æ{öÙgçÎûØc¹Ýî‡zhåÊ•©Õc·óòË/Oš4Éáp@RRÒí·ßþÒK/Í›7¯«Îãý÷ßÿòË/Çû»Ž5êþûï?t^&N´Ûí³gÏ®¬¬´X,G5®»Ÿ]zû8r!þÞ”Û`ÀŒ69}Kž¸äðû9Ç>ñ^Íñq³uñEêõz >ú´:Ép©ãŽÃ<…qY8ž¡ó™Štg[jp<'ê.ñ¿Â³fÍj1)1Y–4Õnw:\f›%ò×7ԅáÄ$'MSM^¿/ÀдaöïÙׯWïß^7¡wÏž² … ‰NÞd D¢S MÒåˆåxN’ähDÜ_öÓÿ^ûÇn:žçñ<"tøðÃçÍ›·hÑ¢Þ½{cm ®…ã9Bç} íÅ”p¢_C‹¯…a ‰ÉI™Y9²¬¨ªJQ¤ÙlÖAUU9>ŸuƒA—Ž3¤¤$ÍfEW)ŽN´$’¦ˆR,* 蚮ꊦŠ"J¬F Ö0B¨}Ë—/Ÿ>}:œcήú‰BYdY–µ¹©)ÉÜØäU 7qœÁ ˆT8"H" ±4g·ÚxΕ9 og4ÄT™$A–UQ5ÐD9F°4M,K1$A©²" 2%éXáö-Y²+aÌÙ50Eè|†¯Fg,EV F£ÍjĘh08ƒAR%E‘cRÌiw¤§¦šyK’;É™`w%¹ÒÒR8ž“TYUTŠ"iŠR… (†`h’"tÐJ—5BЉ¢‡d¬a„BsžÒ×Gš;¥Wí!„ÎSÇÎ[‹·t†0›-®¤¤ z÷‘…ã &³Q×µH$,QUUHzõèi5Ù,s‚+Áž`§Xšd ]ÖY YƒA×Ф( 4IUDY“T9&G›C1$PïÅFÇÕñÙƒBèˆ9;ÚüpÒ®³ø !tBŠø” ‘22ÒSRÓ333+*+(’T5 øC~Ðu’ ¢‘Hb§ÃêÐ4UUdIŽE¤°F˜iE”¢Èª®ÊªDé Å ¢¾,Ää¨ò_¨±ªk!„Æœ'IŠ9B¨ûaW\ô+±Úl:èµµµ^oK(&BÓ«Åd4%øý^‹Ñ¤È±p0(ˆ‚ØKŒºTRqÊNWŠ›âèXX”IŒ ŒB*a9Üä÷7xÕ¨¢ÇT!&%…Ñx}½Ç³s×®êšZUU-fsÜÜü¼ È¢¸qSiUuµ Š<Çefd Êq܉òãY;u¶Ý²³-œ]Õ.:xðà_øÊÇ{,''çˆÿ8oÞ<Çóâ‹/þ:õüË÷ÿDÛù5Ž«õ~Ðv ÷¬²&L04<ðÅáw«Œø € ÕPçX!„Ði G‚`ÆÀ2·ÓéÔ4­±¡Áb6ÛlV³‰çyŽe˜p$„˜£¢(º&Éb$òúšë›j‚-±`””TJÕŒGƇ7•ffdþþ·7Ü}çc¯¾**«‹×Àêâ5$E]?aü=“î¼~Âx’¢âé'ÊÐi4}úôeË–íÝ»ÊÊʾüòËéÓ§Ÿ·Ç5xðàN”¡mÆÍ¸  Àð@%@ü®7°ß¾`nÆ«uþAÇó~N8µöωêÔ㨾µ'»}`;'ê^­ïçl0ˆš®;“4]“YÑMWÅXTC§ý¢ü|#Íò,/Ër“¿™`HWªÛh51Ãóœa…`ØSY'úÑÆ`¸1 †Di44G3,E645<ü 'Ú‡˜$½ûÞâ{ï¹ûÍ·Ýqë­,{(@•$éÝ÷—üá®I'ÊÿßÏÙqŸíüö½Í_TùêMöû.¾a|ÿQ hꂵ¬Øõ\Óï7SFÞL“nQßÔ76³4óøèIE½ `_SÕüo—ìðˆJbwö]ÃÆ¾`hkþ¶Úol›¿mΕÛÙíïÝ»÷ÕW_ݹsg4íÙ³ç]wÝUXXxÜè(ÞÐ'Â+¯¼RRR£G~ôÑG9Ž‹çŸ:uê[o½E’ä•W^ùðó,_ñóÏ?_²dÉÂ… o»í¶Gyä²Ë.ë“ÕÙý€•+WþóŸÿôxø <ðÀ·Ýv[ûÛ9…ã:•vWâx‘g«@ @À P `;œîÈëvI“/:·}sá«PB¿Þ@Й¦¹©IV5“ÅJ3l( aA$Y4š ½ûôIMKƒËp&ƒÆh¼™OJK–UY”Äh0,¨º.©Fo¤Ùm©¡#“œ‰ä)†gYÎÀ9ö¸…jš‡·l+‹9ÎÉÎ.ýá‡üü<#ÏG¡¬l{nNN;ùQ§|²½ø¹Uoü&gÐßoxœ"©¿­]9ßÚ¸üÒÏŸ(¼f¿e6ï~CëZgçý6¿ðÎ%ϼTòN<öûßås«üžwny®RnyKí¿6þ'sÆ#ÀŽ÷}m›ÿXÇ–ÛÙíO›6íÁœ5kMÓ»víz÷Ýwã1[<>96Fzýõ×›››—.]ªëúóÏ?¿páÂ)S¦´c~ø!A/¼ðÂÛo¿}ÿý÷ÇÓÇ·jÕª[o½5??ÿ¤Ùq[Û –:»ÿ°fÍšyóæ%%%}ðÁýë__}õÕÖ6lØðúë¯[,–'Ÿ|2s¶³NWwY/ùz€Ó’æÜ€¿ÍèìŽ9ñ-¡n$âBèL¾>EQ )‚çy¹QQdtÝd4¥¥%÷È͵Ûm’$AB·Ðf«ÝÊд®)’„¨¯©E Fšë—\œ7{ÜÃݱ·Ç–ÛYA”——»ÝîÌÌ̼¼¼¹sç¶Ÿ¿¸¸øµ×^‹÷¼›:uêäÉ“[cÎGy$111¾0eʔ֘FŒ±nݺɓ'Ÿt:Û×Ùý€Ù³gÇ&Nœøæ›o¶ýèÏþsZZ¼öÚk)½ƒÇÕ6n]î‚VÇ< °^(È8üÑP€ÿžz­"Œ9BàS0ô«1šŒÃZÌšayžg–¤ ›Ã’››àH )°ÚÍŠ, ¢ š¢È‘P$Ž¢ Šm¥ò{C^Ÿ•5&m&#Çi”•ãY’‘b"I¨Ê±%>pß½š¦C¡­Û¶}³v혢¢â’·Û=¦è žçAز­¬¸äë«Ç\y¢üxÖ:¥.Ø©¶£g_i{ÀÊ™ÿxDŒÇRGÏÕôâ5“_úú½5ûK×ì/e)æ©¢?L0ªË÷öØr;kÁ‚ï½÷Þœ9s***ŒFãã?^Ôî5ãõz“““ãË)))MMM­µ¦'''766¶¦G"‘·Þzëá‡^°`Á¥—^ÚÚç¶Ktvÿ÷ìÙ³`Á‚Ý»wƒÁc?íT×€ŽWkÈ×Us ðÀG+zÀ$xfÜðü…Fƒs!„B§_VvVNv¶Íî‡#Ь¨ªF’”Åbu8œ>_ ‰P–22Oq&VQc’ (BÌ×àm¨¨ {Z¨˜n"X+Í›iŽ#(BUuUâÂldY†b¨ãÿ¹'IÒn³]2|xUu ÔÔÖ b6›)Š2›ÍÇ ­­«k'?ê”T« êMG¥»ÍNÅ¢A1IfgûÛšÙÿ£;^üú 'œ(©òÜoŸ™Ç›ýôÓO/Y²díÚµÓ¦M;jæU‚ týˆæ÷„„Ç_®¯¯7lƵ¦{<ž¶é .9räwÜÑ·oßE‹µ¿?ƒ§ ÷ÿñÇ¿òÊ+?ýôÓÍ›7ÇG¥•ÿ¸¥»ÎWW:0`'À€!‡W< Àd¼pD;'Bs"„Bgòýå••Uµ5užzO‹/ š4Á@ë–å IDATJ19&I‚"Ät‘`3²Š"iª*E„Ú•å; 7úÓì®4Gr‚Ñf¢Y–Ð MVb¢$G%9úe9Ö¶¬ÏV|QQY“$UUýþÀú›Ü.¸]® ›JÃáp|ÜæÆÒÒxú‰ò£N¹õ¢«`Î×ï5Gü¾hpöšwâéãú€¯ö®_µoŒë?²ýí<øÉ‹;=ÌcAæàÑ›ÑU~O7EÇ·ÿÇ?þqݺuÑhT’$Qm6Û‘¶ÛýÝwßišÖšRXX8þ|¯×ëõzçÏŸ?zôèÖâé---óçϿꪫ≕••+V¬xðÁ`êÔ©K—.­­­mg6Oî¿(ŠN§“㸺ººY³fu°>ÝNg«Ë,0à €Ä¶9ž¨ªžvt$¿Ýè¤Îú¾µÍáÔµ!„Îv²"‘ ÝIÉV›Ä0ŒÕj±;œ$IS$ †4ƒDq:M0¢(R*)Å7ÚròBUx2è$GÒk XNÓM“¢Ñˆ¤ÈŠ$µ-kÈEmÝ^V\R¢iºÙdÊÎʺêÊ"(º¢pã¦MË–*Š"Çq™éE……íäGrcþ4I½¿åËkÞ|Øi´¶Ú¼§àºp,úÏï?€Û½{Ø„ö·3ñÂ1ó¾]RV÷MRƒR{=:êÖ¶ŸN9ñµuÿžð¯G5]ïø¼µŸ¨ãÛ¿õÖ[ßyçiÓ¦q7pàÀ—^z©í§S¦L™9sfSS“¦iñØïþûïùå—oºé&5jTÛA›yyy7Þx#EQEEEøÃâ‰/¿üò¤I“$%%Ý~ûí/½ôÒ¼yóºìA'÷ÿÙgŸ;wîc=æv»zè¡•+Wv¤”c·sjÇչ޵đ ñvÖÛ`ÀŒ69}Kž¸äðû9Ç>íñ^Äñqªä¢;“Þ•'=uÜIk1æDü梈Íurâkωº]ë»RZÌ2A1 Ëõí—§*z$!iÒdâyž5p´?êµ§MÖÀ2ŒFýJPòV7Vï*W‚¢Ûâ´Ò#Í‚¦ò m6rœQdQQ•¨!€¨kößóÌìn:|W êV]6Ruµ?üpÞ¼y‹-êÝ»7Öjߙַ–kW"„ÐéŒR1àD¿¦DW‚Õj&)’ãØ„Äƒ£HŠ¢)‚€˜$2,ERÍÐ4MÇ4E ùüª$q4m )E›yÎ@Q„®ªº¦kI€e}út 8QG༵!„Ðé ÂQ1]‰îôÌ\MÓ€–¥MVQ£ÝJ›HES:¨²²*ÃB$b i»Ñdá9ž¤YÅMè:C‘„®«²ªª2ASš®ËªŒ5ŒêZK–,ÁJ@s"„BgòªF$¥¦&&¥Úö¨ŠŠ!Î̹S9’ÑIšÒe’Ñ_sCS‡PÎ@¤ª€h0Zššjx†qšm<Ï’ÀÈ á˜ÅiVXMÅ¿ö碛·¯ŸiŒk˜óŒ€Ó!„:Û9ìV“ÅÈqf’„P(d6[ 4M#‘Dg*hLÈòyšËwýÔRÓl$g´p¼…3Py.z[šÃt„&)¦P¤AWIPtRþµçn JèºNœÖ]Çó€:‡bÎS +Å_¶:B!ÔÝRSÓŠÔ€ÖTФH‹ÍBÐFU ³•f!iQ‘I ‡EK(Ô"bÃ’„¨ÉrL¤8–R)†")Še)‚%uЦù˜¬é¢ª5¬a„Bs¶+;4uF’¡S¸¿t N „~m¬ÁÀ²¬NÒ±˜Â(“ÅÀ°DLV4ɪFÑLLVb‚$1*é1à€5¨!ë@(À€¤+«‘¢‚ t’Ö)Š0:AÊQ‰šcÛ²ê=ž»vU×Ôªªj1›{äææç dFÅ›J«ª«Qä9.3#£`ØPŽûùw!òÿ'â÷Ý‹§ì—øþ{øÓŸ`ÝºŽ¦Ÿ9°U!tnÄœ!t*Úy%™0 DgYV)Z7™xƒX–B£hŠR””hTäM¼¢iBLFc² ³ÀšÒ¤SŒªq$e" ²&é*£„¬i:¡iH1QUT‚ft’m[ÖÆM¥ýúö½¸ €çùH4ºu[Ùêâ5c¯³ºxÝn¿~ÂxžçAØZ¶}uñšk¯_KÓ´Õÿ-¾pРï×oÀóõ ½ôL›Ö‰t„:«<¸ÃÿB¡3“®jŠ¢òœÁ™`7p´ªÆ@W† )]’EM×TÐ1EbQ‰#Ygu°f+m´Ð¼…5›4 (š (U×MÕ5- ‹J,¤Ä‚j¬mY׿¶×=M&I’³¹`ØÐÚÚZhhl,:Ôl6Se6› †ihlü9R--å8.à@½{ïm§\‚‚øyh3†ô“O woày2¶m;”¨ªð › N'Üy'„Ã'¯™?„aÃÀj…ìlxë­ŸË=j7Ú.Ï™™™`2Áܹ‡ûõƒõë-¯[ýûŸúþ „0æD!„ΊªG‘` HSϳ KÐ,xš78ÞÀòcÐ$UFb¡(£‰d­´ÑÌpÉÒI”®èº¦)ªª(²¢Èšªjr 4E–EQŽ[¨¦iÁ`pý†©©©“]úÃáHDÓ´p$RúÃæÜœœxÎêššýÊ /¿ ÏÔ/÷òËðÈ#@’M?ÊóÏ?]U•YV–_V–_RrùQŸ®^]T\\XQ‘½råU­‰Ë–Ýðùçã¼Þ„¢¢Õÿó?¯À5׬øæ›QmWüöÛKÇû¼½Ç"ú¡^µñ…¶=l—.…U« © Ƈ<”8o””Àš5pàÐ4<ýôIŽëoƒ¿ü^yêëaåJøþûUæêÕP\ °rå¡”ßýþýïCË ¿ûÝ)îB¨ ^¯Τ½êôxNœ·!ÔÞíBæÇs¢3Oü¯ð¬Y³”t>"D(†ÌÌÉp''[m&£™¡ ª¦ ª¥Yƒc«òÔî®k}fH¢,‰¬‰'h–¢h–£! š#Šª°k¤8BÕ(Šy]ý3ÿXxTÑÿXøF|Áa·_7þZŽã$IþlŊƦ¦xºÛåºöš±,ËF£Ñ²¬èŠÂÔ””øŠmÇsò<ç±ãš›að`سŽª¶¥ûÍ-7·ü«¯Æ\pÁO°woï>}ö´Î[KzyynNÎÁ­‰˜ÜîÆHÄT\\¸hѤ÷Þ»ý¦›>dyñâÛn»mñ=÷üëòËל¤øcÆsTWCz:@4 .D"}úÀŠУ@c#  ••ím¹GXº†=I‰m$(/‡ÃFùñG7**²²à‹/`À€SÙ„P:3Çsrø…!tCT¼ÿ _ŸÅdáxNUUU)‘BÕ9–¦9¯éD$,xjš«=R0l¤(›‘ç5š! BW%EdU$$ÖÊ)ŠÆ§k:C„ A‰Ñˆ¬Èº"[â÷Ý«iZ0ÚºmÛ7k׎)**.)q»ÝcŠ®ˆçܲ­¬¸äë«Ç\ùß5%ýûõ‹œèzõU¸ûîã–'J?V}}JffU|9+ëè°);»â¨”-[.züñY›7öù­‰—^úí£¾¢ªTIÉå$©i¹}{Þo~óÝ©T<࣢ÑCËUUгçÏyNÚ~[Uõs?ØŽËÎ>:eà@àyØ´ tL¦Cç)ìB¨ ­¿píOZ+þ‡Bšu%º32ÒY† [|¾FEhtP%YÃ_ Òì}=³9“Ñ@ êФÄ9"ë’¬HAhš“Õ˜¬Š²*Ȥ 4yü÷7’$i·Ù.>¼ªºjjk †iÏ9|ØÐÚº:¨­«+ݼù ߈ÿƒ6m¤¨SÞ~ûçÞ§'M?®ÔÔºªªÌÃqTæQŸÄѳÊþþ÷Mœ¸´¼òÏýg+¾¨¨¬ŒI’ªª~`ýÆMn— Ü.׆M¥ápXÓ´p8¼±´4žþÀ}÷¶ýOÁSv -‚±c!1±£éÇuóÍ<öØì††¤úú”?ý饓æFnw£Ñ­¨È~ðÁ¿·¦÷ù3Ïúî‡\tÑ®={/YòÖ;ï~ùÕW–½êÊ"(º¢PU•eË?}óíEË–ªªjQa!žš®¢i0þq¢¦¥ŸÈSOý%=½&/oûÀ?ŽõMÝIO<1Ób O˜°¼5}ìØ/jkÓn¸aÙ 7,«­M»úê/;RúìÙðÇ?Ë¿±­)SàÒKaÜ8°Ûᡇ`Ò¤“çüq˜<’’àŠ+`ÈC鯽ÿù$$@QÜ|s‡ª(?XòòN}B]èÌœCN:žê8ñ%N#„:îíâÿ³÷æáM•éÿÿ;çä$çdiÒ%mn´Pö²–¢€8 ¢ˆàèwPqCqÑŸèÇQçëeu\Gfæ'#* 0¬¢@+KA ìÝ÷%ûYrÎÉ÷Ôn4iS ´ð¼®^½’;Ožû~–“œwží— „ÐÞešd='áÒѰ‡P5ç·Fš’z÷ˆéÁýªV`8JÇé ¡d5…UUÇJÜçª)¯¡7ÄEEë ٯȪ*‰>—%0ZQñÓZ=ËFPЕ•T»‚1*Z0Š]µï,ûËE*ÙC¨¬[‡Ï>úuíµ»s»ÈaúIK„NGÛU#Ûá*B‘Ÿ$+ŠŸ¦h~†aôΠgô^Tí¨•y>?£Ñj)²¢¨ª_‘Ÿ¢úô:F¯£ ‘TÚå“=’\£B°PQÑ^ë‘|¤†/;Ë—cùò0ì@4çå—¤- 3k Bg@~í"\¦ï5=§×s‚ ˆ¢@ñŠ_%EU)™ÓPïw»yÕçg4 ­ÑȲßåñê(0Ððk-EQ4¥øAiT ÖI~Ù¥·D{MV¥S}dðêòìÀÉvDI Ds^æ;D@ º÷÷±–1pAyAÐrªŽõ«~™ç½>N»ZSm—¼>½ª¥AùUø|²†ÒP”_£ñSP)ªäãIf)Ò{h­‡Óéã41=œŠF¦9J&|Å@~> Ý+hßZ²@ º-×'+>É'¼¢*,«ç ,­¥eYñò‚ÀK¼W”DEU4ÐÐÐÐ~hE•%Ÿ"ù «Š(‹^Qà%ѯQ8¢¢T[ŒËQ¥×¹ &fH :¦“ߨÑÔÿu‘8»¦ßÍ›FæÁj5Üð.c5^Œ^ѹÁt© ‰æì,Â$ÂUBmm­Óé (ˆ’ ŠMSg`9ŽaŠ¢´Z½äSDIQý¥¡)V(²¬ø|UÊERdÉ/øü>J“Eí`¹Õ_ Mß_ãñ’&tqÇfB³h¾ø"¼ŠjµbíêËØ4]§c‹„tÝö %U@ ®xÚ½@“,æ$\6( Š*FFÅ‚æAàyÑO© à“5²,ûý~ŽãX†Óq¬´_¤ýÐ@££#ËÒº¤¼ÐI1F#3_D´isÒ:‡JiXFòˆM}••—;~¼¨¸DQ³É”–š:4cÃ0‚ ìÏÎ),*âcÙ¤ÄĬљ,˾óÞû-¢%çsþJ~ü â‡Úk¿xh4W×íòàá‡ñá‡xðÁKç4?‹cËTW£O<ÿõ¦)[·m·Z­¿1ã8žçåÙºmû­·L%"³Óyí5<ýtvBgñõט:ë×_:Í™Ÿ ðä“X²±±8pK–t\sº\Ðé.V¹K–Q^޷߯¬Yؼ9ìL>ÿo¿5k0x0ŽÅ}÷!&wÞÙ;ÃüùØ´ cÆ´œ¨2W¶séâë9ÉôZpÉ ƒœ„ËILltd”EQ¤ªêj·Ûãu‹‚àóûiVg`( ~•Ñj9Ž3rN§óûd‰÷úUÙ¯ñ{%©ÆéæUÚ F5GÒ¶ˆ´ '@GÓœzŸSôÖ:›úºmú­é}ûFŠ¢Ì&SÖèÌ’’••Y™™&“‰¦i“É”•9ª¢²’4M§sú4NœÀŒmÛÿùOŒˆ¤¤à£êþðÄÇ#.óæÁû˼i_~‰~ýÀq5 ‡×ÛÂÍ7#&z=F—_6¦ÜU·s5š àñÇ› ¯¿ÞhOSš>}ï=Ølˆ‹ÃcAhëFOQð—¿ 5QQ¸ï>¸ÝŒ€×‹]»°z5vîÏwöWH¿/¼€GÅ‚HJËbìØz!¬Þ‚•·E{u¸\m6·V‹„<û,öì •^’°`ââ‹•+¼û.V­BVŒFŒƒ7ßÄ;ï„êÏáöÃ`õÖü BEÅÅÕ–dgwÑœa*T²@ º'²OÖëõZ-ãp8Ÿª¥Í0:ƒÓhü²"ñ‚×åqñ"OÑ”%Ò™¬Ù¨5FëQU·ª:|>‘Ò‚5(´Î#)‚¨PÐÑ`¿FV[wªªªÓéÜ»oÏž=ôNIÉùé'·Ç£ªªÛãÉùé@jïÞ”Ÿ|öù»|øéç_|»qS~Ai¯_Ã_ÿŠ @QmØW­ÂË/ã7PV†ï¾k¬XO?­·7Ì' <`ä8Ž´cû©®ÆÈ‘ÈËC‹j»Ðž–†µk›Ý¾HIÁÖ­èÛNžÄÍ7ãܹzTT„„ðza³Áã€ÔTÌš…oDß¾ˆ‹k©uÛ¿Ž.5›77úíß¿þ!âi±F®aÊâ©SõéOŸÆM7áìÙPñôï –••ÈÌDè=‚Å àÁ1|8o¾‰Ü\|øag¶l0¿ — ,ÛÞv ]ÞVÛ+D¹‚µï…öŠ:!;wÖ‡Ñjú>}°q#ÒÓëÛ1=½>MÃçkìfн²´?‡g°z 7ÿÇÃàÁ0™°t)rr`2A¯‡Ïב½”ˆæ$š“@ \µ‚“hNÂeÖœR¬É`d8³–—±=,³ž3ëÌ‘&½A_VRVr²Ôžçàó]:A1±‘&½ÇkWU™Ñs`X^e$6Ò©ð%¥9£âjtœÖ+”ÞÆ™hÁO{Ųý;·ýiæ…ÞUUuº\‡–$iÊäÉ›6o1™LÇfÖs<œëñxnžrc‹w9œÎ/ÿóÕƒ÷ÝK4gX¼ ^|±m;ÃÀá€ÁÐ2%ËÂá€^‚€ÈÈúé”Á4^^–/Ç8y&V¯ÆÌ™¹Qæ8Øí~9®þáÆ£Ñ@êÓ‹""#›M¼0ƒ¡Ù|QŠ‚¢t$NUEÈÎFr2òó‘•…²²VF›;L0¿=zàÇñËŒ¶Û1ty/¬ŸÐå Ks6¬ç,)Á_ÿŠ3g°qcÐôMË+Š`ÙúV+ `±Ô'³ÛÑ»7êê‚öçpã Voáæ¢" øãQQÕ«qíµ8žh΋Eן[K–t„K!N‰à$\nh//Ò´Îj–$Åéñð¢ ù$Qä)ŒŽâŒúÈk\Øh[ŒÞ`Ðh£Õj±År–(EËx$Eo¶hõœäSEI¥(¥a}Š ¾õ›Š²Z,׎SXT  ¸¤$+sTÃzÎ1£3KJK[ ”¢È½UÇàyüýï­lãÙª=1Ç·’I|< ë">¾ §ýûãƒpèœN¬\ÙÒKûo”{ölæ·Íx8®QL5˪iú^½Z*™+‰âbTVâ¹çšµ×O '²³ñÄxä‘Pý9Ü~¬ÞÂÍæLÌ™ƒ“'Áó˜<ÙÙ˜6­ó/y²‡Ñœ@ t!DQ¤(Z–UÞ+²¬Éb2™Ì´–Vý²¢ø´:Š3ëµzJ’·Û)‹’*É"/ºÁÍûe>¿äUQÖÑ4Çrz†ÕP”BQ²F£ÒZ×ìh´Q#FÏËûì‹/>úäÓM›7ëuº›nœ `ò “E^·þëþþñºõ_+Š2yÒ$ú÷ÏùéÀ'Ÿ}þÉgŸíÞ³'=½ï˜Ñ£I“…‹ªbåÊ–ê+„}þ|<ûlýV¨7ÜP¿¡K@ÃÄÄ #ˆÅâÅmø}òI,[†˜$%á?ÿiÜ·6À«¯â„N×öñóÏ#!2&4ÓT­ÆóöÛøê+DGcòdÜ}w³¬ÆÃ AÈÈ@bb3¹`Õ*¼ù&¦1žùóqÝu˜6 V+{ ÷ßßÁ8ׯo¦ßfÌøµÚ¬~SS±k@f&L&ÜýxZ°z ·¼á–+Äþ·K`ßãóç±vm¨ôÏ=‡~ý0bÆÄ‰ÐjµèCaæLX­¸ë.Ì›WßúÁús¸ý0D½…•ÿk¯aøpL˜€>}P\Œ^hÌ*D…E]]}  ;¬çDXsÞZ¬ÝjºÔ“@ \Á»ØÉB„.NÃzN‡‰µDšY£Î#9’Òâc{XX£Œ$C¨««bÙÑJo¾‹q©V Ý32ZðzµŒ^P`ç%»ÛçRÙ«MM—z¥x"£¬¹RRiž’£ª¨g~Þ4gÂE*YÏÙNÖ­ÃgŸaݺöÚ „N¸ÑÿE2]Ôéð%%7®ÙbÈîÿ¯ &˜}õj,\ˆ½{1lé‰dœ“@ tµ)´&>‚Z–L¸%tž,ð¼ÇKi(-ÍØkN‡[–šfôz}DDk`¡…B©-h-¥ñ«F=kdôzÐz•2ÒŒ‰b¤:§P]ãw»5¼ (>Ù¯øüª’Ejþ IDAT×§ˆÁK!\B–/ÇÓO‡a'~=í<€¤cÜsNž„ÝŽÅ‹qÛmÝ/þÎ &˜ýÃñÖ[DpÖ£íA²d‚@ W6’(ñ‚ ËJï”´Šš"AÅ@Q44ÚˆˆJ¡M–Z·ÎéóHªŸV|²AÇÊ’,{¼:•Ž1˜;/Û0×êmNÑì e}ªFKiý´ªhˆæ¼ü4ØN;ÐÅ™2'B’0m–,!õÑ’C‡Ht3ÍI ò«áòÃêµ:†ÑiuZZ-J»Ã¥7ZŒlm])­Ñ,&ÊÀðÕN‡ ±¢,¡@û$EV4Š×'»%Éi—Ê´²Õª1pzZ£ñù Ï™-§ud ÐÉÌžÙ³I5ˆæ$WÃú¯x•@è:(²¦4uöZ—§Îb³"Þ-TU(²jRUʯªæ(«)Úâ-¯ó8½IU 7±&gP5´ÏçWý”MdÅïvмâ‰ð³Lêgi>Iݤ† K‡O# q¼a€ÎHy¹NM¼H~7oƽ÷¢²²½™‡X‚Vx—±/F¯èÜ`ºT]–+m='«e™¬Þ"B7C•%Jã×iµ<ÏóÞlŠˆ´FûUÊ^ëP|~YñS,£àt&VÑBTeE«Ñèµ4ÇÐz-­Ó0ŒßjÔE0ªß]ã-+ôU–Z1 >Ê]§¸êhNBW§ë,ÛëÊ,Z„/¾¯¢‚-A ·uHÇ éºíáÊçlu2ÄA „nÇã༜žÕ1ZÆa·ÛkLÑz‹N«çEQyÎlðùýZËE›½u^QõÉzZÔú%¿$+ŠÏçSU•eaÖh¼¢ËU&)ª/šÕ™9³*ù úÑÛÔWYyù±ãÇ‹ŠKE1›Li©©C3†0 #ÂþìœÂ¢"^8–MJLÌɲ,‡Óyàà¡â’žç­ËèÌQ½SRH«u˜ÄÂ…øá‡öÚ/—küêÒÓ0¥Ó¡GÜr –,Á¥9·!?‹cËTW£O<ÿ·Fòø‰õiÔEhU­Ç!– Eç5ÕœËaôºõßÔ×þ윤Ĥ™wÜþà}÷N½ù&/ÏoݶÀÖmÛ)šþíŒésî¿ï·3¦S4°;Žõ_cµXfÜ:í¡î¿aÒÄ'O’&û5¼öZë{Õ³:…€´ðx°g,–Ž ¿pç„ 6 ûöÁéÄûïã“O~Å… :ÝÅ*W§äóùçxûm¬Yƒº:|þ9Þ|ÿügíóçcíZ(JKmIÆ-¯fÍÉ6È$ኢ¶®Úé¶»œv·Û­ñkuÎ’‚’ºÇš"LVU­c ‘fsŒ•‹ŒPt”ÝçuÁ§ʪ¢SXc63zÊ J´Ëî)8ï-È×9ꌼG/6Óœ·M¿5½o£ÑHQ”ÙdÊYRR ¢²2+3Ód2Ñ4m2™²2GUTVÈ9p`hÆÇY""hšŽŽŠš:e i²sú4NœÀŒmÛÿùOŒˆ¤¤à£êþðÄÇ#.óæÁû˶Fƒ/¿D¿~à8Œ…Çëí‡á曽£FáË/Ó7=ø^ÓÖ>S‚€ÇG\l6¼þz£=D*]„ÊŠòüsgËËJ«+*ýŠÂêX{óäÉÓçÎ嫊ÆáôúT¿FK3FÖcÕEšŠèÑÈ”Õ@Y9·Fô¨<Åiüª${ZÉkT¹²¢îäI¹´Tïppbë÷õªª:νûö÷ìÙ@ï””œŸ~r{<ªªº=žœŸ¤öî  ¸¤”a˜µÿþÿßûð£Ï׬ݟ“#Ë2i²ó׿bÁPTöU«ðòËxã ”•á»ïTyñE”•áða>Œ¢"¼ôRck×bËTUaúôÆ ·ßŽÙ³‘Ÿ‡+VàÓOëí ƒ9í<qéR"7¹¹Ø±£Ñ"ž`lØ€#G›‹¢"¼ür‰W¬ÀŽؾgÏB«Å¢EŒ³YFa!^x£FµK›5ýë€ß­[ñ»ßµ’>X½+o‹öêp¹ÚlëùKÿÊ+8}âèQìÜÙh?r™™O³²›ª?‡ÛƒÕ[¸ù»\ iÌ‹cÇÈgÒ¥@SSS úÒÌg¿T·†ížSG ®\5ٮϢ9 —™À·ð²e˶dçæy³%²o¿þæ(kRïdÉ/Ö¹jô투a¬YWå©q»ðú`«Î—>q*ÒlIê•Ȼݧ>aã ýÓÄ:¾ ¿ÔÉËŒ%Æ­hÊܼ­W’56®ÆY÷¯7ÿ·…ëwÞ{?ð Òj½mú­,ËJ’ï› *«ªöX›íÖ[¦êtº¿½ÿARb˜¬¬ˆˆÛ½w¶Ñh?vl Çq¤ÛOu5FŽD^ZTÛ…ö´4¬]Ûìö=@J ¶nEß¾pò$n¾çÎÕk¤¢"$$€× › ¤¦bÖ,Üx#úöE\\K­Ûþut©©Ø¼¹Ñoÿþõo O‹5r§ NªOú4nº gÏ†Š§lØ€´4¨¬Df& :g Ř€;ë³í‚ùe¸\`Ùö¶cèò^X?¡Ëb—à_™OŸ>ظééõ혞^Ÿ€¦áó5v3E^YÚŸÃ3X½…›ÿcað`˜LXº990™ ×ÃçëHHá^JW'd='@ —ƒÎh1XЪ$ Nw]u åטIôŸÊ+°W»…Z·äpkµ”5)Ö˜cMŠ3ÅD:œÎêòjJ¥½èƒ(«ZZgÒ³&¨f­ß¨•hŠÇçu]èqÞ܇yhÎÝwÎŒ‹‹Ýõý÷¶íØ;{ÖÝsç<8{ÖÝ6›mÛŽF;aüø¨ÈH-M[,–ëÆ;{îÿúW#/+kæ·=ñ£!}RRÛé ѧOý0c\Š‹;'~éòùŸßþ?Þ™-ÌoLLëe Voá–·ËV>%%Ål(³®&Ÿ7.ÌæPý9\BÔ[Xù¯Yƒ{ïÅ=÷`Ò$<ð**/ÂU®9É’NÐ^ÈdB·ƒ÷zZgâ Š(ñÏÙS§ªÊ«"LÖžñI…ù%?çæÕ–T©¼¤¨ŠH«ª‰1ÅEùu´Ýá°Wש’ÊqfUÃH Fgæ83«³k£¥%It‰Wë7eµX®3¦°¨@qIIV樆õœcFg–”–ˆŽŠ& Ô9­ÌãïoeÏV퉉8~¼•LâãQXØxŸ߆ÓþýñÁ8tN'V®lé¥ýƒ3={6óÛf<ר{‹ŠZÊȆ½z5{‰ãZ®ðLIAmmãÄHEé`œ hµHNÆÒ¥Ø½;T>áέ æ÷†ðï‡ÑŽá–7ÜruV>½záü/?=5‰299O³³1th¨þn? VoáæOQõz~Å ã¶ÛpÏ=ä#ŠhN@ ®htŒ~(>¹¶ºJxÁËÛkk=.7«cY†«©¨®«²+¢ÌhËqf³ÎÀ‰ŠÌ‹¢OQüÅh}PyY’á§´( Mk",&–c´44þfË/¿Ù°1¿ @”$EQìvÇÞýÙ±6€X›m_vŽÛíVUÕívïÏÉ Øôï·}×®ºº:EQÇîï÷ƒR:ÆÇcêTÄĴ˾`æÌÁÞ½ðzqêæÍ«·ßqžyåå(/ÇÂ…¸ãŽ6œÞx#6m‚Û Q„ǃ¨¨–ÊaÆv ›»ïÆ3Ï ¢eeX¸°Ñ,žaÃðúëðxPXˆ§žj–U }Ežy¿ÿ}³—†ÅÇ7‹gî\Ì™ƒ³g!ŠØ»Ó§w0ÎeeX¾¡òiP}Mÿ:à÷¥—°jV¬@QDÙÙ˜:5T½…[ÞpËÕYùÌž'ŸDq1*+ñÜsÍÚë‰'“ÙÙxâ <òH¨þn? Voáæ?s&æÌÁÉ“àyLžŒìlL›Öù—<ÙC¨›jN2ÔI :²˜“Ð…ˆ‹óɲÝn/.)½|t¤~qAaiQqÏØ‘æHÑ+zœ^†ÒÇÇöˆ‹ç8¥¥)½–1è(–áe÷ñnÑ#ªï—Ý¢—WD³ÅbŽˆ°XÌ:-ÝÔר#Žçå}öÅ}òé¦Í›õ:ÝM7N0ù†IŠ"¯[ÿõÿxÝú¯E™[¿ê 74n óÒKˆ‰AF22‹Å‹Ûðûä“X¶ 11HJÂþÓ¸om€W_Åÿ®í;ãçŸGB220d&Lh¦©Zçí·ñÕWˆŽÆäɸûîfY‡Aƒ‘ÄÄfrÀªUxóM0Lc<óçãºë0m¬V<öî¿¿ƒq6€À¾¾çÏcíÚÎlß`~SS±k@f&L&ÜýxZ°z ·¼á–+Äþ·­æ,ýsÏ¡_?ŒÁƒ1q"´ÚF-úÐC˜9V+îº óæÕ·~°þn? QoaåÿÚk>& Oã…³js‹àvRWWßèV{…qH¦ÕW»š$º {íÿ9§  ŸeõZ=Z“œ—ÐS«×ÉPm6[d”¹¢²°ÆY7(s8¥¥kŠË½ÕŽšó¥5E%ž:wtdtgª)©Ô©«e}’Bõ±ýÒ$UãqK?>¾é?_]¤"=„Úɺuøì3¬[×^;Ð 7ú¿H¦‹º½MI ÆkœjÛíâÿ•Á³¯^… ±w/† #=ñ [ËjYA&#¢B·UŒ¿üW[EŸÏÇhµu5öC>‘'x<•Ó'Ož9yÚÄ™£#cE^.Ê/ñ¸¼ÖÈhC„™µ˜¸( eRõàs+¼KJ‘u X­c¼‚·ª¢Œw9I _v–/ÇÓO‡a'~=í<€¤cÜsNž„ÝŽÅ‹qÛmÝ/þÎ &˜ýÃñÖ[DpÖ£%U@ Âe§Oz_Qì‡×Ës++J]U Ã0I½SRz%Úu.»Ç`5êõ”ÛÁ{<%‘³Ën§XÆ–ÐÃ`2¸œN?E+:J$Yp+Šßjàd@tŒÖÀêH _v l§@èâL™‚‰!I˜6 K–úhÉ¡C¤ˆæ$W;db-¡k_S]%É>–e F4‡Ã^YZ®×êâ¢m,Ãz\¼Ÿ¢ Qfš¦ª«kTŸl`õ±ññ†©­ª*<—oÔq^^pպȋ²^£HðƒÖ0zï{ÐÉÌžÙ³I5®LÍÉ’;Eኇ\á„«YURÒÒL”F“ÐËËó'Nœ(-+++.µFX{%%¸%MEyM„¢&õMqº]N§Çl6™#­œŽñ)r„Óib ¼è“ýÉïTd¿¬¥<ïôxD[’}¤† Kû·hç/ÒʽÇÙ5ýnÞŒ{ïEee{3±1¬ð.c5^Œ^ѹÁt© ‰æ$„®ùéŠÐ娨¬4`PrR’Ñ`_JŸ´˜È˜²ÊRW¨®³G˜ ÃY"XËšM¬G¿b ªíŽŠÒ2Éî–E²>šÐÕ Ü¯“ƒ%B³h¾ø“&…]±í1†›É¥ì]¹‹’®K4'@ ݃£GŽzÝž´ÔÔÙ÷ÎŽ´F&&%8ƒ^Ç}¿{wEYå×ë¿yÏïÓÒÒÏœûißO™c3öRTš_RZÎôNJêÙ“÷ :“É©0F“™—‹‹K5UÕu5ZŸ†n~3TV^~ìøñ¢âEQÌ&SZjêÐŒ! °?;§°¨ˆŽe“³Fg²,ûÎ{ï·ˆV¯Ó=xÿ}¤Õ:Ì?báBüðC{íË5~uYÈÏÇâÅØ²ÕÕèÓÏ?Y³º™ß¼<ŒQòoL:zôÀ-·`Étì\‹U«ðÆ(.Fb"žz >zùûa«ùú)-BQQˀȸ%Ñœaغ–œ˜B \©4ŒÚ‹œpePW]“]QY[Wk‹xôøÑSE¥ªJqF3Ű>ß‘’–f޶ÚbŒ‘–¦¾n›~kzß>F£‘¢(³É”5:³¤¤@EeeVf¦Éd¢iÚd2eeŽª¨¬lgAa¡Ûí4pi²sú4NœÀŒmÛÿùOŒˆ¤¤à£êþðÄÇ#.óæÁë­·k4øòKôëŽÃ¨Q8|¸Þ~èn¾11Ðë1j¾ü²1}ÓƒïÛ¼Ã<þ8ââ`³áõ×í!âiJÓ§ï½› qqxì1mÝÓ) þò¤¦"* ÷Ý·»ƒq¾ð}  ) ,‹±c;"¨:Ño°z VÞíÕárµÙÜZ-ðì³Ø³'TzI‚ˆ‹Cl,V®lLðî»Xµ YY01f Þ|J?‡ÛƒÕ[ò4W[¶§DDs^Cÿ„«âJ'sݬkÆŒ½ný´ÞÞ0Ÿ°G .]ŠÂBäæ"7;v4ÚCÄŒ pärsQT„—_n#ñŠرÛ·ãìYhµX´¨ƒqnÝŠßý.lµÐâ¯ý«·`åmÑ^.W›m-Ë(,Ä /`Ô¨Pé_y§OãàA=Š;íGŽ 3³É'[rsCõçpûa°z 7— 4¹sqìùLºhjjjDwl¾öåmßP^xßI&ãDs’ „]ŠÀ·ð²eË¢Òãívû·6TUVÅÚbS{§&&&öêÙ³wRrrRÊ¡ãG7íÜQPRìóðZYÉ1̯§õfÎ`5s&N‘•SGWWVöÐo`ÆP½ÉX\Qvæô™8S”Õh„_­)­xë–µpݰJ3Òj½mú­,ËJ’ï› *«ªöX›íÖ[¦êšÌä;rôç¢ââ[n¾©i>Ç‘vl?ÕÕ9yyhQmÚÓÒ°vm³Û÷))غ}ûÀÉ“¸ùfœ;W¯‘ŠŠ^/l6x<šŠY³pãèÛqq-µnû×Ñ¥¦bóæF¿ýû׿1D<-ÖÈ5LYýéÓ¸é&œ=*žþý±aÒÒ ²™™((èHœ — ìEûø×o°z ]Þ ë't¹BìlóÕ Ø¹³>ŒVÓ÷郑ž^ߎééõ h>_c7Sèõå ý9Ü8ƒÕ[¸ù?ö†É„¥K‘““ z=|¾Ž„î¥tuÒM×s’SpEQYYY]S£¥ƒÑTTRbw:½o¶X &s|\¸Ú*^äýøù|Þis„%1-ù|y…%®G”¤¤©ý×åž°;EÆö0,Þêó1ºbÕïçŒEõnÅã¼¹«ªêt¹>¼ëûï§Lž¼mÇŽØØØ)“o¬çOÛbgL ÊÊÐ|ä¾3 ×o°z ·¼X®†õœ%%øë_ñøãظ1hâ’’Æb6]ßm6Ãå‚å—éü.ÌæPý9\BÔ[Xù¯Yƒ¢" øñG<ðV¯n¼|ƒ+|n ™IK „n½®Ž¦éØñбºªêêóùç=²uǶÿløêû÷TÕT±͘ŒeE%•¥Õ)ŸW9~äÄ÷Û÷¤%÷™0v‚F¡Îž:[RRæ×P–ˆä¤¤äääȨHA[¿  («Årí˜1…EÅŠKJ²2G5¬ç3:³¤´´!qöO?õíÓÇjµ’Æê0<¿ÿ½•m<[µ'&âøñV2‰Gaaã}v||Nû÷ÇàÐ!8X¹²¥—öÎôìÙÌo›ñp\£î-*j)#ôêÕì%Žk¹Â3%µµ#¥ƒqÞpþýï0+ܹµáú Voá–7Ürµ‰V‹äd,]ŠÝ»C%ëÕ çÏ×?n:;drrŸfgcèÐPý9Ü~¬ÞÂÍŸ¢P\ +V ¸·Ý†{î!QDsvð¢a!ÉI \]²-K~o"t; ‹ŠFãÈ#2†8xpTLTiYÙÞ½{wïÞýóñãZF7æÚk³®’’aU$åøÏÇK‹K{%õë3 º¼æ“?KNè}í˜qgª«sèt ÃèNž>yæÌAXc³™Aßlؘ_P J’¢(v»cïþìX› @¬Í¶/;Çív«ªêv»÷çäìêêêÎ;Ÿ9r$i©_ÃÇcêTÄĴ˾`æÌÁÞ½ðzqêæÍ«·ßqžyåå(/ÇÂ…¸ãŽ6œÞx#6m‚Û Q„ǃ¨¨–Êaƶ… €»ïÆ3Ï ¢eeX¸°Ñ,žaÃðúëðxPXˆ§žj–U }Ežy¿ÿ}³—†ÅÇ7‹gî\Ì™ƒ³g!ŠØ»Ó§w0Η^ªUX±EEEdgcêÔPù4¨¾¦è7X½…[ÞpËÕ&Š‚²2,_ŽŒŒPÉfÏÆ“O¢¸••xî¹fíõÄÈÉǃìl<ñy$T·«·póŸ9sæàäIð<&OFv6¦MëüKžì!tuhN@¸@“’iù„®É±CGöíù¡ ¿÷x‡f ›pýõÉIÉ¢$UUW•—W8Ž>iiɉÉq±ñ ŒŽ‰á¡¬´¬(¿¡´ú (.,Úùß”Ÿ2è8Ýåóú† ¤×²¼—7Í1ѱM}1âx^Þg_|ñÑ'ŸnÚ¼Y¯ÓÝtãd“o˜¤(òºõ_ð÷×­ÿZQ”É¿œ=ÿÃÞ}£FŽÔµ8¥ªŠ•+[ª¯öùóñì³õ[¡ÞpCý†.ƒŒ dd 6‹·á÷É'±lbb”„ÿü§qßÚ¯¾Š?þ:]ÛwÆÏ?„dd`ÈL˜ÐLó´ÏÛo㫯É“q÷ÝͲ7ƒ!#‰‰Íä €U«ðæ›`˜ÆxæÏÇu×aÚ4X­xì1ÜãLMÅ®]8p™™0™pÿý<®®ß`õnyÃ-W°ýo,}ÏŸÇÚµ¡Ò?÷úõÈ<'B«mÔ¢=„™3aµâ®»0o^}ëëÏáöÃõVþ¯½†áÃ1aúôAq1^x¡1«Uuuõ D@·ÝC¨]÷ŽY€–%7˜ÂU¤)e¿l ÄÍIèò4ì!´÷à>—àñ©ª­GßLúžãr²³>,ð‚%Â;hÄPKT”"øx‡ëüÙ³{÷ç8<îäÞ)™™£·lÜäv¹û è†R)MŸþ}Ç›óãÞŠòò^½ ø–Î^p‘Š@öj'ëÖá³Ï°n]{íB'Üèÿ"™.êö6%%7®qªm·‹ÿW̾z5.ÄÞ½6ŒôÄ@ ´.8Y-KfÕº#3n¹5÷ØÑm»vÖÕ9’“SRû¤õIíÃhuùçóOŸ:c·;¼¢Ô+))*2ŠÓëczÄ÷íŸ~¾ ߯*·Ó¯ÈÃF ;wölIQ¡ì÷ F–bJâ“"QÅb驼sNOjø²³|9–/ÃN üz.ªT»ç,Z„¸8,^ŒÛñz¦ IDATnë~ñwV0Áì~ˆ·Þ"‚“hNpõiR2ÈIè² 8¸Îîàôle]í{ö¸\ÎŒaÃGŽi2 ÏxÝž²âRI’k,Õf“©WBω7L<ðÓOeee¥%ÅŠ,]wÝ„øøØ­[ÿ묮¥ )/.ûaç÷Y£ÇôNL9rêxUy©áËNÃí´]œ)S0q"$ Ó¦aÉR-9tˆÔÁÕ¡9É*@è.|õÕºã§Oò‚W•}%E¯Ëåv¥§§GD˜ÆŽ»¦º¶¶´¼Òëv»].ŸÏ'ËÒØk¯‰Š´:tðèÑ£Ç~>šš–ú~7Ó`0nØô]AaaEyÅÑ#‡E¾óÎY–˜è¾!5L :—Ù³1{6©•¯9Û!*µ¬@–tWäz'tGvlßQZU.ûýV[4ÅÐv§ãàÁŸìuµC‡ É9Ü'+›ÿ»£¸´Ô'Ë.·3'gRRâôé·&$ôR$iÝ¿þõÍ7_8pÈÐ!’"ÿýžSy'¥JϮݻŒæÌk²wʹx„+—¡ËïûôÚÎzoÀ cÙcäÈ‘¸ôUt±ý¶3ÿ‘¿ì}Y*¡+C š“@ ºdÞ¡KCÓTrRrtœÍÏP5uu^Ñ ¿âpÔž;Öl2FGǤ÷M$±´´LKÑN—cËÆq¶è~ýûGÇDë8¶ª¤èû=ßO¾qÊÀAT¿€×ãõzÜ»wlg96öÂÓ9„‹I@g6Už„΢ë¼@$#ÉJ„«\s’}D„«KSÊ«%ª’Ð]3fLD”Õh18sмVK„¢(ï9wö”Vƒ˜˜X[\^ñq’ ˆ¢ÁhbKKJ¿úòËQY£ GRÂùÓ§÷lÿ¯,I#FgöìÕcüøñE?v¬¦ª*{ß¾~ééM}••—;~¼¨¸DQ³É”–š:4cÃ0‚ ìÏÎ),*âcÙ¤ÄĬљ,˳“Vë‚üšËîÈW_}µtéÒ^xaÆŒ—Æã…’côb—«Õ˜¿ýöÛwÞy§¢¢Âï÷7{µá¼?¹ÂW©ælךMò­H AJ> ]œÁƒû)›÷H‚`2(-¼¼×épxÜ®ªÊ {]ÇËÓŒ¾gxY–%Yä½ÞÓ§OIНWRR||¼Él:{"oÏîµöº¡ÃG$%¥\wÝøè˜˜3y'+*ÊsÝögç 0àš¬,Žã<^ï¡Ã¹[·mŸzÓ”­Û¶[­ÖßΘÎqÏó‡rlݶýÖ[¦³“V#\vvíÚ5vìØ]»v]2Íy—ëµ×^[µjÕ!C4-N¥ô7WžÂÕ§9ÛSD–Œ~W•¸ @®yB÷BÇ0%åeÅ…n·Ëk““ÝQçWdøÆïñ¸Žý|´g¯¤ž½F+ÉRee¥×ë©®®¦uLïÔÔ‰“&þ×hÊ?yòPvveeÕ5׌sÍ5 :‘w|ó† '~þ¹©¯Û¦ßÚðØl2eÎüôŸ¨¨¬œ2y²NÇ0™LY™£>ýü‹vB¸|sl÷?l,¬+‹1Zç^sûôAȪòæ÷k6ßà–ãæ¿[KÑøeÄrú  »ÎÐi™g'Þ?9= À©ªÂ•»¿ø¹ü¬WúǦ<0zúľ™h>‘µ=£•îÚg¿}ódeÁýÆ4µ‡Ž§é¤Ù¦ù/Þüî–“ûúÅ&¿vë‚£5„_YUV}¿vÉ=²ªÜÐ7ëéëïa™PgùH’´bÅŠ­[·ªªúÀ4ûÀ„¬Y³æî»ïEQ¯ïÌ3Bø Æwß}÷î»ï–——gdd¼øâ‹={ö ØG޹`Á‚5kÖ8ŽyóæÝsÏ=X.žçßxã;v˜8qâ“O>Ù0aË–-Ÿ}öÙùóç-ËÃ?¯ Sa/\™––V[[ÛRpvˆ@æd'ájÒœ@ tyœN§Ëép»É‰ ѱ±e•eª*S”F£O ƒ–ö ^¾¦ªÊbˆ°X<.·†¢Qt¹\Š¢>ñþî?uêÌ– Žçæ–œÏçñß?3v¥Õ¨P[uªªªÛí>x87psÜ;%%ç§Ÿ†Í0pœ—çss¤öîÂN‹/l[²åýq½‡½uû³4E¯ú~m@s~´ý'9ß>7éA¯lûȤ7Ìs{û®Iɸcè¤û¾xᵟ4çÿ·þõB{ù'³– ŠK=W[òáþ¯š3˜ ÆŠÝkç=7éAÕ߬{„Ž'ýc{÷íýʶVî^³ôæy!R~´ýÇ9ß,žòˆ^«{nÃ*“ž[pݬéßÿýòòòµkתªú—¿ü¥éKûöí4hP¯^½¸oß¾ &´©‚ZB…ðŒíÛ·¯X±"..nÍš5ÿ÷ÿþßÕ«W7 õoû›ÙlþóŸÿМU®¿ýíoÕÕÕk×®õûýK—.}ï½÷æÏŸ`íÚµëÖ­ûóŸÿœžž^QQñü# 9a¶(»×ë¥(êå—_NLLLKK#,hÎ#QB+4ù\ „n€ß¯ŽÉÊêYÒ3¾W¼äW½¼[§×š#Ì<ÏÆÐZQT’$ÕÖÕôNKí›Þ÷ÔÙÓN·@~~þ‰“y3ïºsäÈÑf³Ùdúùçc?ü°§¶ªvÈÐÁ‰)½Æ]wí…ßyïýÀƒH«50ò9~ìØo6l8òËf¬Í˜@ÌN‹Ïl°ð7÷ÚL‘^œ27`ÿæØnSú h¼o~ÞÝTãÝ>ZKiT¸jëµOðIö77õ¿öš”ŒW§=ѱx² øõ˶Ü`O0Òï+8:e ÿÉéY4EØ|roh͹yóæÕ«WGGGxòÉ'¿ÿþû†—víÚÐc×_}Ãã`„;æÂo°]s^}õÕÀƒ»îºëƒ>húÒŸþô§^½zxûí·;·\Û¶m{ûí·ù<õÔS?þx@s~ñů¼òÊ Aƒ¤¤¤,Z´(tyW­ZuÓM7 †… þãÿà8n̘1ÙÙÙë]d„“påiÎv¨R2½–@¸j`Éþa„îÉɼ“&“)±W‚JV}={ô¬®«±;ê,‹Ù!¢_¡EEt8œ>Ùg±Z fMkµ c0f³ ߬ýשã§úö0iò ÃGŒ<óÓ¡œýÓ- þBóæ>¬ªªÓå:tøð®ï¿Ÿ2yò¶;bcc§L¾!°nóàáÜm;vÞ<åÆ`vÒjaQê¬ÐÓbka¯p׈`¿<­múªŽfZ¤ÿß[mç?¶ŸÉÙ~&GG3ÏO~hÆà ˆÇλšúmg<ÁhH_Ç;C§ ä?vÕƒ§åΚÐ髪ªâãã{ôèÑ`WUuÏž=sçÎpÝu×}øá‡ªªRÕYíÌï…‚* AóòòÞ|óÍ'N8­Ô@Ã<ÛN/WMMMÓ|ªªªê+¶¼<¬áÊï¾ûnÓ¦M,Ëæææ.^¼øÙgŸ‹‹#—-hÎvÝz~ùOD'p¥B~W"twtŒ®¸¨HCÑF£Õ3Q‘Ñ‚(9œNF§×s¯‡Þ¯RŠªÒí÷ûuzÇq4ÃX, M8úLµÝYkw è? G|ω×OÌOìí<……E¼×ÕªSŠ¢¬˵cÆÖg—”ÜwÏïu:“É4ftfh;!,zFØÎÕ—:ªR¢šÉXST‘½Â%zý~?€8STè|2“ýëÞÿ­ó:¿<º}Õ÷k_ßõYÇ4§…5U{ì.Ñ8\§ñ¨~¿¢*æÖÞÊ™ŒFç‘xQ–ôZ]‹ü÷<þ¡YolOœ6›­¼¼<)) @YYYƒýÈ‘#µµµÓ¦Mk°=ztèСÁò wnm0¿ÁxöÙgxàeË–™Íf§Óù›ßü¦é«.’ì¬rEGG7Í'æ—ƒ‘âããÏ;7pàÀVߥÑhü~Ó¨(Šª¨¨HNN~úé§çÌ™óÔSOMJ¦3: êŠ(EÐ ŒxWì/¿| -Jè >œ¡™sgÏVWW‹’O§c &Ëh­Ž3šLs„E§×ëtz³ÅbŽˆˆˆ°FX,16›Õ hÅï×2nŸ.ÿàƒ„ß?æšk† KÑtS_ßlؘ_P J’¢(v»cïþìX› @¬Í¶/;ÇívÖyîÏÉ m'„ÅïGÜ`ùÎT{ìu^ç«Û? ا `óɽ[Ní0mÐøÐù<úåÿ+?kÒ²’àšoÀm°(´—·Ïè¤A¿›ó~ljO¬) À‘²ÓÛN·2ß²!} ªýb“/ù›²XÅúþ¾ÿx$þ\MñŸ7¾:ΛnºiåÊ•µµµÕÕÕ+W®l°ïÚµkîܹ~ᡇÚµkWˆ|´FüC„¨¨(–eKKK—-[ÖfúÎ*פI“V®\YSSSSS³råʉ'ì³fÍZ²dÉ‘#GA(((xå•Wšý²»gÏUm\Ê;yòä%K–ˆ¢8f̘cÇŽ?¾Ã½}äÈ‘äÜN•§9 ¡É?ù½‰Ð 5*³oz:ÏóUÕuµv/Ï3ŒÞ`ŒÐsƨ¨h[l\ßôþ±±q”††¬ž‹‰±EFF[¬VsDÇt¬žâ8P-M‹¼˜wüĦ ›Î=ÏêÙ¤¥öiækĈãyyŸ}ñÅGŸ|ºióf½NwÓ“L¾a’¢ÈëÖýÁß?^·þkEQ&OšÂN‹ÿ3ô†—¦8º³1î>eÅî/Æ®zð‘ÿeXÏôÿ½åñ¦¯>>þ®XSÔŒŸlºm«öå²Ýç]˜Ûñòs+w¯Ú3}þø»Œÿ3é!=ú¼¼õƒaËïnˆçÁ¬û»í§s®kî³ß¾y]êˆÐq>ôÐCqqqwÞyçÌ™3GŒÑT›5]èxýõ×ïܹ³Û+˜ß`¼ôÒK«W¯?~üþð‡Ð+0;·\<òˆÕj½óÎ;ï¼óÎÈÈÈGy¤¾ŸÜu×ý÷ßÿꫯNžòûî?røÈßïúêlž9Êrñ4'@¸dt©ý`ƒ³~ýúÿùŸÿ!‚“piNpUéK¡ûR^V^^QQPZìtºm¶Xø5µuÖd¦uZEõ‹>ŸF¯Mꕘ˜”Ä Û·m­ª®¦t Mi}>Y”|ƒ‰w ªQe(­TMuÛéîÕ£Wï>}Žjï"5L . _|Aö#\±š3Ô)äN”@¸ÂÕ¦,°Z–\é„nÍþýÙÅ%%’âKOï7}Ðo;z4/¯´¬"½_¿´”>uµµÕU5çÎåLFƒ)bè¨ÑÃGŒòS((*ª©«u:\Ðhbcck©Z—_ã“”’’R“Á4hÀ „Äd­‘«¨,#5L ¢9/‘0%WˆÎ ~]“k Ý‘“§N³6)%9!9¹WrrAI‰Ûá.+®02Ƭ¬k)]U^[RQIké«%1¹·-.MIY…½¦Î'IœÙ Å ¢O”DIŸ/û§ŸÎÏçyÞl2 õ¦)[·m·Z­¿1ã8žçåÙºmû­·Lýaï^žn½eªÉdr:?ìÝËè˜~}û’V#\^ºHQ”êêêÿûßúÓŸÞzë-R®óÚk¯­ZµjÈ!MóS8ýÍ•'pukÎvܤ’éµÂGÃEb…'Ðõ9rä¨ËíªvÔ±,k´X"µ´Gòù5´^o4FFŸ8ö³[•=•Ü'õú‰¿6bèùü|-CÅØ¢{õêÅ ‚Kôø¨ÿÇÞyÇGUåýÿ{ëÜé“I2iB !Ä`E@A„AÝgwÁ²»¢ˆ«T "úCEİŠI`YŠ" KÙ}Üçq A)ÒK¢¡“FH&ÉÌ$Óo¿¿?F⤠†~Þ¯ùãιçžò=çÎÜÏýž"ÇÆÆX",‚(r~¿Ñ×5xá\XQp^Ûx¬×é23îùbí:¨©­9bMS Óé2ïøÅ?Ö@iYùøßÿN£V€9,lØÐ¡;v Íyl.Þ½öè7õÕZÓä{;.u(ˆ²”·gÖ“{`LŸû§ ~‚Ä ¸ì±—:ôû Gi’š=왽2àl]Eîîõ?Y/øx¶·%qbƸa=ï¦YÛãí¬õ8fw¦¶üáä¬àðÐå 4œþÛÛVl?s Ù’ð×±3"´¦ùв´dÏÆ-§öвôPÏÌWxš¡T!âó<Ÿ““³cÇY–'NœØ2AQQQÏ<óÌÈ‘#;±±®˜oKòóóW¬XaµZûõë7oÞ¼ØØØ@xzzúŒ36lØàt:§L™òôÓOwb½ü~ÿǼk×.6lØÌ™3™Ë;nß¾}ݺu¥¥¥F£ñùçŸôÑG!ÈÚr6f÷îÝGsÁyUGó<w¨ælö„ÚêC*zlE ÄõçðᣔŠ6F„uOð ¼WàmΆ†£ÒDÄÆsÖ#95*±Kפø»îØ·_j×îI^Ÿ[”x•N4ésqáÑZ“>22\«ÑºÜn™P†T1:à8}˜¶ÕLeYöx<ÇNŽ“9Ò¿?Zíóû ‹º%%†5÷pØvÔdåË¢ïn_uÒ]ûíl'–ìÙМ«~õùá¯ç î\­Si&gý¶ñª{ûýWÿá^ÿÿþºëó€æ|ù«Å ÖÏŸ|75ª[‰ãÒ§ÿ/ 9ÛRƒm‘³{ñÊÓs†?++rpxèò´EoKRoKÒ«swo˜ÿ›)!b®>øÕšÃ›ßù‚ФçlY¢S©g y2DüU«VY­Ö7ʲ¼`Á‚–$Iª««[»vmŸ>}®¨‚šB]1ß–äääDEEmذáý÷ß_ºtiã©,_¾\¯×Ï;7 9;«^Ë—/·Ùl7nTeþüù+W®œ6mlܸñßÿþ÷ܹs{õêUSS³víÚ€ælœ„Ù¬î>ŸÇñ÷Þ{¯k׮ݻwG7,iÎ0¡Ô±ð‡ˆ—¥eÏ ÁE nÐÀZÄ­‡_”xà4²ÌIRÃîæ9ë1š4EGöÓe¦ß—ß=A£S Ǫu‚Æ]n§Ÿc‘«sÔ™ÃÃÔZ5Fb¿ÇÏùpãDNTdEðK¸Ô2Ç¿¯\83™žÏÁƒmÞ²¥è?ï­g‰Œ;f4tKJÚ½w_Vf†N«u¹\?8(Šj²Ž²îèVxõÁ?EêÂ`ÞÈÉðÍÅ»`drV@ãmþiw°Æ{¨W‰“Pãvü¬ >?´yTïûîMì·è‘éWWžC?òU² Ö4†‡.O[4Æ?Pþcè˜ôGôÊ$p¶ÙZsnÛ¶méÒ¥ááá0sæÌ={ö´*#£¢¢V®\"ŽúÜÚ™o0‹- L˜0á“O> >õÆoÄÅÅÀ²eË:·^;wî\¶lY Y³fM:5 9ׯ_¿páÂÔÔTHLL|ë­·B×wÉ’%£FÒh4¯¾úêÚµkÕjuVVÖ¡C‡®®w!'âöÖœíÖ¦[ùµ&>Ä-#.Ešî̉îdÄ-J×=\Wë¯+9ï—DÑØ=¥wTlœ%:Î+(rL|£Ù€“8†Dz²,a¸Bâ¸êíN‡Ã¦Õªpçü’ ’(ªuIàEIÀep¹eŽS&?/˲Ëí>~âÄ÷{öŒ1bç®]‹e䈇ó9(ܹë»ßŒ|ø¾¬¬#G}½å¯Ïg0ú¦ö©³ÙP“u”*WÄ#›…×xì``´—¿:‚ÏÒÕ,þc¦þõ»µçœ?LÔ›#&=š6ô*ÊÓàwçÛÎò´Ecüz¿+tÌ@úƒ–<øju]Ág^WW8މ‰i)l$Iª­­]·nÝ¢E‹òòò:«½®˜o3‰xúôé¼¼¼S§N¹\­X qœm§×Ën·§SWW÷³a­Ö¹+óóó·nÝÊ0LaaáÛo¿={ö쨨(tÛ"æìˆÂl|YQÚ_YQ$¹/wc|“Zߨ¥Õ^Þω¼Š¤›¥¿wê§z•¶=匌Œ´Z­ñññP]]Ý2A111S¦L5jTˆt::¶öŠù6cöìÙ'NÌÎÎÖëõ.—ëÁ >Ûr’dgÕ+<<<8ˆˆˆ@xtttIII[ãr1 S%¸T8Ž×ÔÔ$$$¼òÊ+Ï=÷ܬY³Fn[Dgߎ“ q޹,Aƒ€!™ÀD–mü°hÌ-q3ßð­ŒP@k·$‚ŠÐFEÄõêÛ£[¯Ô”ønIaáfšQÉ’èªoà}>_}½Ãj½x¡¤øxaÑÁ#§ OÙóÃþo NìÛéüÁíqÖÔ6T×Ú.UÛ+«Ý6»Âñ*“9NŠlòw¿yË7eååÏK’ÔÐàÜð%2,‘‘öx¯×çñ»žãÖÚòòR–c##"táf\IÁŸŒš&e§×éôR4E¸"+õ>–×jÔ:5†Ë¬Ÿ ÎkàÝw/*ܹk—,+:­61!aÔÃ#`ÄCÃ:ôï¯þò,Ã0ñ]»Œ>zõì‘¿ã[—Ë¥f˜.qqk4P“u”ßõˆÄ‰Û:æ“éf¡q’äs™y8ߊ¾€?¦~6ãÑÐéL02g÷úªs$NÜÛkæÐ§‚ÏNûý÷ß  I2,,làÀÍdÕ¯$D¾­òÎ;ï,^¼øµ×^³X,/½ôR~~þõ©× /¼ðÑG?†ú /üÜO&L0™L‹-*//×ëõ“'O¾jÚ´i .¬««“e9 ½g̘±dÉ’I“&ɲ|ÿý÷?ÿüó+V¬X²d @Ð.)ƒ+íÒ]‡FC ‚Àìv;fßFϥ̯¼Z<Î6¾E⸹5'òs"n%ÿÂÙÙÙÞÞ=»víb2鶺ºêjBQô* ƒ“"ËK‚Bã¤×ã®(/ã9®K\lLT”, 8(ÏÊ’@à˜ ðjšåXœÀ Q”$†Q#Ì"­”U”Ínî5ª‚Z­Fíˆ@\ZnprfÓ¦M999kÖ¬INNFM†€üœ­Ðrþgã‚·!Ä'Ûv:â:ÊRtç!nIe¢bb) ã¼®K%eõ>Þ¨ÖêTj™—I•ZOQ:ƒ âÂÕjNH’H„L34Ža^IÖQŒWEQ”xAa9Yy¿à–Sσ¦‰ ·7Õz°m櫯¾zýõבàDÜö𓹦»lþ²·'ò|"mȾktû1!Y‘eÐk4Ä­ >·—÷úHŠÁEÑçqÉ€i5Z™ÀTŠÂ¤¢ÑH"F©Y‘D…dÀSpŒ Si42øYÎ/rŠˆáHœÀJ.–Áx‡ Œ@ ®ëׯGF@Ü š3øAôºŠO´ç qÝ%n“·?,ru"nÕžìv9AÙ÷ýNM©dE£(†©dIGàº0À‹¸ @Q N¨ ‚YÆ0 ÃdÀD^”D’e*ZM+8-c8%s æçY¿—d\âÐvš@šóšNhmœ,s©´G|6ßðéOâš¾õùEjç†n:Ä­ %È®ªj¯Ý®ÓDMQjŸ—qY¡d¹k´Åïóy^àSHE"‚¢)š"IäeÙÇs>¯OôùYÁE —RQT€—d’T$Y‚þN€ËkütʵÀW—l[¤§§ßñ¥×:ßv¦KÌçD îÍB?^Ãgàf:3à~A#oˆNS°Aït‚¤&ºÅ·Åÿ± .?Í ¸ÂR*Ál4xiÎãr{.Êͳ¦H4 ¢,°~\ ŠV0IRDAD\QdA$Y‘\Æp@R0£RÂH '…ד€Î VžˆÎâæx’ =QHsÞPñÙèÿDÓ>ˆNÓ™¿ÌÖfArq[áöqRg WÉr­ŽÖx’r`8Ëóõ¶:Àp’ D^Àd‘$IàyIÀdA”$p‚$ Ф0`1À(‚¢™æ¬¶Z‹Ož¼XyI’$½N×½[·þýúR%¡#GJJËü~¿^§ë›–––úó†ò'O>QTäv»õzý€þýSz£ÕAnR~Çò–£ªªjÅŠhhhèÚµë¤I“Fu­3méìtèu¨W«eþúë¯ÿþ÷¿×ÔÔ(ŠÒälã^)hÀiÎ.>™Êó*Ä'ZqmµÜ5ë`̯K³Éé¦:³qôlóïÄmð,‰á:C¥¿_Oª´eÐÓ$†Ùêí‡M«Ó‘A`8a"A’$ŽcŠ 8Ža8&I’ ð’ 4MR)"( +†Š"7{Tþ÷¿Ó¨Õ` 6tèŽÉ={ŸcÆŒ 68Î)S¦<ýôÓX/¿ßÿñÇïÚµ † 6sæL†ùùÙrûöíëÖ­+--5Ï?ÿü£> ACa[ÎÆìÞ½»Ãáh.8¯Š@âhž'iΛB|Bë.âŽÓ™M¥fsg&º+wÉCz¤˜¤&KDÙé³r½Ìh5­Öh4¹}nŠ"ÕjV«óxXÞÏù9žc½‚ूґ¢G@0k~—[äý*Lá?P  70ºÕLeYöx<ÇNŽ1¬¹'Ãî°@Íœââb÷þðj²ŽòeÑÎw·¯º?鮿ýv6Köl hÎÕ¿úüð×s†? w®Ö©4“³~ÛxÕ½‰ýþ«ÿð?¯ÿÝõy@s¾üÕâŠëçO¾›Õ­ÄqéÓƒÿМm©Á¶ÈÙ½áXåé9ß•98»%%íÞ»/+3C§Õº\®E AP©T°gß¾Áƒ1*Ïó¨É:ʺ£[àÕÿ© €y#'Â7ÉY·ù§ÝÁï¡^$N@Ûq¹«°ðù¡Í£zßwob¿EL¿ºòªø)¯]°¦1 >õÆoÄÅÅÀ²eË:·^;wî\¶lY Y³fM:5 9ׯ_¿páÂÔÔTHLL|ë­·B§³dÉ’Q£Fi4šW_}uíÚµjµ:++ëСCW×»‡4ç¯y,¿æO¹ 4†0ð€Ž<ŸˆÐBî&Ö`Wrã³ÁwV{æ—¢›q£bt¢O¬¨¬ׄ™T…%Q’^g`ÂMZ?ë#qY¸†­ÒS…©(§T”„)çóé(“pS0S`EÑÅû&p†ÀH\”[ÙŸsÊäçeYv¹ÝÇOœø~Ïž‘#FÜ—•uä豯·|ãõù CßÔ>u6PÅñ¼F­KÍß|0fê_¿[[pþpÁùÃ4A½9bÒ£iC¯¢< ~wp¾í,O[4Ư÷»BÇ ¤?hɳ¯V—=tüºººèèèÀqL¿Ýd2ÕÕÕ„ܵ ­|[ ª€=}út^^Þ©S§\®V,Ð8ζÓëe·ÛƒÓ©««ûÙ°Vk‡Ü•ùùù[·ne¦°°ðí·ßž={vTTºmHsÞñy}ïè"˶ùÈŽ@Ü”28ÔrYÈU‰@´M©YÉcs:O>—œ`ÒФ"°~Iòz-I‘´ ¢½~žAEYVdž£HÃ\‘QS$EÀ HYLòH,­×¨#´˜AëZÏÇq“Ñx_VÖÿX$IfefdefΞ(,ê‘UUU=.?¿VUUEF„£&ë(±†È{e•³.ÑÜD~Xtæ‹ 5nΧ( Dé̡ӹ'>õŸú ÞçúòÇ‚%{6.þ~ÝÕiN#£³yÜœOV”ö—GV©µWñMj}c –V{y?'ò*’n–þÞ©ŸêUÚö”322ÒjµÆÇÇ@uuucxffæ·ß~ûç?ÿ¹õíèØÚ¶òm‹Ù³gOœ81;;[¯×»\®|0ølËI’U¯ðððàt"""áÑÑÑ%%%}úôiõ* ÃE .Žã555 ¯¼òÊsÏ=7k֬ѣG£ÛÑYàÈTžÌååKØk4&‘iö!†d€d€dX‘ þ\ùÑ¿Ñj—û•:³ñè´?ïÔ¼'þÒµQ‡D ‚Ñh jŽ¢Õ6‡³Æfe™RQ2ˆ~ŸKEcj†¤Iœ¦iÃàéã9VI8AdyE%^DIP$ŽPxãHÌ- "M ©b”¦ó47où¦¬¼œãyI’œû²DF@þöõõõ’$¹\®£ÇþøãÀô» µOŸUW[A¨ª®>pèpZj*j²ŽòÔÝ£àÃïÖÚ¼ õ>×¢‚Ïáô ÛÎìß~ö<’:8t:/~ùA±õ‚N¥ÉŒOuÓxÂ5F¨h°^±<ñ©|·n2;·­òXtf(ª>·ó\+ã-ãJ Ù’8¥­œ˜ÅºêÀÿzy‰½rî7WXøgÔ¨Q¹¹¹‡Ãf³åææ6†ÿ÷ÿ÷¦M›Ö¯__SSÃó|qqq`Li[m«È·ÍÿA–5›Í ÃTUUegg_1~gÕkøðá¹¹¹v»Ýn·çææ6,þä“O¾ûî»EEE,Ë–——/\¸°É›‹eïÞ½²üËTÞ#F¼ûî»åååÇeee<øª{{zz:Ú· òs^õSz£¬k5ü5W“žhýÛ;œ«ÖÚ±ü ?¿¡i×Fš¨#îp aa¤BÒ2Å»<ö†z£šb¢ŒH c’"‰Š„+8.€â“D5MMq,aÁ02AÈ$镞µù=•N‡®A6éHÉë---ÎkàÝw/*ܹk—,+:­61!aÔÃ# WÏù;¾u¹\j†é÷ظ±FƒºwKâ8v×÷ß»=½N7ðî»Ñ¢µWÁïú?DâÄ?ŽmóÉt³ÆÐ8Iò¹ÌÇ<œoÅ_ÀÓG?›ñhèt& ™³{}aÕ9'îŠí5sèSÁg§ž°lß¿ýt¦¬(¡Wš>äÉKκÜÝF4]·¶­ò¼úà³ >éËì!Ýïn™ÚIkÉŽ³ûÇöš6ø‰ÆÀׇOœ¿}Õ{;>ykëßáòÊFÏf>ª€²¹x÷†cÛÍ1“2]ßI“&åääŒ?^’¤gŸ}öûï¿„ÇÅÅ­ZµjùòåŸ}ö™Ó錟4iR'¶W[ù¶Å;ï¼³xñâ×^{Íb±¼ôÒKùùù×§^/¼ðÂG}4~üx:thãúC&L0™L‹-*//×ëõ“'O¾jÚ´i .¬««“e9 ½g̘±dÉ’I“&ɲ|ÿý÷?ÿüó+V¬X²d @Ð.)ƒ+íÒ]|í†=#nE0»Ý™ÇˆNUÌ5J·Õ¤ ùŠDèáþNҜ״YÛ^þç ·@ˆñèhYZÿÂÙÙÙÚþ)uVÎéaÌ~±‚”ùÞI1Ý»Z´jLÃëåhÚdwó5n¿#d õ4­VdÌíTƒ¦#u N¿üÓÙ '/”\²×^¬·Ft·$¥ôª®³>üSÍ¡ ר jµµ#q}h¹ÁÉMX˜M›6åää¬Y³&995"òsv.L‹'j¦ÓÓmý?0ޱ Ï'z¦¿ÉEãÍÖ@íV˜Í•oK—&Óñ^@Ü™¨´”)ÊÈ2-a G6ÔVÙ=.³W«7„ ŒZpÕ ¼€#c“ºQZ]}M³ºŠõº%…ÏÿT,Sª:»ÿðÑsçÎK˜"iIÉ¥Õ¹¼"Pq ÈÂÄmÀMµl[…ùꫯ^ýu$8Hs^Oýy½ß2­É ¾½}{ص™íë-?¿UA2ˆNÁ/yÌ1&NG»jì‘ Q8)º¶Òê*ZE„G„*'9=œÌ“¢ÇÞPu®¤äì9Z ˜¤VDŸ×y´¸(²KWuX”!±Û€n=z¥¤˜cÂý¸Ÿ I’¢]Özdaq}X¿~=2iΫ ®ß¢ÁÛ®0W)*·-WÛЪ³ĵBÄý†H‹bT54Ôà4Ó£kÃ%ÚWï(³Úô³É^ç⎟<_êtú5j[ƒ£¾Þ•`1Óçõz{Ü{_ïþwa*]/4Z}\—.ZƒúbM™ÛïÒ¨uZ¢Y@ HsÞ´ß2í>Û|ªg»%ÛÁLí×m×Í’+{õ:ñkhðÔÖ{µfƒYoÑ+¬¨a † ’d­³‹§J4ªÚò2ë¡¢ÓU,Çt‰Up,Q&­«¶Úï Òî¿ÿ®Ì{ë]~—§)FèeXAÁqµJ¥‘ Yø&¡æÐ¡#ï½ç./—EñÉââk‘ÅêÕ« Û³Ô*q33mÚ´Lœ8™iNįŒ×wðm;$(rÞ²¶ïZ”Í{c{ä1ê.D§p±ºÌ˺{õèݵg×ÚÊZžS(ƒ^mޏTm+?uÁçôÚêœv/gîÖ=åþûéððî={d¤§¼ÿdá‘Ó§òbà%Ÿ(7¸}$pŠD‰õ{9½Q§QëýÝß,ûàç… |ýµ!)éZ¤ï÷û×­[÷ÙgŸ!S#nu^~ùågŸ}ö‰'ž`ô¬4'¢s”g[BàHP¤?oW‘ÙFÿ ž÷Ë ‰@Ü(B©¨,e9®wïÞŸ÷ŠfM¸Je(¯¨qUØMÑ‘]{°€ááÑ]»&¥¥FFGÑŒZ«WÇwïæpÛEPêì6E¢Nä8ÎÅ˼à|œ¢e8¿Ÿóùƒóª¶Z‹Ož¼XyI’$½N×½[·þýúR%¡#GJJËü~¿^§ë›–––úó†ò_¹*p0eòó¨±~ ®òrÐ'\«U ÒÒÒn–U£ÒÓÓ;eÙ›–é¼öÚkIIIS¦L |ÍÉɱZ­|ðÁ­Õ~½}n;”dÔþ²KBBBjjjAAÁèÑ£ÑOÒœˆë&A¯‡`á—]@Q2¡i®a}byEeƒ×GJDe­u`V†…ŠQéµN^Д”×»Ýþº…÷ õ6™ó`/Õ;œ>^ïÃ4„ü¼$¼Â):…•€Æ$Ñï Îë±qcõ:]fÆ=_¬]¥eåãÿ;Z æ°°aC‡îØYМˆ_ÏúÔÔfÇùœ²(æä”}ýµ¢(IcÇöŸ1'ÉàhÝÿë¿*¶oÜîöÌÿøæ›pä½÷(.í¿ÿ;øB Ãßµ«lóæöäb³Ù"##ƒCæÌ™óÄOìÚµKQ”ƒ†PGÍ$P0!DË+¯¼òâ‹/fgg“$yòäÉ/¾ø" ©—´ê+((ÈÉÉ‰ŠŠÚ°aÃûï¿¿téÒÆSX¾|¹^¯Ÿ;wn@s†Hç‘GÙ¾}ûSO=Õ¿ÿxàêÚ¥£ö·Û½sçÎo¾ù¦¤¤ä˜9sfˆÈµÏòåËm6ÛÆE™?þÊ•+§M›ÖØ ›6mÂ0lÁ‚Ÿ}öÙ /¼pcíÐ)ý `#Àq€‹EFFÚl6ôë4'âF)Ï Ñ©”¹b`ˆ-X‚DÓÙ%k9œõ:pe:¯.Lg‹Ì S´¹¸Éi¨sb4£Ó†é4aæhE!|Ö¬3öJê!ù¸ ÎÈ*^ÖH‘1*2ªKËKì6S‹Q¯Q08­ÁüŠà󃌌Ê/r,ÇcŒJæ‘õ´Ì±q l˜Éð|vKJÚ½w_Vf†N«u¹\?8(ŠjškMéW_@ÂÈ‘ÍYúÕWÍ4g¿iÓHµºÇþpuékµÚ Ìš5 >þøcF:~G‡JbVRRb±Xâããûõë·xñâ+^²hÑ¢ÀÁ„ šy±Þx㸸8X¶lY{r4hо}û¦NzÕµè¨}^}õÕÂÂÂûî»ï™gžÉÌÌ$¢sí³sçÎeË–…‡‡À¬Y³¦NÚ¨9g̘8˜6mZ£æ¼þv–Íü´j[ 0`@xëÖC?Hs"n ÚŽÔÄÚ¤Èz%ñÜ!‘ÙLc³A"3H‡71‹Ú¸U8{ò‚!<ÂlïžÐ«{¯ŠR=s^äys„9­wЏƒ«­¿$Ÿ‘bõ:Ro¤™xsX•­†òùŒÆh4¨i'HÁÇó˜¢à˜$ jYä@á¿à1Yh™ã”ÉÏ˲ìr»Ÿ8ñýž=#GŒ¸/+ëÈÑc_oùÆëó †¾©}ê‡áÚã«©Úhüùkmmóz³¹ý©EDDÔÖÖÆÇÇöíÛ·K—.––ÖéåÏËË[»ví‡~XVV¦ÑhfÏž=bĈñOŸ>——wêÔ)—ËÕòlã8ÛöàõzW¯^=}úô¼¼¼!C†Æš^²¢(-ÔN9ÔQûØíöèèèÀqLLL]]]ã©ÆðèèèÚ ~rýíÐ(,;a>ç“S†´~²¦¦& ³Hs"mE¶TH‚BS›°.ìÆl\ˆim×qËQ}±êÌ©•Fæ|©ÍêøÍ#cÓïpþü…³ÎwïÑ-ãþ{Ï•«¸XZr¾¬KxŒÆ¡!ñHƒà%¿Í©&qŒÁ%¿cACQ’Œ¹¦ˆZ’â|^¯Û'p\«™â8n2ïËÊúâë€$ɬ̌¬ÌŒÀÙ…E]ââPÓ\kÔ‹çâEÞåEÅÒ~ø¡ÛíþöÛo?ûì³·ÞzëÁ|øá‡ï¹çžÎ²Oxx¸Õj ´`uuu°âj ·Z­Áá7ÄÕà;€ïæ7ö/Kצ¤¤ _ ¤9w¢ =Ê”m!¨Ør ®Fn]9äFŠÉiº÷L‡7™Á2Ù›Õâê¸;õ®’òŠ:[½IÅßü É‹c&Œ¿7ëÞÓgÎþxö\R·¤® É’HÙ.Yëm^Ì)F”NkrY«0^ŠJL $Y¤D•šáxÑåöxe‰QkE^Ô“z=Mÿ7où¦oZjLL In·çDQ‘%2ò·ïȼg Á`ðz½ç.\ø©øä£cAMs­I7îÇ¿ý­"?¿ñë¯ImÈ!Û¶m{ä‘_Îáp,^¼8''f̘‘‘‘aé8í¨Ûê/ùËSO=5`À ÃX–5^vذX,{÷î4h~(˜V IDATy©^–eÍf3Ã0UUUûÛßÚ™KËtÊËË·lÙò¯ý fÍšõÄOŒ3&îò[’ö¯ÓQû€^¯üñÇüñššš­[·~øá‡!–Ší¨}†ž››XË'77wذa‘á†åææ6jÂh‡Né?ò²¥à€;v\µúEÜT`v»=ðNÙâÎãšxACL¼ oTb·î*DmížÒQuÝöÒ²jÌ´ºÚz¼¨°ººZ–V›˜p÷€»T*UIiéÁÃG\.—šaºÄÅ¥§ßm4—4Û%%x—NµZÚ±ý´\CH„‹—mÙ‰cÆÜ5kNQmE¾òËŽ3æÓO?MLL „¼öÚk]»v ÌôËËË»téRvvv'Öhß¾}Ÿþù?þÈ0Lß¾}§OŸÞ½{÷Ƴùùùyyyuuu²,ÔÈ/^\QQa±X^zé¥9sæ´g fËt¦M›–‘‘Xg>ûì³Â€d ¸OãââþóŸÿ\±ü7›}|>ßG}ôý÷ßÀСC_~ùåÀÔÊôôôiÓ¦­Y³† ˆ#FÌœ930†öV±C»¥É/š³´´ô¹çžÛ²e ú‘Aš$èUjÎ_â‹ì-ª<©×¯rá²M¿4_ZiNâÑœ[~úÎãö±,ŸÚ¯_÷ä·Ÿ­²Û Z•Ø£GRÏEE„é1‘wÛl ÕV¿ÝnÑêubƒc9£š‰41 £U*/Çzü¬ˆa2AØ ,È‚Š®´Ù>~ëÃkTô8x³ñÙgŸ?~œ¹ÔàpØK++šˆˆE¾IXµjÕ‡~Ø·o_d 4'qKJÐ+¬‚4-óŠ[e¢mKÄõ'‰>iiqñ®‚ßýT”ž>pèÐ!¥%eåeå§‹O "WRzg(·O28<*¹—ÇO“z‹&R&ä=¬*2žÔõ1Iê0Îãv†Õûþ÷¿Ó¨Õ` 6tèŽÉ={>þè¸_âëõ÷eÝûùºu¨É:Š$Iß}÷ÅbA¦@ Hs"7•í¸J 5¥“mz ™âf!6&No0ú=>‘êëKŸ1"1%¥wï”Ý{¥õ¿+-ýnJ§sûXžx^ôxý8Ac4¡€Ä*¡U9_ñùÓ?žp;–ðˆÁ_á¨xÿ 0½éÄáC­f*˲Çã9v¢0660 šùàì{Ë«Ê+Êcc¢Q“u”ŒŒ ÃÞyçd 4'q )Òæ”¹ Š@ 7Фèµz­Fsòô™‹eiƒ1*½º,ŠgÏž©²V;šgýÇ ’ H6Gƒ, Fò‚DTl’ÅÁÔVñà‹I´DED”–\2jˆ>BwøÀáãGµÌñï+WÂL¦€ç³[RÒî½û²23tZ­ËåúáÀAQl¾±ç…’’}û÷?6vj²Ž²ÿþÏ?ÿ|Íš5cÆŒAÖ@ Hs"·‡E"@Ü2TUVUWÕ0j¦ªªÚ^g랤×ë)ŠTëtÒH’Äy=¢Àa¡ÂqEæyOƒlÐê &FE¡””s¢ÓhÖèM*œ‘M‘ú„î].œ;wöüIAleÚ”ÉÏ˲ìr»Ÿ8ñýž=#GŒ¸/+ëÈÑc_oùÆëó †¾©}êl¶Æø²,8tøBIɘQ¿1™Œ¨É: MÓ¿ûÝïV­Z…L@ æD n Š@ · ö;à¸Þ —xQ¯Õ;ìŽ ‹h‚J듪7êzƒÛÙ€‰EQ ’Çí©«ö«HƒŠ ÕÀ1“Üõ—Ô*‰Q‘%’´”’Ú“<õÎZFƒGDZÍÇq“Ñx_VÖÿX$IfefdefΞ(,ê8vº\ßî,P©T¿ÿíã ƒ~l¯£Ñ(I²@š@ Äõ†&)KTTï”Þ,Ç9ìõÕÕÕeeåF½Ád4j5&+'*·èçiš¢p¸x±ÔQï$IŒÑ’ðÁy ¼ûîãE…;wí’eE§Õ&&$ŒzxôêÙ#Ç·.—KÍ0]ââ7Öh0ÀÎ]ßÀá£G=Ú˜ÈsÏü™¦iÔpÅb±ø¾üò˵k×VWWÇÄÄ<óÌ3=öX§ç^PP–––p“X£³Ü¿-Ó aç„„„ÔÔÔ‚‚‚Ñ£Gwì•DaannîêÕ«¯»|<ðâ[€<€=<@À€W4uo|P 0à=€È靸  `6À$tW!͉@ "ˆ.‰]]~Ïésg»$ÆtIèŠ)²Ès¢Ÿw»]”‚s<ËCã$È’À Š’’$‹‚, ÉFêÈIn—‡ãx’ £J­ÖÈ¡j2Ÿóà¡Ã}RRîÍÌT«Õ^Ÿïø‰Â; F¹oÿ~¿Ÿ;f´N§s¹\ûöï§h*¹g϶â£VCt"¯¿þúøñ㇠–œœ\XX¸uëÖM›6À·ß~û駟Ο??%%åÔ©So½õ–Ñh|ðÁ;7÷Ý»w?üðÃw²<ôÐC»wïî¨æüâ‹/þøÇ?^9žÒTy˜0 `)@ À%€ùþð@ ÀQ5‹žø¶íÄÿ`ÀZ€»Žü àqtc!͉@ â2‰=~×¥šj`d™R̃A«ÑÐ*ޤ^0G„á‚Bˆ/ø%^£išÀ€¦H•Lë(­A¯gTª²ºê’ÊJ§Û'+DLl,IÑ>޳„'§¦çõظ±Çz.3ãž/Ö®€Ò²òñ¿ÿF­sXذ¡Cwì,HîÙ³­øˆ›ŠZcö×ygjËNÎ e)oφ-'÷À˜>÷Oü‰ÐtÞfË9œoo[±ýÌdKÂ_ÇΈКBä+ÊÒ’=·œÚ+ÊÒC=3_yài†R…ˆÏó|NNÎŽ;dYž:h6›§OŸþÎ;ï¬\¹rÞ¼ysæÌ1™Lð¯ýkúôééééžž>uêÔM›6uºæøÕšÃ›ßù‚ФçlY¢S©g y2DüU«VY­Ö7ʲ¼`Á‚àS<òÈöíÛŸzê©þýû?ðÀÚ¬Q5ÀÀ-Z"ýàÈ\QlØl¶ÈÈ&7çÌ™óÄOìÚµKQ”ƒnÜØÉÓY_yå•_|1;;›$É“'O~ñÅÍ(j«ck rrr¢¢¢6lØðþûï/]º´ñÔ–/_®×ëçÎМ!ÒiÕÎ"##m6[‡*²nݺ'Ÿ|Ç;i˜-=0à•Ë~ÎBwÛã—g€¦¡_¤9@¡3ë)#¥ñh­ÖKœÈ²"ÇË"Ab ¡`4.€ˆa¢ˆã Nâ2Éy= ç—(\$1Œ&4Z0Œ—d‚¢U5¡R‰˜$f±jõÅêKõŽú–9þ}åªÀA˜ÉðdvKJÚ½w_Vf†N«u¹\?8(ŠRˆøˆ›ŠC?ÀÈä, »`McøæâÝð€æÜüÓîöhÎÆøÊ 3þˆ^™NÀ¶3ûCkÎmÛ¶-]º4<<fΜ¹gϞೃ Ú·oßÔ©SC¼^¯Ñh€ìììÙ³g›L&Ç"ýÎòeiµÚ Vúøã5M綆a%%%‹%>>¾_¿~‹/¾â%b{„ ͼ‘o¼ñF\\,[¶¬=¹·´sc©:T‹†††}ûö½üòËc”Ìôˆ¥#‚|›÷„X .€px `)@€³ó{iN@ naÜœÛkQU^Î-‰ŒŸe^§,kY2Y̼Ë%Ø],H ©ÂqBq>QPD^(’ÂI·Ïï¡ÞíÖ™ÂzéôA×ÕÛµÕ—"£¢{öIYn™ã”ÉÏ˲ìr»Ÿ8ñýž=#GŒ¸/+ëÈÑc_oùÆëó †¾©}ê‚<-ã£V»©hð»ÀÀh›…×xìÁá5G{RkŒ_ïw…ŽHÐ’g_­.{èøuuuÑÑÑ㘘˜àS^¯wõêÕÓ§OÏËË2dMÓíçr¹ÂÃÃgÏž9:®Ó­Q[[Ø·oß.]º@ZZZ{i96yyyk×®ýðÃËÊÊ4ÍìÙ³G„¼§NŸ>——wêÔ)—«•éÐЃVíüskÖÔDDD´?©M›6=úè£*•ê×6€0àŸ[zÀŸ2þ À ð'€ÿ ÑeÑï¯íò¸\Òœ@ <чHµDGFE[(÷y¼¼$±’ ¼Š1ˆ889¿ÏÅùqN…«DŠfVEÒ8MÊ$Îî÷sGO]°VFÄwé–Ü›Që+*.]´ZO—^èÕ§gT¬¥ÕLq7÷ee}ñõ@’dVfFVfFàì‰Â¢.qq!â#n*ŒŒÎæmps>¹év¬ùbC›ó)ŠQ:sðYYQ$Yjí%ÈÏñMj}c –V{y?'ò*’n–þÞ©ŸêUÚö”322ÒjµÔ]uuuð©•+W<øOúSqqñš5k&Ož ½zõ:zôhã?GMNNnð æŠ"0%%¥¨¨¨™æÜºu«×ë€üüüQ£F]±jr¦%&&¾õÖ[ IÒŽ;>øàƒ`͉a˜¢(Á^ÇÙ³gOœ81;;[¯×»\®f3ZÛòO¶L§-;(,,LIIig8ŽûÏþóüã×öÝ O„h¼;.¦šÆ,è2‘»¾ùëww¡_…›´?'@ 7A.UWú}¾„øø„øD³9¼¦ºæü…V"ŒááQ ñæØ8ÚdiÚÅó.?Wçt;<^7ËÙ]îã?ýXïö¨ É$càôy90©g÷‹—*OçµyË7eååÏK’ÔÐàÜð%2ò·ï¨¯¯—$Éår=~¼ðǦß">â¦"#>¶Ù¿íôÁáôß~ö<’:¸Q+@Qõ¹çµL­1~fü/.¾dKBà”´ÙŸԡ°êÀÿzy‰½rî7 ]ÎQ£Fåææ:›Í–››Û^^^¾eË–_|fÍšµqãÆK—.Àþð‡¼¼¼ãÇû|¾cÇŽååå?>´ðkÉ­7dÈíÛ·‡8ŽÅ‹Ï›7oÞ¼y}ô‘ÃáèÜöúË_þ²oß>ŸÏÇó<˲ñÿ(y‹eïÞ½rЖeÍf3Ã0UUUÙÙÙíÌ¥e:mÙùg¡·cÇ!CÚ™øæÍ›ï¿ÿþà%ˆ®†uø&HpÀ=s*€ €72‚Åt‹õo_˜ °À°àu€—š¼‰hõeâºÙívŒªG q= ü ggg»Ò)ša(‚ 3‡ÇEǰµ†±X"Uf?Sé¿ä¿(±’çÿ³wÞñQí¶^¯ÉÝ¥'$B ¡)@¬ bWP±½þ, ¾RDDEì)RD•º0@h!RI¿ËõÛúûcåÙ¹ô—¼=04µßØÌ‘AÀ¦ü½ïg}ëãØÌ¤Nì‚¿¯a{WçA›OíkûÁã,š?‡FókЧmúúTM±cýñ9Ÿ¿oíúã;«õ ÆÈ'ûÜ}KÇë‚Èé_·–çù1cÆ|üñÇ’Oøâ‹/öîÝ[Zÿ.\˜››;{ölXµjÕâÅ‹+++#""üñ˱?§×ë6lØüùó¤ñãÇÇÆÆJ_<Ι3§¼¼[]YühžÇåTôrƒhˆ‰NÒkµƒÉ¨Ô‹^ÁVY{NYº¼N·Wtò .{µ½Îyà°GäÒzvqr7㩪®NJjSQVîj°¹\HÃ@>'@ ×.?ÿ¸¡ª°ÌYa%5Æv Éf‹ÅiáÑÌàÛn0YÌjJA „£¶ÁZQ]vælÙÙ³EEv·ƒó2®{Meõo¿nt¸ áÇWy®rÀu”r9ï–•ÖY‘†¯)¤u€¤5~.ɵR DÛ’m‰ ëßüOøçȳ`Á‚ÜÜÜÀ¥}ôÝ)ùœ@ þÄmu§vî30*®]J»ø$¹Ra󸬥¤ºuê^\^"8ïcy/ÏÉÕjµN£Òªj…B%׆i-ñ£)¬Ê^ú]U¥.ˇy½B –X¦ IDATÓ1%U!—3iq1.i‹¸x<ž%K–ü‹æ¯^I^yå•1cÆŒ1B.—#m Ÿ@ D¨ ¹ùÎv‰ÉÑ‘1z}APœ 8ÊKä‚Òa’S´ÇéÂhŠáxÝéªk Á͹EZpqNJC\—Þ纮w±Îü¢3%F•Ýêp:ùdÁ‚­Äóos(É€9»€x€‡þ  ¨xà—ó{Ÿ xÀÔùãããÓÒÒ²²²†Šò9@„Êõƒn–ËŽ;yÆí°± [m­x.\4z\.à šrzÝv¯Óǹµu¢Ç[Z]ìœÒ‡ÜvCR§¤“'JˆOˆqZݧóÎì=[W_R{†(ðÙyÞ#æµoÿN©©×õé£P(\n÷¡Ã¹›·f ½õ–={÷z<Þ;† U«Õv»}ÏÞ½M¥tè ]%Âæ-[Ó»wÿ}o6ª/Ä%gâĉ>øà 7Ü’’’››û믿®X±"ÐÕô{žÿ[y¶lÙ2þüiÓ¦¥¦¦æååM™2E§Ó <8xj:ewçÎ7ß|s3'8€‡&¼ÜZ«¦,è0 àîrÿî»ïFÕz¼f7Øœ ð$À\€H€r€i¬ ð;€  `&À€-m”ÿÆoܹs'ò9‘ω@ ¢uxžQe”ÜåöØv ^ðzÜk=N`^—ÓÕ`AÞëq <#—S%ÖÁç>šw(..jàþéé]òŠòj*Ï…‡‡EX¢­µv[…÷04Èm5õ:Ñd2KIÜ1ìÏ5Q• EÏŒ‹—|Ïóü™Â¢î»W©P€N«Ø¿ÿ–¬mí¥ÈÙû÷Ó4ݹS§Ý{~L-ð!aØ% ¿ ªõ~ž“_]|sJß¿9)?gײ 'vÀ°Ný_0‚Ä øûw›M¿á|sã—›ò³SÌñÜ1.\¥’/'ðŸîZ¾!o7'ð7vèóßAÈ)Yø ÃÌž={óæÍ‚ ~’g4ÇŽûÖ[o}õÕWS§N4i’^¯¿•u¡ò¬\¹rìØ±’œ‘‘ñ /¬X±¢UŸóBÉËË{þùç›9ñ@8À¸|ÎÏf €A3æ†äs–”” 8°¢ï 8Nø RêAVè `@lÛåïÞ½û7ß|Ó¬oWv<ªÏ)Š"Ò@ ÿ8ŽA¶ZL&p,'ðUËã2G‰ÿõ×_WVV._¾\„éÓ§žºýöÛ7mÚôðÃwëÖmРAm«…f‡Cƒ8!*O~~~`={öœ9sæ%·¥ÚÚZ“©ÉÄÓß–j2´Ø,‡Î;lƒ^ )ë%K–Œ9ÇñKS’ ’æî˜ ðßó㜳îi»ü&“©¶¶õ9ÿ&ŸÛ‰@ ÄÿÐçäyÞa«#D`}>wƒƒçغºZ·Ïg4‡‰>ÆÊÔ¹¼.Nˆgk¨D¦¸´ oŸ^}Ò}Œ÷ȑ×G#WçÉß¶mç™ÓEáú°Þáqº¯«¯9v4—eÙFY³p‘t`Ðén6”eÙØ˜˜»v÷ꙡV©ìvû¾ø| ˲gkÖ¶ÂqœeYžçS#ÉkwÎTKNfKþ‹¢(ûü?Ûàyî/9·¤ôÞÏZä_|§.ùœëí ÅçôÇÏ.><¦”þMÉ}œ€ù{ƒûœ7nœ;wnXX¼ôÒK»ví <Û¯_¿={ö¼ð m®” ãºPy\.—N§€÷ß„ z½Þét†â_ìW©çXZ|ûù˜ÏÌhhý"›Í¶gÏžW^yåÒ´•/H pSÀØf¯ k[“¿¥ÖF8ÿ¹>§(ŠÈçD â‚ä¼ ‚àj¨õ9\Àp^»ƒÀqÖf#pœB`=<Ë3 @’Ãú\«×ëPë•íSÛÉÕ”ÝÚ T(2ºõ´V7ädª.­Ò(4 ¹Šõ²é=Ò•*•Óí+;[Út4rô¨GAp8GŽݾsçÁƒ3ÒÓÎÝðË/.·G£Ñtê˜RU]ÍqÜ–¬mÚ· ûsT–çSkêÍ^›>g Óø³‘ŸÙÒAÓdýŽhˆØ<ÐÊU«œuáUÎúPRóÇ·zìÁcJé÷ûtŒô³Ò^<~MMMDD„txÊår-X°`ìØ±sæÌÉÌ̤iú Tâ…Ê£R©ìv{XXØ„ $'M­V·ê_è÷œáááÕÕÕqqqx 3ä$´õs öü¼Ö ¬X±bøðá2™ì¢»6€I?lH€Çú¬ˆ¨xàQ€µm”¿ªª*<<ÝAω@ ¢uüskÝŽ:w½mpÓ«µ¤ÏËáçt8lV—Èy9€àpŒYŽóÙu=zu5GmÎz·×n2«ê£œ8xÌnw™""” ¥9¬6¨#"#drMÑ-y†J…"½[·V¯‘"tïÖµ{·®Ò©cÇOXL&–eËÊËÊÊËþ8ø×ó× Œ>¿ÄA×r ¶4’xÐè¸ÙÀFfÜN\]ë²9|náïÏufµ±ÔVåð¹¥ç=‹ÚxVE^hæ‹\|½BãTÑ ãñqŒŒ¤¥¿û…ù™*9M&See¥äM;w.ðÔW_}5`À€G}ôøñã‹-zúé§ÛP#:·öBåINNÎÉÉñ/ð““““’’rÉí*55õÈ‘#ó9·l˜h|A—®í°àÁ€Ë»·’©Ïç[·nÝ÷ß±ÒŸpÀïn(>ј4‘ òçææ¦¦¦¢;È¿Éç´ÛíjµzüøñH@\aæÏŸJ¥’?k—.Ã4 Ž•ÂÐÀÚJÀïÕFÀ¯Sw+Tm®:l¨4‚öî~w4ÎÀ LzXü¼yó‚KÒR„£Gr/(>¢ ¼ýöÛ¾kÛæÖöŽKû%oÏÆü½‚ð·ï9oï4àóßWmÌßûçÏ´~_±ÚYäÜéJ{3ßÅùã÷‰ëìL1Ç,;¹1ïi™Øùo ïL8oÏ_gÿøÌu÷V9êæïûiúÐç‚Èyë­·~òÉ'“'Oá“O>ñ‡oذaåÊ•ðòË/1bذaÑÑÑªÌ ]y¡ò<ðÀ³gÏ6™L)))'Ožœ3gΫ¯¾zÉM"33sãÆ·ß~û_AÜËF'Ö$ÎsÿˆH80à“V2]¿~}ÿþý/vé¦%/¼0åïßö˜ 0 àÀL€Þm—óæÍ·ÞzkKoÐ Û ØøñãSSS333ýó @ .§OŸ¾dk“\-äççŸþøcÉCxñÅ{÷îýÈ#HÑ.\˜››;{ölh2tyi=Š6ȳjժŋWVVFDD<þøã—cN¯×;lذùóç'$$´ðßšÏ _Ì(ˆ˜ØÊþœ‚ Üwß}³gÏþÛàj+nÄß6»uŠÿå—`ÀæóûsÞð€¹-ò=ñÄ6lP(ÑívûàÁƒ£££×­[‡:–œÏù믿fff"E ¸ÜœøàƒÃ‡Gµ‰|N@ ×.¹¹¹J¥é¡YJKK³³³ßxã ÉÏ t>‘rÄ¿-Z‹@ âÊÀóÿ2õwH’ôÁó<{ŽãüÇ Ã|üÉÈçD |Î6#þÎ gà’¶W%gÉ’% .DFˆ¸T¼òÊ+cÆŒ1b„ô:éZ÷9ý]?Ïó† ¼á†6¤²mËžçÑ]@ Dm‰h„4¥öŸév^nü¢Èår³Ùœ™™ùÄOhµZX½zõâÅ‹Ï;9zôè˱7IVVVçÎãããCŒ¿víÚiÓ¦½ñÆMW¬ qDnüøñíÚµ{öÙg¥Ÿ³gÏ®¬¬œ1cF«å½Üé_îú¥(*<<¼ÿþÏ>û¬N§û·— ***¾üòËììl›Íûä“OJ{‡ÆÇǧ¥¥eee :unxàm@r몫¥?km­­®.-µc¿¾}Ó»vU)äv«Õçq÷LO¦×Ë)JºÝE.9UÕÕ•UUmVìE^Žtˆ”ƒ@:¼ò…m5—+¯s‡ÓYYUew8B—5® pwÕ—Ñét–””4Z£±ÙÀ¦ø]ÍÀkÇœ5kÒk¯ñßÄ)oüçÉ'—®Xq©TÔ’…lß¹Ójµ]×·O„År1 ñËœ’ÜáŸÖ„/Ue]d+ QE—Õ´þ·]JSck5—+ß³}¿lù²VÞ=üÎqÏ?ä6(Ø?¶ûý'⬨ÊÊÊ3gÎ@RRRDDÄ•”pëÖ­AÎ2$øå.—ëèÑ£]ºt9zôhRR’Éd€ššš¢¢¢´´4éTðNûàÁƒ8Ž÷ìÙ3pœ³ÑøO£eél½ÛþéîåÅõçž»gt'K¢ÿìþ–þmwáaèŸØýƒ'&8#¿ÿít¯ÿxÙ¨w322¤k¿Ú»&»øhmQÅØ#ô ”T`²þ|yAXqxãî¢ÃÝÒÓûÄu•qMÒAdfYvÙ²eóæÍEñŽ;îp»Ý999©©©Rš¦­Vë!C^xá…œœœÏ?ÿ|Ê”)Ò寿þú‡~(ÑÆ…žeY¶W¯^gY–=uêTvv¶$gjjªÿ,Ã0;vìøí·ß&OžÌ0 MÓp×]wíܹsĈn·{ĈÏ>ûìÛo¿¤¼F£ñ7Þøî»ï&Ož<''GJ';;»Gå***6l˜¿\~ø¡^¯©\——ç/×àÁƒƒËìO¶UËiIÏëÖ­{öÙg###ËËËËËË`̘1þ«z÷î½}ûö¦)?òÈ#°dÉ’6[ì¿î,pøÓidX–„?þhÑ¢EzDÑíõÕÕÖ¹=š¦ÃÂMÇíñ¸=¯×ãr»¥—p< ½Ð-8Sèt¹Àãñ€L&“üŠ¢ý Í]#}í—yÅTä‘Ï ¢p¢ªÐö0Wºµáø¤ž€÷¶.˜¿íÓ}ï)Nƨ Pl3øÓ‘‡wtsÊuï•-ØîÈ›ÖÿÏyŒ'¶}Ð4߯ö®ÙÒpìÍÏÉHzÒ†O>׸̑AdþꫯΜ9óË/¿‚0}út¥R)Å”\Éi‰ˆˆX²dÉ Aƒ222êêê:tøëÅ\‡êëëƒ(äé§Ÿn¦/=ÿÜÒ…ÙÙÙ:Îð²uÞ¼ygΜ™6mš$g^^žÿÚíÛ·÷éÓÇl6±wïÞ@=ÊËË‹ŠŠ”J¥Éd²ÙlR ¶T^0`ÀÊ•+GŒ‘™™é»¥ò²,+¥¿oß>­V›œœ,¥Ÿ““C„?}¿¥ô“““gÍš˜þ¦M›üÇqqqkÖ¬iV-M·8jsýò<½xñâÞ½{KåZ¿~}III^^žT®P5oÞ¼fË•‘‘‘‘‘QXX(•Ë/†T®ððpé§T®VeTWðVÖ’ž×¬Y³páÂèèèf¯ÒétÙÙÙ}ôQ›ó½jÎb6›M:zê™1ÇO¾ù¶Ûd2š¢¨ÏæÍ{æL[ƒ-­SÃ0%e¥6›->.><,Ìçõ¹½·ëOjkë6ýú댙ӿþrÁµs×Ôh4,Ë^7p0|ûÍ×Ó: ‚ðó¯¿î?ð‡ÏçKMI~ÇíEÀg_~-üÆ®]ÿ3Ã0¯¾4nîç_À­7ß¼vÝz×sÏðáQQ‘ß/[^Wo8 ß ÌL)‹Ï¾üDZ§ÆŸ/.6füË/ýç… Î–•Wh5IoÏýç8|äÈêµ?)•ÊýûqתŽ=fµÙàÕ—Æ‘$ép8DQìÜ©Ã0¢(¾þæ[ÍÊÜ´t¯L˜Ø´–«kjŠKJ(Š:SX¸êÇuZí]wÜ! ^—”,únñ˜ÇFYm ‡çþõ>uÿm;vDFFöÊèÑê×M‚ ìÝ·ÜóÏ®÷ØTEQ‘o¼=­©xÅ%¥ÿôšJ©ìÖµkeUÕö»n¹éFUÀ ËÏ¿úzùÊU]»tùÏSO¾øÊìvØÿÇADGEõîÕsük“ƒè§©Á4’yÕk[5x†aƒÔoŒš-²¿Ý5m2•UUZYAr÷ò\KòŸ.8Ó¬þyžPÑ—JÚF´Ô4.²Ki¶É¨UªW&N:™J«Ñ;~‚aY»Ý6dð S§ š*a÷ï¿75¶À~oê´é»öì¡)*66öð‘£½zöŒŠŒlÖn›Žñ†ØÍ¶TÿNzM*ÈÉ“ùRnÉäšö¥Á{oQ[R˲WñÝ“eÙ ª«« ~øaÉá³ÙüÐC}ÿý÷ ÍS½#±ðî»ï6 íµ×AhuÖ†\.OHHX²d‰ä65 Ã0­V[]]½lÙ²víÚÉåòà‰ÜtÓMÒfAHž'AÈçD ÿjpÿ×êþ¹µƒÁ`0hu:½ÁðÄO>þØc?ö˜N¯o×.‘¤)‚ Iš¦hJ&—Ë é]ÿòkŠ@=<œ»gov|\Üß/^ðå}zõ:züø¾üÑúöé½;kËòï¾%É?ýügŸ~jË/?[ÌfǓڱãÖ_7Ü4äÈ=rTšT#E“F$}xdÖo¿Ü4dˆôP+E›ÿùgŸ~üÑsÿyæI“pßýûïâß—”¹¦¶vמߥ¿ÚººfKôì3O­]¹bü+/À÷ËVPuÓ4jõÎÝ{\n÷™ÂÂ’ÒÒ퓺uíêÑà/ݡù{÷í×iµëV¯\·zeFzzuuõºŸ7x½ÞÝ¿ÿþÌ“Oœ)œøúí“’´í’eËËÊ+†Þz˱ã'„&*E1áü|Ñêšjÿ#]àì‚ H’ E Õ55@QTLt´Ûí–Þ°ˆ¢È²lÎÁCÍÊì¿Ö_ºÃGŽ6[˵uuÒƒÔ²?ð·%kÛ /¿’ê4ÏóïÏú(1±Ý“?ø„!Šb‡¤Äþ×_×.>^Ú„­¸¤tƬŸ~î…iïÍØµ{O]}ý‘£Ç¾øúIÈÜ£G].× ™žD©¨%ñJJKAèÕ³ç„ÿ¾üÕ¼¹›~^çOdμϖ¯\Õ§w¯/>ýD§Ó}öÉìä`Æ´·wlÞ8êá‘®Ÿ¦Ó¬Ì!|³õÛRF­¶»¦M¦ •¤˜M£5•¿%ý7UÑÅ4ézM IDATKÛ´omëRZj2–<¨ŸVý°aíšè¨(I A4«„/>ÓÈØüÍœ¦éC¹GvíÙ£P(–/Y¼ré’ßÖ­Íè‘îÐÈn+ÎkTðP¬®¥‚Î=r2ÿ”F£– âwtEQlÕä!xïsèPK꺺o Ãð-“ŸŸÿàƒšÍæêêj¿j6›ï¿ÿþ“'OòWéÖ&BfþÀPRÐét ßÿ}]]N§Ójµuuußÿ}»víŒFcðk¡Év)p-#„@ ®•qN†cI L$0bÅÊ(šv8"8IØv–a} ãóy=n7ðÒÍ58ÎÙˆ3……ÒÈC¯~‹ôëwþãa‚ ¤R)äúëú2 c0諪«ôëÇqœA¯—"$ÙìØ×MCnðù|3ØŠ¢Ün÷ŒYîÝ·/ð†d³ÙôkOrôØñiïÍŽ§M}c@¿ë›V\ßÞ½½^oZj*”–•Ñ4-“ɆÝvëò•«~Û¸©®Þ wÝy§ÿîXºãyyÐ1%E£VÛíön]»ä:t¦°°®Þ*—Éâbc/]ªV«_û¢×ë]¿aI’j•Š$I–eI‚h$Imm­t Õh #–—a˜V• }<ò¬ÃálTä¢ââfe–ÉdJwìøñfkyðÀ?çé½óÖ›ý®ëûöô÷~úùçM[·—”äåç¿6a|î‘#ÕÕ5’ë{ºàLLtÔCÜ/“ÉH’”†Pæ~þ…(Š=Ò»Ÿ<™ÿÆ´w¤Ô¸ï^…Báñxöü¾·[—Îz®¡¡!ˆŠrmV¼»î¼Ãl2emßžµ}»\.ïÝ3ãÕ—^R©þt~ݸI­VÏœ>$I—ËØ–Ýn7˲§ ‚ë§©Á0 ÓTæàߨ\Í>`5ͨ°¨(x»kÚd4ç?£ ½²‚³¥!Pþ®]:7«ÿ¦*ºxiO6ðÞ=3‚7¶u)…gÏ6kÒ’÷É:hµZ»ÝÞ©cJÞÉ“Á•ÐÈØšvªi©©ñq±v»]’ üc#»=rôX£ž-«k©íëõ:Hé,$­SêÉS§þ,{k&×âÈUU—•W´¤®«†a‚LîàyÞçó•––._¾üÕW_€o¿ývĈ,Ë ‚peÖ¼õ¯Ÿ˜]³Aðx<Ò[§?¶H’ ÇÊå;ÚF ˆ«Æçäϯ[«'I’ I’ ä*% T«rEQ< ˆ@ÏqÇ9lvQ¿–õ(=µOJ|áü~AEœ÷£4µÏç ¼…PŲ,†áÒëðÀûPKSh¤Ç\¿÷…aXÖö¿gg§vLùhæû …bÈ­C¥%[J¡crò„ÿ¾,½}OïÞ ˆ¦>g½ÕªÓjm  R)¥[æð;nÿaõš×­E‘¦¨¡·ÞøÀí/V£‘RĨ·Z@¯Ó+• †eA )ša¯×kw8<^¯(Š{÷í7 aFc#‡Êëõ~ñõ7 ÓéÒ:¥Úívÿ³)†aåþ˜¡(¡Kç4IáKW¬xèþû¤Š°;j•J§Õ6+sÓº“b6­å0£‘¦(†eÃÃÃÜn·N§Žå¤…¦Þ}¦?òÆÍ[ŠKJ¿œ;§àLa½µ>6:Æl6À¸ž“|xž¯©©=[RÒ.!>:*ÊçóÀž½Ù#z éFêTt¶¸¸%ñ/øæä©ÓgÎløõ·»÷¤uêôÀ½÷HzöèñÇÁƒ¯¾öÚ´7¦HŸ¥á8"ü™W«úiÖ`šÊÜàI’h©~ƒXf«í®i“‰°X.´²‚󯞴eùõ:]³úoª¢‹—öÍɯ6ðí;womëRZ2 iÖʪ*)¼²ªªU%42¶¦jUu5ÇqR7hÿì¶iÏŠÕµTVn=¿êA(]}K4Uµ”T³êººaY6ˆß•””$M£õ¿ƒp:‹-€äääý½]»v5>`À€P.÷-f×l`KÔÔÔTVVŽ=Z§ÓÕÔÔ‚`±XFµhÑ" ¯oßtx9Ÿâjð9ý+ÈùçÖ²,#‚(ý9œNiªe¼>//ç'–p’Ãɱ,Ì­½¦t÷·åz¤k5šÂ¢³……í“+«ª¶ïØùðC.”ßt;™À™Aöã rÌñ¼ô>5ÿÔé­Û¶5û‰H`Ê–¨¨HɵnêMkmæ‡ßzó~Ý™ýûK—›M¦~×]·kϸñ†tZ­A¶ÀÒõHï®V«NÌýü F³qÓf¸qÈ ³Y!—ç:t}ß¾_/\ôÔÿ='"†ÁÆÍ[Ö¬ýiò„ñ[¼.^ºtÕš ‹ŠìA¯•¢(’$FC}½uƬÔ*圃¤½N÷ðC.Z¼äËoæ=~<©]»šÚÚ»÷¬\º¤%™½q©téÝ»µTË·ÝróO?oXôÝ’A™ý·nÛú÷‹°X^}iœ¤íM[¶þqð`Ÿ^½î¿÷n¥R¹xé²í;w>ûôSÜ{ ‘.—KÊQ¥RvIëDDCCƒ g +«ªn8Húô4ˆŠºwëÚ¬x555YÛwtIKKnßþpTdaQŽcþYS_í½™³~ÏÎ~kú{S'O"IÒh0À÷ËWä9:x`f«úij0§ Î4•9¸ÁËd²–ê×­iFAj¤¥&CQÔ…VVvŠüy'Onß¹«‘þ‹KJ[RÑÅH›””h±˜ý œaÙPú‡ íRZ2‰”íu:]YyùØW^U*{÷í÷_Ò¬hšndlÒüR§ªÓéJËÊ&O}+#½{Yyyz÷îþ5·ÙmÓž-«k© ñqr¹¼°¨èãOç*äòÝ{~÷_Ò“ké¸gô–ÔuußLƒÏ©Óézõêè7ò<ýõ×ûCÉ‚çùwÞy§Qà믿úåÒÿíÛ·7=Õj"n·»´´tôèу¡ººZr˜Gm6›~øá… RÕt ЖÜN¸J|N©wÃ0Ìÿ©Ñj)’$(Ф(i6NàÒÛYA^ày^ò6y–e9®ª¼àZ_Þ ×OûÍ9ó>ÿô³Ï¥öI‰f³érôà7o>~"ï¥WÇßuçÒTÌà—‚ žµDFzú§Ÿ}Áq\§ÔŽãžÎÿôv÷ð;$Ÿóîáw6zPÔÃ;oNýéÜï¾_ µz⫯\×§·Óé¼{øÎþdÎG~5÷Ó99±±1V« úöîe0¤Å¨$N. iÚh0ôîÕóчGvNK“æ|>=ḟŸÌÙ´eKRb»ýûíØ¹ë‚”0jäSxøâeË~ß›ýûÞlÇ{öèf4ºÝî–d½–Ÿ||t½Õ¶yëÖM[¶ÈåòçþóÌÁƒ\.WlL´4 vòÔ©?LîÐ~@¿~~ñd2MÓÒZ£\\ÿÏß³³;´o8ܬŠô:]³âÕÖÖý¶ióÊ5?úë÷¾»ïþ« É©“'Mx}ÊïÙÙï̘ùúÄñ#¸¿¼¢<çà¡ät霖\?M ¦Y™[¥¥ú b™mkwm«¬–ÚE«ò ‚ØTÿK–-QE*m`<0ó·M›.¨¥5 †–Lbú›Sç|öYΡC½{õ¼ùÆ!¿mÚ¬P(ZR42¶Ø˜˜À÷Dï¾õæ§Ÿ}¾%+kKVI’½{õ œ©ØÈnI’ Þ³]PõêKã>øxö²?DGE]×·ïŽóþÏ%ìê•JeKêºê eWd™LVTTr¹üBwQn6¾´Oè—7õZCLÄn·wíÚÕl6×ÔÔ|÷ÝwÒ÷Ûß}÷Ýc=f6›»uëVUUd¯øû÷œè9@\`uuuÒÑC#xûÍwn><61ž¢i’¢(úO·“$IœÀ@àîüð&˰˲ SZXüóO?½ñæëË—þpÍ©à ƒtá8Ž$IAN‡Ñh”Ö¥t:<ÏKil6›ß‘ Ñjµ$I:N†a”J¥\.÷z½ÒÞ»Ñ …B¡ðù|’«æv{Tj•A¯÷z½2™LZ±Ù|ƒsóíwú7~àÁb6sçtþù¤Ýá¸ä#f“iýšU.—ËÿÌÝ4éûLŽã¤…Ýn·Ïçãyþ­wß«¬¬zìá‘Ý»w“†=~»øµ ãcc¢ýwV½^/ÝÑ¥Û-Çq^¯×?—IEŸ×)·K›¤«• “Éœ.—Ïç3…‡+ –e¥/l›•¹¥Ò5[ˆ±,˲\D„Çq¯×Ûèa½QåªÕjš¦Ýnwðÿžyþ… zjÌãþÙÅÁUÔ¬xàc·Ûc0èuZ-˲N§SEéDQÔh4Ò÷¥N§“$I•Jåÿ™eÙfõÓ’Á<õÏ5’9Dƒo©~ƒ[f(í®Q“¹ Ê ž{`.-ÉOD#ý|lt]Œ´MM(”¦Ñ†.¥Y“(,*Jl×N§Ó¹ÝîGŸxª¸¤äÝ·ß”9 Y%HFØÔØå"Š¢Ýá0…‡ËåòFÙmcß84«k©ícæt¹¤¡WŽã{›PL.”Þ;ˆº®âûæÂ… ÓÒÒZõÒëêê  C‡Á'£6å"çÖ¶tyˆ‰¸\®S§NuïÞ=777666,,L*NYYY×®]>œœœd¯”¬¬¬Ç{Œ À¿€-zfE WƒÏùÀC÷M{kúwÝÕ†TÖ¯];eêä–¯B •žT¤ÍʯäJiùÓ‹ÌÑÿl-£éF£ß|4{NŽÕj:ùµ;† µ|àD)€´•â–­«~\+}yh1›ozۘǕ–1 ]½’mƒ¤íΚÖQÄC¬åÐS‘Úº:ið§ÕªVÅk©Ô”l`éZ2˜¶ÉDA,óbÚ]ˆ•Jî!Ú§_ÿmPÑŘVú‡/i$Õ;3fî?pÀl6UUU{¼Þ¾½{Íý±ÛíöþÝ6#¼jKê•ò½LRµª®«’Õ«WÇÄÄø'B_•¸\.›Í¦×ë}Ëf›²yóæG}”:ÿÆŸ$IÇ¥ÿèù @ü{ùk žàçŸ~jC*Ò÷œH›Ú¸Ò+*]'gÔÈr¹\­RIßy>HÅÄDkµÚŒé7ß8$plp=4zÃqüÖ›oºëÎ;¤p•J%ͼ áƒ<‡žNK1C.o©–/ùl¨ð°°F«OµY¼‹7’F¥kÉ`Ú&s±Ì‹iw!VV(¹_¨}¶AEcZm¨ú/i$ÕC÷ß×1%ÙfkÐhÔÓÒô»žeÙ@ªmFx:Õ–ÔDà‹—ªUu]•DDDx<¹\~—Q«ÕjµÚPƒX#š[‹@ ®&þç¼ûÞ»†Üp#E¶åÕ#˱[³¶ü¸z-Rè¿ék"¯×ÛôV§P(0 ã8î’<I«Ð õ*6˜iFÿÀÜÿ]AÓ4†aÒÄ料"®qu;wîàÁƒ ¨ö›åçŸ~ä‘G¤qNêü²H9âßË_ãœÉ’7oÙÔæ„zôè´yd¦_æI=»_õó/Íè˜û¿ žç‘ºº‚`±Xt:Ëå qÐïÝÄÕìsŽ~ìñÝ»wK…]P†Q5lØ0¤M@ AÀq¼K—.GŽñz½Á· ¹–}N4·@\µ>gBBBTTTÛ:8ǯîo3@\t:]—.]òòòÐPgŸ³é1@\ >§´€;Ò@ ˆËŠ^¯ïÙ³ç¾}û*Bñ<âêñ9@ ® Eõïßé¡{öìAÞ&¸ú@Û=!@ ùœ@ W;hœ@ Ÿ@ œO@>'@ @ ω@ @ äs"@ qaÛ+%kûŽs••þŸ‘;ví<0sPf&LöŽÿøâi” <(Âb ±54<7ö¥/æÎѨչ××[J…B.¿ ݸ)22²{×.¿gïcYvà€þ—¶tÁù~ùЦ†|ðK•Åŧ ×^P‰^{ãÍa·ÝÚﺾ—V«YÛwètÚŒôtÈÆ-["-]»t¾LŠB @ æsnÚºµ¶¶6µcGé§B.&ý¬«·º=žK%G£¼€a˜FqDA¨ª®x%™üæ[wÝyû-7ÞxA9ž«¬Z÷ó†Ï?ýÄ"ÂÇŸÎ}ìá‘Ò¿ÜTVUI‡çRÙ9- püRA_LqÚPÑT¢ºú:Ï¥3¤@‹Š‹‰ ô9×oøµwÏŒà>祵j@ .”={öç!Îs‘OÇ•••@LL I^é½ÙOž<ÙüÃIÀS_°[s]]uuµL&‹‹‹“„ç8®¤¤ÄçóY,£ÑürQW®\-W`$!ˆàá9 §eÒ e”€ã€MÓ4I,G¢µ¦®ªâœ×ã% ¢¦¦Öîp0 £T)Õj EÒ¢(Ð%pœÓåQT«U"€(Š Ÿ×"`8"€(ºNLƒNi±DEFEEXô:NàN¯³ÆZ[~®ÂfÆ0R.Sª•jQ€‚‚S ¹<6&R­Qƒ(pãózO:Å2,IÒNN´À Çj³±«R)F£ÙbÖh4޳,ãóxŸO‘p Ãqðy}g‹KkjëhŠ2™M–K¸)æe Çx}^ËúŸËíq8œ v»Çã 3Œ‘‹)ܨÓëä2º¢²êðáÃ…g‹jkj*e||œB©ÀpÌérzF¡P`Æ –£ä2œ ÃHš&ä4!£IšTÈä§A¯Ñ†‡à F‹Ùl7û/@Ó”Ã騾}ç¾}ûÃôFƒÆ WhÕ µÒíñ9Ý./Ãà.W*i¹‚ H’$(Š¢h'@&“‰ïõºQ¤)Êåö¨T*ŽåxŽ'psÚ,Ñ$% "Ër¢ `AÐ4)"ëcxžU(•Ïs¢H8-§)šLXŽåyÎ`4DX,>¯Çíö‚(ˆ‚ÃfW¨·ÒïôèÞýÿžyÚÿÓÖÐÐÒp¢ …EE,Ë%$Ä_èc³yùq:]gŠ Í&“\&óÞvËÍR.v‡ƒçy§ÃYS[KQ”^§ 1»[o¾q銅EE‰íÚI!ûüár¹Ì L¿¥Òy¼^ÆçÓétàóùì‡)<\ŠYW_f4†~{xeì‹ÒÁ[ÓßU«ÕþŸÍªTª–åÎÆÇÅIï–-,*ŠŽŠ’ËÒ²2§Ó•””HST#uùSà8îLaQ„Åb6›ü’TUWWVUéuºØ˜˜‹¹½µT¢ éÛíö¢ââ‹Åb6ûË+*jjëT*e»øøK~lÕb%Eù|¾¦‚!q™HLL¤(Š¢(2€‹¹)swúôi“É8Ž'%%]a·Óív7ž’’¢ü§Nòz½†%%%‰¢xúôi‹Å"—Ë“““[-‹(Šaaa‘ F8A¸xÖ+òvÆÇɵÅ#3hy #$5 ˜Èr>‡Kð²"†9\./˺†Ã1¹NmT©Ôj Nà¬Ã0LFӌϋ œR!ˆˆ¨ª¬âXޤe '`€Ée Ža]AÒ–pStT”^§ÃD ãlv»ÕnõñœZo«µ ™R©Ð8éóz’:§uŠŽ´èujš&A\Žœ\N§Z­¨­©e\>µ\mŠ€xDQ®”ëõz“Ù$¢ÝÑ`·7à€éõz­ZCÑ´B.WÈå8à‡#ÌQVZ&“щíSR“Ã-&çp‚`9ÖÇ2/p¢PSUcµÙªª«KKÊÊ**ÖÖë³Ö[kLáÑÑQÑQQ‘‘Qv‡ÃÃzŽ¡e´Ú Ñët,Ϲ·ÈàJ¥V¡Tbæõú¹BMÉ€¤}>/ëó… q1±aCX¸!2"’¦èÒÒR«½^©VÄFǶoמ Iy…2**6)±]lLLx˜Aà Áf=~{CCUEMia1°bx¸Ñd2Ë5jB&ׇ…9Ý.Àp^pò ­ÓžÅ)’¤H¹R¦T(¼¬çXŒ$åES”L.ì ޳¼G$1À 0™J¡ÒRE3 ãvºX†•Éd†8.ð/ˆŽÉ5‚"E(Š)å8‚(Á qÂïÙÙ§ θ\.•JõéG³d2Y£âL˜üzÇääC¹G´Zí™ÂÂgŸzòÎÛ‡ÀÍ>rì˜Åb®¬¬Òj53Þ™¦Õh.á-'Húä\´xIxxø©Ó§{äáï»W„iïÍ8‘w2!>¾ÁÞ ×éf¼3í ŠÅN˜üz»ø„c'N ††qY!š£Í>'˲………>ŸOJÁçó¶oßž:ÿVú €ãx=ΧR©€Vàua†0C˜B&x^EÀãžó1n§Û ×ÅÅÄ&wh¯P*ËKK Y–uy\8ILF‚¢ ‹ÎFZ¢ Œ¶{ì6{ZjÇä¤$…BF"&Š>ã¨oP’TT|;‹%Òçc‹)E]m­Œ âãâL3†ãN·Ëérϳ,ãñzœ.—ÏçEQ®P`<Îc€Ñ”R¡ ”²p³9¹c2ëcTj•Ö ÓuN€ðçP•È‹E†é ¢v‡½àtÁáÜ£µµ5n¯ïô©Ó‡sËå2£Áíõ¹y5†x‘³ÚjõF¥r¸T.¯×˰ÅËå ·×å­¨V*$N” Oh—ؾ}¢À2N—£¸Ô+±cǪëª,&KBb‚Π¯(?@¨”™L)—)4­ÇéÐ Zµª¬¤T¥RªTJµR©7êkkëëëëX†±ÖùX–Qª””Œf9Ï rJ&'d:£ž¢i’’ÎÕÖÖ¨Ôª¸¸¸N©qg¦¨°¦iŸÏ‡ã‚Ûí*((¨¨¨P(5uµŸ×d6+TÊÒ²Ò§@°ZëhšÖéôçÃ1Ñj­Ç“ËdEy<\bbÀh…Be0Œ¦0V[ÇzqŠ”)ä¢(¸½žººº³%%§3<<<2:Æ`44ír¹óòóí•U 6;Žj•Z0p{¼V[ƒR¡Ô;ìN—‹¢H—Ó‘—wbçŽe%¥QÑQÑQ‘Z£ž”É8ÀV«ÕfçNF Ç{nFáAàxA$IcŒ›©®­&L¥Tb5ñN2,+p"Ïñ>ÞÃx1Ì`”ÑAP"Oc Pîó2N·Ççñ2>0L¦‡iÂxL`8ŸHFb8á8.“ÉXŽåxœ¢p†e½ŒOÄ@Ñá°«8W_Wg2…éušV|΃‡øÉéxøí··ôiæG ˜9zÔ#°wß¾™~¼dá|YÀ°d(Ê=2{î<ÿÏÿ<ùMÓ³?÷À½÷<üЃ¢(¾;óƒ¦WyìÑ9Û0·n¹éƯç/|êñÑ$IÚíö}¼ûÖ›!–®k—εuuçÎEEFOrؾ[º´èìÙ¯æ}*—Ë—,[>ýý™O<öè«/cXöÉÿüßö»n¹©µäŸ>ýÅÜ9J…bמß?øèãÛ‡Þ†ãøèGñÕ¾ý«×<1ú±KxË ’þ‰“'?ÿôZ}äè±ñ“_Ïì×ÏãõÎÈÑc IDATÈ9¸zÙ÷R‘[zEzAUyþƒáÐ-¶©`‘‘èy@ —ÕCkêp†èž5åôéÓ>ŸO£ÑHwR¥Rév»Ïž=â¼ÖKèE‡$…”””¼¼ñæûrØ·K,a E€Mªh²ÌàPe˶LQ¢LÐ"ªhK–dÙU*X 6IJTf¹hWÉ-R &Á`"@"‹Mo_ºïÝwó¹÷ä™39ôt·?ᥥ¥¥¥¥w.Cƒ¾>óüÚJ“$ɲ¬óçÏß¼ypùò凾•$ök Âë/÷e~MÓ< Ž œó7x:cìÑ)¬a –‘¬ÈE*ºÊÒ4ORÕµ SO³¢¬¢:/“y89ЍCI"”ÆyÎ%Œæ¤2 ËX€bù†‘„ÑÙdœï,¸Îsƒª¨hMhEŠ$Ç’¸Ú[ñ-g6â㟬ª*XÓù¬ÝnõWVnܸñøãK":;ïï¤Q 98»ùÂKû÷wÚ-×qtRqn¬¯õ:=S3e 5e5 GggÃ2/F“ñéð,Œ"ʨåØqžÒp§Y§Éb±¨ÉË<;¾~õšaè2’‹<ŸÏf¢$j²ªªjÓÙl^diG„Ñ­­Ís›‹Å¥'üöÝ[£Ñ€ÑÆR5ìªÌÂ`~rr"¢i»Xч–ã"I–Â(GHétZ¤©TÍ0mÓ1 Û2ª¦üŸú„ŒŒ‘¢k‚ !eYÙ–ETÕ$Š£ºÎ'ÓéôÖíWƒpf–¡kª¬”E9ãEäšÖõkWn\¿¶ˆ¢¬È¦³i8&émùP8á@Ȳ´¬+×uè‡h6™Þ¼yó`o?Ž¢¦i¶¶·Z¾»¾±Ñí÷âE¬êt:ßÙ}X%Ñ,˜ôWzç¶·Ô [ë+w÷ö÷öòÍ<Ü5-“sžg™é; ÷wLf3ßuu]‡@ 5©ëÊw\Àg p +(I*R×ežÛŽséü…Ë—. €"‰+ªl˜ª‚Q‘g³ù°¦ª‰$æ’¨h†nNžÁ,Èâ”Ô$E‘°ŒdE"m7I¢ãã#A’$2- \„yœC]×õ\ß2m$ñ¦!dãñx4ÊŠÒj·£eYÎfÓÉdŠ1v=·ßíµ»×uŠªøìç>ûÒK//q’¤eY%iÁíÛwú½ÞÆæ†çº—/]γ¼È3I‹,¿}ûv†¡Ûë^¿výæ­[’„D Ô¤JâDÕ”élb:ÆÒæÖ:’Ľ½‡óiÀ‰ ‚¢ ²ª9å’(b,a¦nzF¯Þ¼ùüŸ)e¤®×6zº®ÝÙ¹5Í9ã–åHÉŠ’fyšçH–{½þúæf§Õ†¢‡Ñéàl2™U5q\×´œ••þã7ndi¶{ÿþ­›¯Î¦Ó‡É® ¦iØŽ]–E¯¿rîÜö,î?x0œd£!BJ»·ÚÚYo_½zeksr6›Ü½{ûÁνx5u#pPÕa†fÍça¸ˆ3J“8:Ð( -ÃH£xtvºCßót]W5MSÔN»­`%K’ápxçþîý]Z¿ÛqmÃsŒN·£é†ÂÆÊ !UVÄ»{‹,‹¸@¸ÀMÇ–e¹ÌˤH$I Òh0F³¹†¤–ãkªâ8v§åš†ž$§d1OÏëuZmîgó“áp8>±ìz¾n™BCkÊ"Cˆ’ @®iªé˜2Q˜fiÇ„H‘mÓñ[ÛµUMcŒ+ ŽŽ‹œ×UÉhc˜–®9šªºž'   C±ÈòáÙ¨,²•^5´&$œÍ8]¿-Ìçó·«•,Êr6›9ŽóÚtÁ·EÓ4gÃ᣷íëøðÝÝ7ÔEQ”¦éJ¿ÿ%·_¥üšÑhÔòý×– bŒM¦Ó¦iºÎ;´¤ûWïþø_ÿÁøoý–÷~IÅ––––––Þ!ùÈG¾ÿû¿cüÚ#:BoK?ç¿É~æg~&Û9IJêø.6ÔJ)kYhm­ž»qE0ä¨*ó²" ­Š’ÕõÆÊšÈÀÉÁÁÉÑ€3îû-UWã$⤪ª(\œ³ÙÚÊšc˜ñ"ɓ̳½oz×»OŠ8=¿¾¹ÖïË"ÚÞØ|÷{žzpw÷?ÿ' %O<óÔO=DaÕ]ÕT(’` bM“° €Fq¾»÷ ¬ó¼L&³ñÙð¬®*Ú˲MÃFXm8‡SÂY™åŠ,[†©ÉŠ¢(ÓÉDFHDI,ËX&„ôz=Ó4Ó4;=;NÇNÏ/š*ÉÒx±‚ ÈJÏó4¬FQ¼˜Ï³,¦SQ„Š¢l¬­®¯­:ާY²ˆ›šð† ôzNÇç€ÍÆÃ;wîž)j¿Û½tåÊt4N‚ ®ë,Ëâ(ªëZ€ ªk,ËUUцZ–å¶ü££a’æX›²¼çn¿×¹ñøc«ª$ë²þ¹ÏN—µB*ëª.ŠBÓôv·ƒ²4N³Ò,¦¾ïk†ÁEѳ¼^¯-!4ŸÍ<§¹ 2(-[¢¥¥/ëÆõÇÚíÖ2KKKKKËœóÏ{H!’jÎҲ⠌ˌ"€ M5tQÁ’‚DEf` « V°LjRW•,+º¦Æ‹EU¤&i–Fq\æ¥$k½žgÙ*’ÃÉLQ×kÉ¢49ŠêwsÛ[Û››¶a[~{ccmm}­®J ¶çHÿòQ8´¡“Ùhpz6™ÌÒ²”5ÕñÇw¨Ô¤e¦iHÑUUÑŠªb ÈŠê:‚ªÊQüh•ÙšS*‚ÐPÞ4ƒã“p0JU•D1Š"BJ)–eEUt¢AQ@›†©izËiÍ&³<Ï"tM+‹²ª69§¤®óïözžëVE~t|tppx|tÔÐF3´<Ï«º¶Ûr\,!Û4Ë<¿sûν;w×WWЬhynYa¥Q*J’mÙŠ¦iºÆ8¢P7µv·DA B(Š\à mMyTuÍoµÚ݇ÂÎîîË·^ Ï$Ú¦éx®e˜›Û[¦keUYRÕÕÉpx<T5ñý–„Pœ$v_V”²®Ó¬¬iÑ” е IDATLd×÷úݵ®ß©²CÁw¼¼¨Oö><=9‰“n;n»Û¯olbCŸÌƒ,ÏU,[«6ÄržçEUCQHÓˆd‰bSÔ)ˆ³"/ËRÓÔº¨ò$iêº(‹Efi¢È².ËUQRÊŠ¼œÎgIVz®gZV¡h€¢,³<—D”Äq«íCAè¶»ç #9YæœKK_ÞÿØ.ƒ°´´´´ôgìµÉœ_2¥s™·’sV á@1âXY©™ªÞqÝÕ¾Ûi‹†Ü.(0^%­жãTR!k(Y’.!!ÄÐTS7T„AÊ´hªC‰VõhpæXöÅóç¶Ö7¯]¾Üö}JšEÚ¶i™+ý•žeœSIUMå„ÔU5šMÁ|< KR;ž×mõÚ½vN 1A‚¢$ÊÐÇH®ŠšP7„3F›& F‰†°EF))«¦&XyÝÌGãiò²@’äx^«ÝBÚuéu|[7(ãy’¥‹9P‘E1ÏòÉdjèZË÷E%¤Š¢E#„¤éx¼Òë?víªçºál¾·ûpeV` õ{ý~wU‘uÏõ÷w<ÈÒôÊ… Ï=÷¬¢©{î¦Y³v§³¶¶V’çÅtºEùÃÝÃùçAxpxppx§Y¯×UU#l˜–nÝ^/˲»zçÞÝÏ~îs³ù\É yžGCëkýž,ãh±˜N&{y‘Å©íØuUÍf³†pU‘]׳[Ä8ÍÒÙ|2œÃ08§¢MÅÅq%qèëÓš5óhQ Ó?yá £ñÈr,Dz$Iì®ôÛ­áÉhçiݪ(§“IZVªfÚ–-B‘5àüúyøá`P&¥ ŠP•ÂiÔÁ󀩫ŽÓ¬‰Óôäèxp|4ÃyÈë÷ú¾ïµ»Í­sÛ.4‚0™ÎÎNÏ’,7=¯Óëj2öcÜ0FHà ³5«( ZÑ:«Š,«‹B„BSÊH]WeUDAµÖécˆ’¢H£¨©%]Ó, ¤Q’æy]×Q³Y§Û1t]à\ƲgÛy^.sÎ¥¥¥¥¥¥¥¥o iÙÏùöEÀI–$MÉ‚,ÃjùŽï–IeÈH­Éª ­ h˜Œât ÏΦÓIUÕa°¨ëÚqœn§«`œEIÎYMM]G@‚ŒCÆWzݵյ­•þªaT†š¦ší–i†®)2†Te><äIóÉlFRd·ã–åø¾¬«q‘Ÿ &³±j(ëº*«’T¤. ˜ÔMCFh‘¦†®˜H!¬hE)w S%ÀA-@óŠ"ËK½‘Ô4MMê(Z‹Ö5IÓx¸w6Dqtîü…v»=Íò¬˜Ï-oq´ÈÖë´W:Ešdi’H’fêŽk·;­*UE«i3ž–YIkºÚ_DID¨,ë`~|||R…çyª¦ ʪÚë÷ÛÝV·×-Šâøàp6™.fišý•¾mΟß]$‰2™…³™cÛý^·ÛëkªFeΠ” '´i U.J‚ÐÐ*Ë!‚œ7””¤Èó4‹%YW2Ë@Ã=Ë‘l¨ºŠeJ(h¸*« ³8r@Xd©(Šëkëq˜-sÎ¥¥¥¥¥¥¥¥eÎù¯sHeU©J—$AÄÖUÕÐ$3¸(`I¶LKÇ*­H‘f¼nŽ'·o¾ztpe§¬&T‘å^¯×ñ[Y’.Â0ßq}Û“˜¨H¸ßí]¾t©ßëù^ I©*„¤–çÉ™–8Ë‹¼Ì³ùtr|rÌçãÙbióÂy¿×q\O7¬†óÁèìî½{ǃcM—t¡Êà`2>|¸—¼zk0™œž0ÂÊ8 )“8ÓN¯ç¸ž¢jYQpÊuY—‘ ¥–ik)hTC®ëbLH]Š€ÏNUY§ "„Ê›š¤q"" 8@"’$d™ö£)Äy–E‹! ox4ŸÓ÷ýe{´´´´´´´´ô¶»{÷îyY÷^6ïßpy^6”V€0Y€X0,E·(²¢N ºUåYµH’0žN&e–áóÏΆº¢ùšVÅ¥•µ²(TU+‹2O3Ë[ÝðL+‹¡ží®­¬^Ü>oZ¦*«ª¬–À(5M­.ë0'ǧgƒ0œN=×é­õû›+óxq<<ÝŸ–y‘$+jEÈ" `¾ßˆçaÅeY ªµÒ]± KHÃXhj$‚"Ï)¥Ba(ˆU]íïïçUÞ²Z«ë+Š¢…‹režçyžYzíÊeJéb1Æ}¯ÕjµîÝ»wûÖ½‡åCÃ0;Ý lÿáþ[·çóyÓª*;ÝvÛoiêqžä’$¥IÌ£y°0u³»²º~îœïºŠ¢Ü?Ø ²$'¥Pà vîÞõ,kûÜö¥íóÁl¾s÷îàädoçÁ•Çnt{}†‡ÇÇövm×)²³¿+)¸·ºòü ÛnýÁ'>±³sOKõ Ûœ²­•U@Áôèô¡I°8>>:Ž ÃP0Û¤¦mH‚MCM¥œO¦3ÛóVWÖTUOÓììl¨ d{î"Šl˲-³jêÅ4Ȳ¬åû¶c7”Nç3Y.¯_½qtp|t|0œ˜¦©ª*’¢É†¦º^F‹¼,Îßnw[¦azžç:.äB§ªªA)mÊ¢èt»u]O¦Ó$IADy®«FÛ÷Ûí–Œð|6;8>P(B  Ȫ,Šb™ç„#‹X‚Ãhq68iʺßéÙže•  ¨J© #£³àM»åùm/NÚ²*m­¯ý…|û"ZìííßÝÝ98<®A ¶|ûÜ…ËW.Ÿ?¿®Éà·~ë7n¾òòK„t{ýþêFÕк&ç/^pJ‚¢á–âÊŠTÓª&…c›Û›Y”¼ò…›ME,Û‘& -ò\’•Éä,Ï QBHÆ]7{½Ž‚åD” ¥ªª™ºi™Î²ŸsiiiiiiiéÈ—to.û9ß:Þ4‚ÀÎÆÃ“s_’HšT \J/æ“ñä`D3ZæÕt6M&Fõ•v»#‰¢ïûq°H‹,ŠISÉ2:n‹”U4t¤¶=¯ãy¦¢®¶;"DEž¿üüÍWnÞœÍǶcmmo¾û=ßÜíw4M>9=¹}ïέ‡÷ì#Yqm§Ýnó²ÈÒœVIJ¬ùÉ$Ͳã£Ãx™¦ÕòÛb)NÅqiŠ,жÒöÎãI²¦êšæ·ýº®eCΊ\”$ét6šL§–iiª&0LÊüÂæ!UD”Ô¶ítÛíº&yš»®ÝDÅ2M?õ‰OAè[Þ…­ ð8Y¨ªºÖ_—¡*2$2©Êêd‘¬¯m\¼tyckSR”iå³Ñîð$Èâ¶ç]½tqsu…TÅïÿæoiš®™F”f†¤\Ù¾…@’îhA<ï®õΆÃ"ª­éèÕ‡Ž'ã8\¤”Ë–Ë=;>v ólçÁt<;º»ãkúÓ?ávº»ûãɤ®kEB¶ªÉ)²L!¬n ‘TׄsáÁÎn„kkk«+ºax¾§FšeÉ(:9>úØÇ>VVÅÚÚB’,IŠ(ÕE¶µµ®©rU×BR‹h.IRVqEV]߉¢èlt‘(Ip2<Ueì8Ö¥k=ßÙÞZÇ>|pxóÁ«ÇÓ³Z`’&CAvûñÇŸ~ßûþÂ3O?µºêééjËü•þkô™/LΆUQRAP”U¥Ç™¢)y™9Ž‘'¦ckª(Ÿß¾PU¯¿Òj·*JkÊ:î"Š&Óét:åœ/‚U¥e™É"šŽG½^/‡³‡Ëœsiiiiiiiié_gi‘-²xÏ$KîTI•EDª'"˜Æ‹hž¹°æ­éª!!¯JÓ²€ê¦iXãµ|A„®ï6uÕ×uVֳɤH3Dzέnn¯oö;ý–ïÊ®krz6:<<>>:žÎ¦ívûÙgß½ºÑ·\“s6šMOvÜŸÓ¤ÈeÓ°WÓ4(c JŠÂ8¡€¾ßñL‚˜¸ÐBH…4Œ«¬”D‘s.ç:ª®8žÛp&‹(O×iõ;.¥UUUeÅuzÎØä”“š!׋ãèìl9c¼Ì‹ñhœ¦©šŽßê÷û¾ßfŒæ3ä»n«å˲"`}u¥×ïëºvvvvtpÄ9猚¥éÚêÚú•«W%ïÜÛÛ%¼Ñëêëßñ¾o»~ù2Iâý÷ïÝ=¸¿¦iÓϲ™kÎH] \’DX7œò¦Ýk/ÂŃý‡Ó`îÙ.#4 cÛñûù,ÊŠ,ï­¬>yý±KO>á¾úÊ­;wΧ$/ʼˆa´`óšÖªmJ*N²d4=_<ÿÇŸÿã£Ã#Ë4dYÖu]7Œ²®Š"?>:¼uë&cìܹsívÛ¶íË—.ÇãÓ³³Å"0lÑÄE¸MΊ¼´m›2R7eY•XVD Ž'“Ù|Nêº,˲(<ÇW5EVP¥§iÚ< Æ“i½¨jÊ (ªª"J˜¡®ICiQVV£$‰³¼©k ¶aö:-ÇÒE i\C ‰òáéÙl6CHÑu >MEU¹žëØRaÙ4¦® ŸÏgH‘ [×,“ à`p< çTàŠ¡ëªehÖæÚùozöÙs›[ ¡§GœÏ‘6úýÕnëx0¬²«†(¢"NÍqEª¢ÌmÛØÚ^"DzXVæy§uY—f^€bCU3ú½ÎùÙÙÙ`0XYYA’$K0>ŸNe"ó ”°¶Ì9ß~O>ù¤ã8¶?õ©O-²´´´´´´´ôutÿh?§%—[V'q@+HD&²æX¾ãªPU™¶æ¯jŠaÆÉÙ)c @€q.IRCˆkZÂÎA81Ï]ÙzâúŽ×‘iÇîïN&³Ñp<O³,kw;Ûç¶:½nê‡û{ÃñÙh2Üypo2c]µZ¾î¹a*‰gŒQ¤Ê¦aXšåY6#´ßêrB›º)ò,ŽBHCš²,Ò,Fá"%h9¶ª«˲:¶e[š¦Õ5Y%Ô±íùl>몖 4X¶%b–eQ•U%EFHSTM‘9ç·¶zý~Y·ïÜI’äò•Ë—.^@¥i:8$q"c¬(²ã؆®·[-EWφÃñh¤išcÛ/^¼téâÖæf“¦ ÏNN²$-ÒL·L!¸…Šº!#×¶A¸¶±žEÉÑñááÞÁFUÁŠc9½N÷Âöº£âýÏþÁ§Ë´p¯ßí­ôûçÏŸ?›'QBEõuÓPµÁàx>› iÜŒqÏûäáÉÉ1ç\UUŒ±iš®ãFÑâôdpgçøèÄÔtÛ´‘(µý–ëyýnaÿð È3BHÇœsǶe—EÕBj"•¥eÙÑbQE]ׄ2ƺnpN;­îÖÆ¶„%BÙàt˜çEÕP !ÍÀF”ñö±GÛÏ>ûì‡?üá«W¯¦iúéOú#ùH†¯½ò«ÿuiiiiiiiéëh”’Ž[ݶÙó‰SwÝnû¶ï Ö9%4D]„")N“ŠÔ ’„hÓ¤I‚%©®ê,IƒÙ,‰ =¿½Ñ_][[UT5X„Óñt4í?Ü_‘ ˆªª¦éù^ZdówOG§£Ù0JA8;"$*–ŽëZMÖ4I”i$Œ[­Ž¥@¤ªia(ÕeMʪò«ºªAàœçU¦‹0‰Æ“ÑàtE(aÉ÷ýº®¤‘dš&¥t:žpÆuU‹Â(˜ÍiC5U—eymm¥Ýie5ŸÍuU§Œ7 U%‰ã0š¦iµü«W.FÃû÷ʪ(ʼªJ¬`Ë2¥^‚Γh1LÛÊ“4˜Î Ëè´Û-¿%‰RÅÑl2 ‚EA0T‰8+JÝÔ½n;.Òi4Œ‹\(㔕ÄCVEM45‹Sl{ýNçÊÅKÏF¼øùçII$ ò<'u]ECˆª©mÛ½¸¾Õö<ßwà8^Ì‹c|CÖPFDZmËBHÂAAXáÞÞÞàäT‚m92’EA¸ ¢¡›ç·ÏsvîïL†#@Ëó-êêpRÊ(¯«º*˺n!$I’’Bè·Ú+i–FQRuY’šÒšPÎ!€’E ª*A€ V0ÆcR—^ËYYéêº<Ÿ–E^ˆd›NÓq8–±¢kn§½rþÂùÕõUÓÒë¦ÏOŠIÈïôº³Y°MIÃIô Üw<ÏT=b Mc-¯µ¶Ú÷=³,£i³¦6T¬a¡.ˆcºë+ë³q„)-ÊŠ4 c‚()2–° žM‹*ÓtEÓ5JIÅ’(¥EœGóHÕu.À,J£Y8Â(Že,ŽNuM³M Bž¦”†Ò*[®[ûø‘ùÀ‡>ô¡ŸÿùŸÿóRgJiÓ4¯íž;wîÙgŸýèG?úh÷™gžùÌg>óâ‹/~ô£mµZ?õS?õíßþíï}ï{ !ê_—–––––––¾¾ô®£·,oµÓÛ\áè­ö[½Ža›Jy^°(›ŠÔ¤fMÓŠ"¡B”ÐE؆9Z$§''ƒƒ£2Í<Ó~êÚ+—/c„www÷÷öö&£IUÖºf¬¯m´{]Ó4ò*éæÑp2ŒÒÂ’¢ÉyU(øí–ë{²¢ YF´-[ Ê „±ªª¤&ŠŒÑ4˳$QdÅ2 ªÈª¢¦‰u™@>œŽïßßÙßß›ó¼Ì!„’$¦“Ižçá< @d$# iŠê{þ3ÿ/{wlÙU íµ×žç}öïòÈcyšÖ«uY–9–×U=ÇEšæI’æyî8ÎÎÎVžä­F‹ ˆÐ -ËÒ*úâêš$J¦mïîîZ–EQ B(MÓ$ýÿVž××Öów:ýý½¶çù’"#š&)T‚2NÒ$NÃ0B ‚@BXâ"Ésžc×VW¯ºâò+Ng4ÉìﵿÔû'׋8Z¨×çqA_;1??¿¶¶®éz†;»>ñ`Zš&/,,zc4žÚcÓÛ%@Š@ò”˜xØ™ -.¬,-Ï«ªàØcß3IU ô}{:÷û¾ç†£Éh‚ÓŒƒ0K”4ÆT^ð Á0,,°†¾Ÿ$ÙªÔyq<“&išEœ¦”PUcùò+ :n‘$ Iò4% ÈÒŒeO}ü±8òÿWÎùêW¿úu¯{Ý»Þõ®}èC'Ož<{öì¯ýÚ¯=õ€ïç=ïy·ß~ûUW]†á—¾ô¥[o½õ(Çx&m/áÔ©SÿøÇŸüÅ_üÅÁ`pt½¾¾~ûí·¿ð…/D=ðÀo{ÛÛööö.Þ¹²²ò©O}êÖ[oýÙŸýÙ׿þõ<Ïÿó?ÿó-·ÜRÅ¥û| š¦ýýßÿýwÞù…/|ábðÃþpEïxÇ;ËËËïz×»®¿þúf³éºî}÷Ý÷ž÷¼g<?“ñÞ|óͯ}ík_úÒ—OŸ>}×]w½ùÍoÞÜÜ|&ã½îºën»í¶«¯¾š ˆ­­­»îºësŸûÜS?_’¤¿øÅ–e=ðÀ?Ú¼lÆ+^ñŠÛn»­,Ë£ˆ¢(Žã\üêö÷÷÷¬^ºvfffffffæ'‹Ó%Jd‘À²D …8:D$¾ ºƒn·7‚Pee¾ÑªWëqm]Ø~âÑÇÒ(f!šk4¯®]~ü$Ïñ?öøæÆÆa§Ã üââb'D9QXž5±&AضM1ôÊúɧ( IDATêêê2Ã3£Éð Û&H"Nbž$)@~4™¶eq,ã#Llg8áh§™KÓºªŠLs¬‡À1Y†<EÉxìàÉp8'£ ð1Æ’$‘$Y«Õ8–Ÿ›Ë’Ôs¼A¯_dy§®ãøž0xàëßàÞ†e†%¬†(‡‡]†¦®»îÚÕÕ•¢È:½Nzq:®çi–§qGý( q^¬¯­_;ž¥é¸?hïî_ØÙ:}å•4Aâ,÷lwÌL0.ƶM±ìåK+8-¶6/äY.‰IÀó›çz‡9Λµ:åæùó¢(9ÍÑxaaé²ãÇ]Ûí¶¿•&õF-ôüZ­qbý˜,+‡Ýî·¿÷Ð?üÃ?DYrÅ•WÊ’,K2„жmÁd2õ<¿Ä˜g0. ‘D‰ã0õ‡îÔ <Ÿ@Ó´z½aF&N/M3–c†ñý`óܦ9 'K".±W–€éxB¨¨*!Ã0BŽc!$³"ÏócìyM1£n9.MqõºLÑTG@œÀë:U– åx<>Úw†bYçE‰ñÒòÒÚê 1MÓÿöíïÞ÷_itª•z£1_Ñj<'-Ì-iªF@hš&.“,KªFE-XIâã ü×'¿¹¹qá°Ó§ ™$Eg¯=êuÝH³Œb¨>ÑÍ“¨ZS 2O³ /âÀ·ã(,²2ð°3œN&žçC$–“–%¡*rÍFèÖÒ¼›Ó8Œ¢ ‚ÑuýäÉcË‹ÍV³nÙöÙͳ››Û©Õk±¤޳¼²ò?žõl’Y–fib›fFætâ:ÖÐü¯œsqqñ†nøÄ'>ñÑ~4ŽãÛo¿ýž{î¹æškŽj/¿üò¯~õ«=ôÐßøÆz½~ûí·ŸEQƒ~Ÿ€„m[ÆÃѰµ°°¼´löG¢$Õ›-†aÚ‡¦c†iŠ\èûÖÔÌ’Ô+\AiŠA$*ÒŒ@äù¢(lÛNÒ´V©hZ¥R©6›ÍBú‰Ç§ãñüò’aTž…ÈÓ,£4-sêynœÄ’%. U Ë0eŽÇãQ'$Ar, ²,JQ mÇÂäYv·Û›Œ'”8Ç š¬Õk ‘÷Úžëa\"š.²BW+F­ °lËó}!A’£É¤’ãšapYJ"­éj½Õ¨×벬8®óØcM§“8Ž0Æ8Ï¢4úç67ãÀs¬é¹s›»Û»q’ŸºüòVsA•+â^‚b8Š€e’Æy!„D‘ŸLÃv{<˜ìm ûã4Ã,/Q]–$Ç‹š"¹ž—å©cNó4ˆ#‡áEІyŽM˦®“€¢$Úà«4„¨E’04¤)ÀÒ¡!.˲&£QøB,/jªV©+ËKÕš.ŠœiNövô,rËœx®Ó>8Ø_Ø][[EQSUŽ¡Çƒ~¿ÛµL3 ]IúßÏ­E½óï¼ÿþû Ã|ìckµZ½^ðÛ¿ýÛyž¿ô¥/õ<àºîg>ó™ë¯¿þâbÚ%ÚþÀœóÓŸþôÑõË^ö²ç<ç9¯{Ýë&“ÉQä¶ÛnKÓôE/z‘뺀x`ÿµ¯}íSÓT€a×^{íQböÁ~ð(øû| ÷ÜsÏwÞY©T¦Ó)ছnÂö³Ÿ=ªý¾pï½÷^¼y:ž9sæôéÓO>ùä9'^z¼W]u•®ëï~÷»zè!À—¾ô¥ÿŒyù oxÃ×¾öµv»}1ræÌ™[n¹åž{îFš¦íîî¾ð…/ô}ÿ™ÔÎÌÌÌÌÌÌÌüd)ºÆñIBs:y‰ d„o…qD~<Mâ8%I‘\ä]ghz:™tÚ‡qµê͵¥åg]yO³ëîïí%Qì8Ã2‚(ø¡ØëૺNóÌÔ1Ãa­¹É¡ öüÀw\›å‰“(šæVç 2+Åi,Š’Î‰ 'øaàúNižöºNèIŠŒhJÖ”ˆÌó<÷|/Â)… ‰ÕšQ¯U5UeY&ð}–¦‚ ¸¤"!YÑ+8/*ªÞj¶¬©ÕítA€Æq\d¹çùq?d?DÓ´V©PEQ¢ÑÞî$‰Å¥ÅZÍè÷ûƒ~/ŒCE52¢8!ß-a§ÝöûBÇ××µªÁðܹíóƒñP¯T(ŠŠãpí§Ž!–ö“XP¤+[s^àíìíN¬ / B!åvž§ÙÒ‚eÛ Å†!ðbž ,UUóý`<8žÇR4»ÈÒ4íûþt2‰£HäxUVJŒ=×)†'È"IûýîöööÔœ2"/‚$Š9JŠN#Êw}?ñ³,YQ…çúýnBDQ $`G½^ï ÝfhŠg(†¡ Ýh44͘S³(Š”žëâÐ »¼¼|òòS­í­íÏ÷) ù¾ Í0¢hÄ‘ZE_][[X^Ðt]ÕTYQÛ‡¾çUŠm[ƒA<³4GÑc>v°»ï9ÎAû€"Éfsn®5W¯5Xš/1ÁP,Ër"/¢Œ“$/RH‚€¶å\8nÔNŒ³"‹S’ µ"Ë*/Jœ ðòßr,ÇŠ<’U‰—X„x²d0‘$©«êB³©IN¢A§cF¾çZ®Æ!ÍÐS˳<+0¤hVdzuíø¤`¯!'0kë+Q’P4ô='ËsËš¾›$a…õjb8è·¢0(!n6›OßÏyq ß… Ífó(o|îsŸûÀ%o€/~ñ‹ƒ?°-€ †aŽ®1ÆW)Ÿêرc÷ÜsÏŸÿùŸß}÷݃/yÉK¾ùÍo¶Z­V«u988¸ú꫟ÖöŸøÄ÷æ3éóäoÿöoïºë®o¼ñè¹ßW½êU_þò—/fÂeYʲüò—¿|iiI’¤jµ ¨×ë?~Îyéñ¶ÛmŒñïþîïþñÿñ÷¾÷½$I¾ÿ6664M{ê@?”ç=ïy'Ož¼í¶Ûž\\\|ûÛß>Ïœ9£ëúk^óš_ÿõ_ë[ßzq•ûµ33333333?Y,Cã"7ÇÇ0 ó"ýÔ±|ß\Û üPE–EAÌÒT•ßõv¶¶¦£q³V›«7O;Þ¬Öâ tMËvœÈó)šæEžy/ðÂ$©ÞjP$Jó Ñdb×w©ñPL$†eŠ"GA’¤(š$I\°$TAjèµÑdLÐÐtY1,½043Ê’©5µ=Çô]I‘R¢p#?/rÏp/Ö+5Y–8ž‡$,A‰ I’$Éç¸À ʲ,Ë’¦iY’+èÖN?îïû–í„a”¦éh2β —¥ïûÛÛ[,Çx¾_1´ØÙÚ §„YŽyQ¢h*+ˬÌJX‘M24¥iB¤Q«Ì»ÍÑdœdEÑ¢Ä "‡(xxagg‡B0Ï’(—T©RÕÿ·œ3I’8Ž®’Š¢ŽŠº®?õHÛ¶³,«T*Ϥ-à9ÏyÎw¾ó£ëõõõ§Í¢(ž9sæÑG}ûÛß~1H’¤a/ùË_ö²—=õæ£祈ö>Íìó%ŒÇã¯|å+7ß|óÇ?þñÅÅÅç>÷¹¯~õ«Ÿ:œ/ùË–e}ç;ßq]Wŧ÷GóÇ»··÷º×½îþà¾ýíogYöo|ã-oy˹sçžz3Æø™ìYý¼ñotçÌ™3O Þu×]Õjõĉaî»ï¾/}éKßøÆ7>ÿùÏÿÀÚ™™™™™™™™Ÿ,¸ÀE‰5QE±ÈKÛrâ ŠÃØ6íÃv¹ªJEA‚%©Èóý½½Ý­¡c'O5«õzµêXvž¤4ESÃbhYQôj…8ß Ò,%baia~ya<w»Ý’(y§&M“’(eY£È'ü„UKPÒ M@’„¥È‰JE“5ÕöÁxÔîö]Óu0Î]Ç ã(Ë2Žc ÝPj²¤ÈM%NÒ4ϳ<Ͳ4-Š`\B‚ `–e,ͤY%1")½¢óóóqØ–cšV† áât:õÃв¬0 ‹"gX†å˜Ãöa»}åË2sók$MmíHeÉ3,‰‰ÎááA\0$2*†a—:µrâØh:Ù>Øí¶ëð"×”íöë8 /U5QW1hžeb.ÎÒ"*+ÕÊÚ±õùùyÓ²mg2Äi’gEknÁ÷C JYQË#Šzø‘GÚMÇ dY¶Á×!C•EaN¦é„–#0Üd<õ½@mTyNÈÓ<ËrU’¢8†žíp¬P«Öó8c‘(ÏqžÇ® º( I–9ž3*º5™ DŠ¢ !ŠâäØúq­bDQdZfE4Ã$i:™LŽž¾¾öÚkëz”$ßøú7ÏÝšN¬$Nh†Š£(ϲ¢È‹"÷?N"Û²žxàB‘eçâ0òl[%Iй2×W×– #Ë“$ iŠTT^Å"/òßsÏ=wß}w³Ù¼ù曃 xêyBú§úøãßpà G'½ð…/¼é¦›žÖü?ZåÃ?õ¥ÇýPã½ûî»ï¾ûîÕÕÕ—¼ä%¿ÿû¿ÿÙÏ~öŠ+®ø¿5#˲üÊW¾ò3ŸùÌÅŸŽ<ÿùÏÿÚ×¾v”R¾ò•¯”eyýõ×e•—®™™™™™™™ùÉ"0Á1,DZµzÍ÷ýÞ¨7™žÙ–ßïÃ(ÄyÎ0”ª(Ç%q|ncsÐ뫲²ÐjµMœå?ôPEÕ5Eq\gcs )jVä—‚(¸'é`pÍ5×<÷§šå¸’ |Ï# ,pž„¡Ïõâ$®ªº_RÛþ.Ï ’¬Ð,%%A!@C§YÂrÌÒòR3OÃ0rdzÏq¼²L¼#Ù2/eYd†BˆF$ÎsQdQ¤*²‹3lϱ– ðÃ`<lwö‡Ž ¾5o’˜¤…Æ©‡M×sv‚ÊÑO=»aT^+ŠB5´jµ¾vüØ#<ºßn›ŽU<2Çq5Z:(Õ£Cº,ß™z&I?ãœó‰'ž¸îºë „cÀsŸûÜ£à3lîºî7¾ñÿ¨ö]ïz×Ë^ö²ç?ÿùßôëw¾ó½èEG'ÿ°óËÙç{ï½7Š¢›nºéU¯zÕ™3g.æT€õõõO}êSG çQÎùýÍÆR­VŸ6¨ÉdBÓ´ªªG«‘W^yå0ÞÝÝÝ|ä#’$Ý~ûí$I^ì @Ó´o¼q<?uÇé3tË-·ð<ÿ©O}êûÿ|Fãb±V«qñõ›—®™™™™™™™ùÉ¢!UÆÅh:uú“édjÚ¡Gqæúag²$­,/ƒ²öûÛç/ U?yâK3±nœÝ}Ÿ¡è½í]s2MâˆçøÅ…Å8IJPöºíÞa „ÐUW]õ¬k¯åxþððpgg'I“4Ïü0(q‰‹‚eYžåI’ð=ïìÆ†ÄŠ+óËïnÖ›­Z½FSÀ Τ?™L}ß…à8®"ª‹õ9ŠD¾ïÇ#˲Â8‡NWUQtU­VtI³¢eiZf–fE¥I$H‚€y‘GQÄ‘k;iž14“f)IRxA –¸cÏóEêözíÃÁ gYÖt<5§–jè.Zssj£¾Ð¼æêkpR\Ø<çXÎÞþ¾¤«ÏÖU7 ´ªÑŠ|^à.»ü²$NBãѤÝïPÅQ”à¬èÊÒêòÂâbñÊÊj¯7p\?ŠSša’´€ˆj4[ ªªYF"0-wjåYšãÌ÷=è1Q{¾Op¡Þ¼üØÉ¥Å¥²$rPVšM‚¦LsÇéñ'V–VöwöùÞc®ëCæ¸ÔD¹R©fYÅQœÄ¦5É1.!Á‰B­ÙX¾î:–aŽÅ¸ |„jŒ$P‚°»·oš&‰®ëFC×õ(Š6ž|òÁû®eMIXªª( l–ç¸,¶Ïo¦IÐh6u]× }uyykûüÖÖV¿sˆ³ÔPÕ¼È\’ôƒØ6MD ¢(u½Ä‚ˆpGigA‘çˆEÓÉhw{w{oФiÊ0 I¢Z­QÑ´…ù…zÍP4Ùu­ä¢Ä±<$‘í¹ª®ãÑ4 }Ïs œy^`˜eQšá0O‚ÒW Q’Dš&YV(Ëbâ8ýñxdÛ’!H’$I"D”*ˆ«’47u¶vö;ý<÷×W–OŸº¼Õœ«ðœ®jÅ(Âöýáx ÐUµV­6[MAä}Ï{òɳíÎ(/‹gšs~ò“Ÿ¼÷Þ{ï¸ãŽ|àµZíÏþìÏz½Þ?þã?þø³ÀóŸÿü?üÃ?ü“?ù“$INŸ>}<þüQÒòþ÷¿ÿþûïÿØÇ>öþ÷¿8?~ü¦›núÖ·¾uß}÷ýg÷9‚Ïþóo}ë[—––~çw~çiÙì+_ùÊ¿ú«¿j·Û?ÿó?ÿ¿ñßßü›ßüf’$ôGôÉO~2Ïó‡zèh ÷ᇼç=ïùÀ>púôéßüÍß|j«K÷úë¯Þóž÷w÷w{{{‹‹‹7Þxã#<òÔ„077÷—ù—?üðs¾á oØØØxðÁŸ?sæÌÛßþö·¼å-ý×­ªê?øÁ²,/>{éÚ™™™™™™™™Ÿ¬éÄLã$ƒÉt’f)IR"E’ëuI–d ‘æÄql;Š¢¹Ö\³^Ï“l2ûŽx^–¤}ϳ¦¦(fK×5]ד8  ËEqtpÉîÎN’¦ãñxjNišæ8„eY’$IšŸ›;qü²ý½½ÉdjEÞΣüq~¾U­ÖDA$rDz,QàiDÑ¥ˆ²&ÉÀ¨/ÖZq{Qxnoo8AGQøiišJ\EÇi’" ¹¶[–%")†eqQú~P–%. ? @YfYFQ”,kY–AHêš®ªj£5טoÖç{ÝnÐ~´÷¼(<88ìwû§/;Õ¨Ö–——)„ÚíNEûC‚c¢4 ³$L"š¡XŽñà Q7â0ôûïS4’‰ç…Z­f†,ËQ$‰Hˆ*)Šdä{i;œ(eÉÒhqi1´œvK\`PZžkOÍAãµÚÉõ§ÖO€ÄyI.ˆ,JI’zö³®=uêr|/€ˆBE1Ks $êõúÚÚ:ÇsãÉxgg«À¹ãZSsJÑT¥R‰«5šaByžgyÊ2pkwçüæ¹<Ï×SUuqq!4N;‡®ëŽFƒªQ©(†$JQY–uú]Ƕ&ã!" Qà(=Û<ÜÛ›ŽF²$®,.È’ÌДc;ç¶¶¶{½^‡€Òy¢LA2O“0ðÝ Ò8Û¾°Ó9ìfq†*)  ©ò|«eT ^rœ¸ )ÒuÛ›0­iŠQ5\×íõ;£ñ À…¢)y³¼Äe%?r2Hsó]ßvyŽÆyæØSD’«ÇŽ¥iR‚’fQç[­ù ŠŒF |ì^8ØOŽå™¦³´¸Ø¨7“jµ*É Ãr¸$pIÐ4E@$ÊòâÒ²¢Èn§Í"áŸiÎù…/|áÝï~÷ïýÞïí·ÜÝÝ}Å+^ñ|Jö‡uúôiá;ßùÎw¾óƒ+++G[4¿öµ¯Ý|óÍwÞyçßøÆ£ª'Ÿ|òfS?~Ÿï¹çž[n¹e4}õ«_}jü-oy˽÷Þ{ôFÍÃÃÃ[o½õ“ŸüäÓÚv:×¼æ5ï{ßû~åW~… ˆjµztÑc=öño{ÛÛÞö¶·u»Ý;î¸ãCúÐÅV—/ÆøÍo~óûÞ÷¾£â£>zË-·üßšŽ¯¹æšg=ëYG/ }š÷¾÷½ªªÞyçGgƒ_þå_¾¸WöÒµ33333333?Y“‰5Œ=Û‰“HQAJ “àº,ò¼,( Õêõf£Ùj4â Ü;ÜŽÆ. <Ç%I’a™j½¾¼º"‰’ã8SÇNŠ|®Ö”q<y®··»7 Œ“4-Ë’eY’‚$‰TY1*†"ËãF­!ËÊÚÊZ8è ú[Û[¶í\ØÛn÷»šª©ªJ”¥úË!š%IÓtMÑTQ"JÀ":ˆ"‚¤êõ+ ¾ë¤IBB" Ã<Ï)DºŽ 0&I’¢h¡(D—IÆEF!„KàE>À€ ˆ”…kHÊ´í8ImÇé‡$„4…t­¢©ÚÉËN¥Iºy~³?ö†ýs›çGÝáúÊj½Z§V«T²éÄrn2T ¥ DDR¤™“y¾ÇÐHDI’-ËIډ뻂ÀQ4¢hƸ`&KrPŠ¢qI@‚À˜p]<ž2,‡)ÖŒµÕU"ÍÛŠÃ apæ» !q‡£ ú¶·¿HqlšæÀšª_yåUz3K3ŒÁÂâbž•–é’I²bTë K •šÖ šŠ*5šõƒöþ`8ŽF?ùDÅ­V³Ñh@‚O§Óét{wg:Ò4½º¾¦ª Ïó£Ñ¨Óé8®å9„°Ùl.Ìͯ¯¬ÕŒ*Ͳi^ìî\غ`ZVú{»†Ãnøãñ„e˜fͨUk¢ *’UCß &Sw8u;À-›ð IDATýƒ8w&¦.É Ë!AE“Éøð xI ŽãI‚ !Ðea¡Ùj50.;½¶ãº’$ð< \àÔ‹‚‰9e¶×ï´à TUYÒô0LMÛ ‚(+²"/=³$²pÞ˜ J\äy–4µzÍÐ*5š¡8ž“d™ø–eçæš++‹ýÃ^–e¶ãnžÛîvÇõF}mdU«µ©i9nH3<Ë‘$ ³¼ ¢tb:¶ëïí¸~$JdzÄt:}†Çê$I:qâDE›››G¬þ×€ž8q‚çùÃÃÃÑhôCµýOê3BèØ±cE={öi+ÏÄÜÜ\­V;{öìÿq'ê¥Ç»´´T«Õ†ÃáS_gò_@’¤ÕÕÕ ö÷÷¿ÿ\ÜK×ÎÌÌÌÌÌüÿÓÆÆÆ3¹­^¯î¸ãŽ_ú¥_¢iš¦i„EQ!„I’³oòGvÇwd‹j·Ûq-›ãESxNÀ9NÒ—@eY’yAˆÂ0Š" Q<Ëž?»y~s3BQã$NšÍ¦ zE?:ÈÔ4ÍÑx¬©ê±ÕU]V=×ÝÛÛ=8<( @³,Ã0E‘•e) ‚Q1tµ"|‘«Ë˵Zaé(‰LÇšL'»ûû›¶m˲Òj69–³L“¥™V£¹ØšoÖŠ$ ‡óܱ¬ÉÔt¯  A£4ŠŠôà…í D $ŒŠV«Ö(ŠÇ;Û;q)Š,K2"ǰzcuu ”ðñ'žìtûiš§y>[,Çk•ÊÚúÚñãkk+ óÚîÙsßú篺½€‚( š¤96Mó4J¨’äcNì Œ«­§ÊƒjµÊËþŸÍ5êiœ¤I† `N¬/Üû%’@««kÇ×7Z5AáH’t,×uíþ ×éöûDZ:Öl6iвl»}pÐë÷EI¼òÊ+.;y™¦kyš~ñ‹_ÜØØ ªÞ¨ëº>77·07¿´¸¨ŠIQ9$ÌAÿÉ'žÜ<·yaëÂx:N’¤Ä¥Q©´ææêUƒc9ϱ¸(:½Án§ßîFÓ)„X¯(‚̉"G!2Š¢n·7ì µ†¡UÊ¢}¡È¹V½ZÑysý ÓíÇIš$1$^àxžÃ8ïõºQAB$M×µªÙ»]ÇñJLP´ (j–giãCà²eQ¯hFµ¢jŠ¬Êš¦æy–Ä1E¡4K÷öÿõ›ÿ‚³Išæ,Ë(ŠJQt–yžCRyÇ’$ˆ’˜e™ešižñDz ú¡þi=Ï;z3ä1ŒñÑ¢âà?©ÏyžÿÈ]t»Ýn·û£÷àààààà¿þ¯àyÞc=ö£ÕÎÌÌÌÌÌÌÌü¤˜ ^ÒAà0.\ßeY%A VVV „;»»¶eA-v¶¶Ì锡è¬IëªÆóüüü<Í2aFq,ˆbƒ¦V——kª^QTõ²“ª,w»Ý©eÒl"É@QEšžŽ'“á‘H’$Ñ‘r÷ù?ÍðL’&cŠDÇG‘éùÊS? -Ç~ô‰ÇÛÃ.¢Éýƒý,ÏMVeÙ6ÍaP"N’4‹eYZ_[=~ì˜5µ’0õGžíÇIšçE³µ J $É4ËÓ$ƒdf: eY^][õ{¶m­¯¯þÜÏý\s~þü…íý=gb;c;K²ƒƒÃñxœ„)Îâ /rˆ¦ „²*ÿϾÀs¼~o°µ½e[MS'O^V­<ÏsK3ôü|J’¤ëºæÔ †®çɲüÂüÏ_ø…_U… Æ8ðƒƒv‡„c'ŽWtg9H@š¢H|sjNÇ®ë†aØí÷ÏŸ?ßï÷I‚X\˜#¢}p8ö³$QdY•eI”Ó<¨R5æZ‹ë‹­ÅÚ£>º¿¿ïËòÅBÍÏ­²4ëXÔÂ\S––§“n»4\ß.!š¯Wë…µcë‹ÿú¯ßÝ:¿“g9EQ†Ñ¨TtUÑIQ5¹RÑj ½>§H*©èôù³û[ö*ŠŠhŠ`YZe]Íâ2ó×§S»(Ò ç™ÅùæââABJQ”åõ9†aÎmnâ¢X_[7*‰0ò²¼ìÊS“‰¹×Þç8öôéÓõzµ×ë'cœ¤“áhØë§i Jœe).KHBФ]Ï%9 ;‡¦izƒÎa§j²,--Ο¼l½ßï¶;œ(†¡iz–'œ¼ü4I±[¶Fãqšdš® ,Ÿ¦)C-ËIš†ó¬¢Ôh„@‰)©š\¤Yk~^”äÍöáaƼ ¥YÅñdj@p‘Y¦A@žåjÕzG®çἨTuAäƒÁêú MSý~ß±mv}™aXD“$¢(°L%BȲ̢(hŽMŠÜñÝ g;û;’"y¾K”˜£ÐÇ´eIÂ%£¸°ß~ÝþæÎöž"ÊIœ3ˆ[ã,-pQ¦Qâco<GqÊñRœ¦EV¤qâ¹~µZÕYäÃ=ý@VuMÑ šÍ¨O÷²8G4 HHQˆDˆ(ËîAû¾¸o®Q¯Uëºf0,gçeÚ»»û>òH…U£Rk.Í-µ4]áB‚€¹k®¹*Ï‹¯ýë,ÇH’À0Œë:€D‰‹,ív»?üÐ÷¾÷MSµª‘¥±m™ˆ$Û¼p~3¢,}ß?ñ„ã8só­V³žg™eÛs­†mYIù(‹¼È žç2œ Fý°L%]•$áèýŽeI”%!)KêÂÂâdd&qD‘å:%‹²È±*MNü(r}‡˜²ë«ÇŒzaYDÑõz«^ošÓéhd:®Wàùj£F‘ôÁî¤ ݸìøÉÐÊÏ?Ô`ž€Džæ‘¼Pd(0E"‘gI³4±& ײ!A€²ä‰aM«Öj Ï š›Ÿ[– ‚ ¡ ð®ëA3¬n蕊!´,«ÙlÎÏÏÏrΙ™™™™™™™™ÿÖ9g·ŸØîpÿ IbŠ" \ÒH’`ea‰EŒ&)ˆ¢m×áYþòS—Wë5†cÏÅA³Ì4tÃ"T `ÿðÀv,€K„H€‹©3éMz<Ãù~ ð¢À‹%.‹4_ž[ΓŒ§y¨%(˲œZÓ ò8hr`šÝ^”`™ýNwhZˆbø‰È²l·;tÝHxžá-Ë ƒçE®¤9]ÂR4+ð Š,›˜öx4NãØ±¤(²Ë¢.KDz§Ói–åf„^­/¬’(U4MWUÛ´Ë¢)Š¡è0ªuõ\w-I’»»;“ñD”¥Ša4ëuŒ Dz¦“©95]Ûf´'Ç"J‰eIòˆ–Y^åù8Ž<Óe‘Eñ4LŽgy^VÔ¥…U]¯p4xÁtìzNÌP.bŠ‚€qÇa$˪íú4Ã2ˆæhFWTQdˆ Q¥i’æ®çÇq*Whž+pQ<ñÄ“ýC½^a"2Žc³?xгY†=yêò+N_]o´Esœ¸°¸¨:ÏQŠ* /IÇ1$EJŒÓ$†yš,ÌÍUT%‰cÏõ{úè¿ÿÏ2ãñ°sx8O(ˆa‘F¾‹$©„Äd4ö{Q’L§¦95]× Ÿ€haaQUäÐ|ÏEˆ¬Õë8KÓ,ó}7Iâ¬(²R Ó4Âxìûxï0 =7Ìò"f3E,›ììfižä‘éøÃI»¢Ê]ªº, ¼\+¨$ašßüö¿L†ã¼Ä§NŸRF I’a ¾ßÞïšSka¡µº¾¤¶êžkïmöö·Z¥®JI!DZË«š¬*R ²8Ó,#Š,X6‰¢Ø‰q\QâÒg3H…QRÆqZ«5Ö×yî9®e™$…XD!`œ ²Èñ<„¥ãÚ¡çaÄY<Ë9gffffffffþ;£ §iã¢ÄEåYV’„¤IÍf“¢À2NAŠÃÀ‹‚@d’Ežï Íq0' ‹ózÝššíýýA¯—Fñ|£¥ˆRæ¾ï9ŽEPÉTвUeUvdVÏTÅ¿3ó_VŽ0H@ž)HÙ–[ßÞ‰ã„ç à€Àæg@9AFQ䨖eŽÌ¡ \äùBQ“ €œ¡iŽe³$ Œ8Ž8YU´¢®µ‚Z* Šì:¶kÙYš$Il›'R“4årÕ©©©r¥Ì1¬ïzjAQ êöæfŽRˆ×YÎ@NÒA‘~Ú®›¡,ˆ"ÇRR"&M³ C3ª¤ÎÏ-NMLCœê´z“X†Ã0 E…B’I²,£ëEÏó!NÈ’T,hÇgI¼yæìævÝ# Â4EÖÈb!Ês7ðÝöÙúæÒâ€gŠŠÌ×Êy–š¦ÙÞiá9iYÞÔôÌäÔ¤^V‚ h‚¤p ÏH yÑïo¬ožZ=EÑ|AUf§'ÃÀßÞÞªom~ëÁËQæ»Nš&Ëõ¢Àó,ÏqCdœ¤¶c÷F£ÙÝÜގ㨢ëe]'!®ªªƒaCc0èâ0di:ÏÑÈr3à'yî%Q‚Pšå¶ÄIFÐvì,ÅTU#"I“¾Ñ9EQ”yAb²$N²¬ÞìX¶SP E½@óŒ­v»¾½C”®•5U/H…r©!é:^³ÑÜØXß©ou[½aßì·G–mm×둟W«S'BHà·mËqlÛ [P% IGa˜ÄqÎð†14I2Œ¢íFÓôü²P$IS/ð Oã6fZÃ,M0 tezf*I’¦iÙ,˨j!ƒN¿7Ž9÷>¬(Êîö#<2¾ ccccccccÿÊÕ*Í24ÍDa@Ñ´ã:Q’0¼ÀˆÃÀvÇñ‡–ëz^$9$eI†årAÑ4MU”jµ¡çy¶e3$ɲLÇ£ÑÈvl”g,Çsœ °‚k{¡ ISSSe½* JQ-.ÎïáXα݉j­\* ·²²rüØj}»áXŽa‚(‹º^*ëºnZÃ3§OíìÔjµ¬@YâEBÂ0p—"I„r0œ ² ~h™'H þA–Æ,Ëxžc ú(ËTU›Ÿ;tèÐp4ÃF³éù.N@ÐÖV}sþî½ÿýïÞóž'I’ªª†ý_ÑæÏþóªª>­ðî»ïþ·û·ÝíK.¹ä½ï}ï¾}û\×}ôÑGo»í¶ÑhtîÌ—¼ä%ïz×»æææºÝî½÷ÞûùÏ>Ïóñ_ÂØØØØØØØÿÅjU”DQMÓDam»¶øîú†çû,IÆ#ÛZžãXžk¹®^)MÎL+š*«²¦¨±u›úæ¶52Š.ª Ã{½Î ß§hŠáXãÉð 1—ðÙé™ù¹™^§7??S.—Kå2FàQiz1H¢V»Ýn·À*åJ¡ Z¦ƒcD¯ßÇqÜ÷|’¤ªÕ †áA@Ó4ÍЕj%C¡I’“k§ûƒAF’$…IB‘TàùIc ï÷ú;[uÃX’ò\Ÿe¹œ„ÃHUÅÃ:ƒ~hšaƒ ¯d2I×ôŸþä§¾ëMÖ¦Ÿ³ÿ "K““5š‚žgêEÍõ½V§5²†Ã$IÂòÇq’ÃáheeµÑhjmjŠp, Çñ,Ë‚ 'NœX]]ͺì²K/»äÒrQgHJd¸RQS j„§Ožùîw°¹]ÂH+¨û, *OÒ$Pš& Îí¡Ñ¨×O¯ÞØØ£bQç9` ü( \Ç¢Ã0Š¢(šF92›HÚa§YÆ bA+„QÅ)ážÅyžçÓ(‚À|Çu˺¾¼w/‰ÇŽöB‡M“4c®¤ ¤!¤hб2Q›™F®ç†Q„aX–e¶mÉ’855}ÉÅ¡4;zô©|ÿk§N%i,*‚Ä‹z©<99SÑËšZ,˺¦¾OSpnvºZ)+²äyÞ±ãÇ]/D¡ФI’˜›>pà`ø"Ï&IØï÷Z­¶ãØE½X,j¢(€á{A¯×÷<`8AÀb±( EQ(Ëâ(j59ÈÒ8ÉÒ„¢)H‘¥RiiyÙuÝ~0,Çv}ÏrÓñÇ1çïÞõ×_xç;ßyûí·ÿßÒæ,ËΩæüüü%—\rçwîî^tÑEßÿþ÷Ÿxâ‰;ï¼³X,ÞxãW_}õ•W^™$ àꫯþÆ7¾ñíoûöÛo?tèÐg>ó™R©ô‘|dü—0666666ö?94‡†‡1òä¾ï»¾ëzîp4êvÚ3S3Dš…Ž“eËr •òžŸóC¿?è÷;]¡mŒ\Ó–y1£R{dožY‚H‘•bAO3Ôíö8Rðí lanvÏâBI×|Ï™™ž˜•d9Jâ ŒI|êø±v«¢L’$žªÕZAã8ƈâˆfY†ášnw:ŽíJ’\®”‚ˆ£Ø´­(Œ“,iw[e¬äܶ¬$ŽDQ,©šªi$M"å¤hŠ¡–g}׋£#ñbµ¤ô4Z–Ïnl c»±†¡$òqÛÖ( š$3„6»]Û²I’2m§;0’(•eynnÎ÷¼V{hÛU½ä…‘í{œ$‰²¢µ¹ÅEM×NlÕë››[FÀsÜòeû¯¼üò~ßX]Yô[g7º¾oy"ÇéEÍuì(lǬM–•‚Xª½Àà `{v‚ÐæÖ¦ ²aäÔëõɉÉýû÷»¶³³½L–eI’Îll$IR(¨<Ï/ïYÚ³gOE׋j%éeMÒ¢p!ÇTõ؉ÕS§Nû¡o­>¹°0;1U¡¸Ûk=þÓŸnl¬‡~À2\±Pœ˜˜"\EŠ¢ºÎN³…“pïý(M-Óêõº¶mC’¢$ŒÂ$ÉÖÏ×7Â0†Ô4mr²F„1h‰˜¬ÒÄ!QÒËåZ•€ð;ßù/ŠZ©ÄK 7 {Ã!L²bA`.G@‘eE’ †5f˜r¿|ôØ1ÇqóåP•ÂääÔýû/¸à¹õíÆ©SkžȲ\,”±¯oÖc/æhž¦¨,ã("IÈ0LFŽãDQ¤(Š^ª0 „ãx_WµR.ïÝ»41Y]\œàß¾~âıÑhhÙ–ã:ÕJ…ãy–çÂ0 ‡­V‹„”¢g&& ZQUU–elDzÌÑÎÎŽåzQã.I’f³yüøq"çæ“,ó½`cs˲ÜqÌ9oyË[Îßý§ú§B¡ð½ï}ow÷ ox†a/{ÙËLÓ ‡ÃÏ|æ3]tÑücÀ‡>ô¡õõõ—¼ä%!@E7ß|ó§>õ)ÇqÆvlllllì×2 (Š"Iþÿ‚ b|e~åryw£³YÇ1,ÍR×õ]ÏËAŽ@P¤H3…Ù¥KŸw©È³Ç‚@yÞé´J»íV†I’P$回ÀódÃÔtúv‡¡)­Pdh&ŽPŽ€ÀÊ4ÅšCƒc™<½^×èw]×u{}ã¬(ŠÅR‰„•“«?yüñ$IK岪¨•JŎΞ]?}ú´ïûÕjuÿ¾ýó €þ`pìø‰V«Õî´¦§§gçg‘±µ¹Õjv‚Ð[X˜«–ËA¶[V«IÓtŠ’4ËFæàìÆYçY–Áp‚¦IÛr,ÛÊ" YÅð¥jIÓµ,M“(6,3ôÛ¡4%!t|Ÿ¦X×õQŽa88AMó$ËÚ¾ï¹Érµ¶0¿€2”&ÉìÜüÒòR©\R4uä:9†Cš)UjÕÉùÙ¹ÿç÷®Ø»´xÁTmzeeŵ<”"Š$·66Μ>éy6†£RYߪ¯ãa i ÙÓg7r@AÐëõlÛ˜šœ¾ây—kzÁ³ÝRQ™&À°ÁÀ°{rrB-(§NrÛõœ‰ó˲,–¡ÜsP†š›Yœ# ÌQ¶zr­Ó¬·š[4C CÑжM×¶hHq Cà0 ÂcOUõbÏDQ42 ßófçfKz1MÃ-ËÜÞÞ&p‚¢ÙàIây^§ Ç ‹{0<7†ƒ4I8†%IŠgÙÅ…y­ ò/BAÓúÃÑV}{kg8Ű(IB(GiF‘4IÀN«]¯o ’ éºVÐX† £„m»Ç¯8޳²r To´Ê•ÚÂÂMUâ8îuÛFÐi´‡=cÔúè{ÞóžÍÍÍsgÎÍÍÝ}÷Ý7ÝtÓ‹_üâ7¼á ÇýÇüÇ 7ÜeÙ3·ù¨ªú¯ÿú¯·ß~û×¾öµs…wÝuWï}ï{³³³7ß|óUW]U­VmÛ~ðÁ?øÁöûýgÓß믿þu¯{ÝË^ö²Ý݃ÞqÇo{ÛÛNž<ùlú{É%—ÜrË-‡Æ0ìÌ™3wÜqÇW¾ò•ó?_žð…£ÑèÑGýÍnÐÅbñ•¯|å-·Ürn~¬,Ë–e»t[[[€skV:ôÕ¯~u7à<ðÀïxÇ;®ºêªsórÇÆÆÆÆÆÆžýS˜¢(Š¢ „ç"ÏqÌù[Â1€Pêû^³±)²V«ÉŠZд‰ÉIEU—1,JÓÄè¦mejrÒs½­ÍÍ­Í­Ó§N“$Y*•&''%N€€p=W$YR cø‘,ÉÖÈJ£LŸ,R$ÜiÔ^/ŠÂJ¹œ!TЊ€ÀÙ luºåŠZ Ijh˜žëu{~¿Ï0ÌÄÄDµV«”Ëe]ç8®R.CH"o;Núƒaßq%,Ïh%å²Ë.žžò<Ÿ¦I^`‡Ãáph`’ i…œAn×ë4ÄaàºN–eœ Á(Æ! ¦qÐzŽå„'K’È (Ëò,÷½À÷‚$I†U š(ˆN×4Í8ŠÊIœèvz,ÍGV·×+U*ZYovÚ'N¬tÚ]‚€ÅB±X, úÃÿØy„¡h#F˜ž˜šž“DÁvÌV«áºV†/0;½ ‡4ÃõŠÈpišÄIØëuh†`895U( $%Qv÷ìúÙÕÕÈP¡)†îõzÆÀ¨–+Qöû1EÀ„IâYGQ ªª ˆAR$E’t†aqoŸ\ ƒPàùBA% ˆaI’r€¡¼ÞëöE^ÈE I1E½"ˆ"†a'I2ô£ ƒ¡¬Ýn-//ÍÍÍJ²¼g߾ˮø=; ‚v›á8Q’ƒ( ŒÂÄ÷ƒ4J.Oâ' Â(nŽ,Mã0B$ æûA«Õõ½å™mÚÕjmfr’¤ëºª¨ ”A«Ùœ$É™3gNŸ>ë8ÎÄÔ4F`µÚdµ:ašÃúöÖÙ³§WWO4Û««ÇçŠzqyyÙuÝV§íù¾ïûq’ M$'šÎC†qdÙžeÚ[[[žç± #‰²¸$à8Æ0tÛ;Û›[›››/àB’r|¯PÔp’\X<ïýœÓÓÓW_}õ¾ð…Ï|æ3aÞzë­÷Ýwß…^¸{ôÀßþö·üñ7½éMårùÖ[oÝ·oßóŸÿüݰä™ë>³~¿ÿ…/|áÜîŸýÙŸ]xá…çæyÎÌÌüøÇ?ÞÚÚzç;ß™¦é{ßûÞ‡zhÿþýqïžÀóüóŸÿü}ìcªª~úÓŸŽãøÚk¯%I2˲gnó3F4M¿å-o9s–J¥·¼å-o{ÛÛvw/¸à‚ÅÅÅ»îºkcc£V«}èC:|øðe—]ölú;;;{Í5לÛUå…/|áî;y~eEù÷ÿ÷Ýåy~ñÅE+€‚ÀE(Mâ8F‰¬ÊÅb„mš­úÙ“k¦1ºø¢‹®¸âÊéééF£ilˆCI1€„S$˱Bà;ÕjíÀþσ.K“Žc‘!qÃÒcàïì¸^˜¥¡Ü¶ÝN»†~Pš&´¢@‚ˆ‚ Ýnã8¦5H’…‚:55±±¹¹µ½…/p UMU òÔÌ”¦iE½X,i‹K ëëëgΞIPâG„Ò(ûCëÉãOeYV(Pž ‡†ãºz©šãÊ1Y’8– ³8L'ô‡CchšÃa9–¦$H™åŠÅ/ðQœGV¥(Mí0t{<Çó »³ÓüÙ“O‘ -ÊÂA„Žã„Ò0Ö×ëƒ^†¤¦¨4E34+Ë¢( ÅbC4gæ¦hšì ÏwF&‰AQe™8‰s„ªÕÚÔÔ$ÈAž¡,ˆCcuõd«Ýäei~ÏB·ßÝØÜÌÒTQåÁ z~èºNaˆÒ8ô8ŠG†Å)iHÒyžÅq”çÈ÷Ý % ¶ëdy®KJA£)Æ ÃúÎŽã9Å¢V©VxŽ‚ (),ËÆ|R(êÛõVÄ9Àr ÓT­¨—5­T©éÓñä©“«GŸzÊ2-Û¶Z­öúææE=7AH/WH†Á H³/ˆI$‘dñ(p¼,Šã8ò\§\©Ô&&0·l»?ècÇž¥(ų0ˆŒläy¡ªÊðœÀq¢*ˆÓ3²,™æhíÔɵµ“­fó‰Ç¯omb8áy† ‹‹Ë{ÃE1•jM%Û)²Žã˜ýAÏÝ^¿·°¸Àq,ÀvÏ÷†Í1,ŠSV$Yá8ä&ÏËÝN§Ûî:¶-KÇ2¢ÈK’P*—h–™œžòÃhýìzÇ,Çã0²}odÛ4Å3”ðÌ­…¾ï}ï{衇4Mö³Ÿ­Õj­V ðîw¿;MÓ—½ìe»&mÛ¾çž{®ºêªsƒiÏP÷WÆœ_úÒ—v·_þò—_vÙe¯ýëƒÁnÉ-·ÜÇñ5×\cÛ6àÑGÝÚÚzÝë^w~˜ºû£àÅ_¼˜}êSŸÚ-ü•m~÷Ýwßí·ß®iša€ë®»!ôå/y÷è×¾öµûï¿ÿÜɆa9räàÁƒ'Nœø-ï‰ÏÜß .¸ P(|àxüñÇ<ðÀÆ}ùo|ãÃ?\¯×Ï•9rä†n¸ï¾ûz½žªª/xÁ \×Ý=zúôé‹.ºèÜÉW^y%àç3ý·`UEQ!Õ§—æÊ5AÂ(¦d6g ;rGæ°Ýl $¦ ‰çE#Ó8{êÔ™S§·×7mÓÒÕâþ¥å¥¹HR¡D~$ ’$J¶åP&hŠ‚ŒVS————–hŸ˜('Qh} AôúF½ÞŽLQÖhÆQâùžeŽÒ4*•ô!ßó Ìð\R¤ï»ž_D1Œ¢ÑpØï÷lÛæ'x08$Æ ‰#–çx/UJaFÛv\ÏŒH'ð:ÝN£ÓfºÊ3Û±=Ï÷â4N$饥=µâM’¼À+…/ žãæ"0‚¡š¤9–«VªÕr•çÏõh–—• ß}Œ@‘çG#s»¾Ýh5)†©LÖDALè8ðü4Îp€ƒ±4—'iè‡$eQTd™ãXÛ¡p©jáâK.”dñø‰•“§Îzž“¤ €< ƒ4Ë$IbYÎu]š¢^åø‰••Žc91÷¿Ñl ‡Æôô4Ë2­f3O2Ã0|lj¯ßkgIÒéôPŽëz¹PÐG¦i ‡8ÄEEŠ"?Ibâ~âä¡X*%qæùí8ZI›šš!K3YQK¥²  Í0,§èÌ™Mßó !s€Y–MQôÔôÄÒÒާišl6A°zn…Þ׿þõs…¿².Ã0š¦w·BçF)Ï·gÏžûî»ïïþîïî½÷Þs…/}éK¿ûÝïÖjµZ­¶[²½½}øðá§Õý¾ðóŸùlÚüËüó?ÿówÜqíµ×îÎû}õ«_ýÍo~ó\$œç¹$I¯xÅ+fffDQÔuP.—û˜ó™û[¯×Bù—ù×ý×?ûÙÏvGŸfuuUUÕóýZ®¸âŠ}ûöÝrË-çNOOßxãÝn÷È‘#…Bᵯ}íŸÿùŸ¿ë]ïÚ1¾ë®»¾ô¥/}ò“ŸüÊW¾rðàÁ·¾õ­Aà8>~ÂýO •µB¥p‘xqmrB’ä0‰{½^œ$½Qo0Äq¼µ¾NâxQQ)fqÒowÖOé6Û Eª¤Tõòp`üä‡?v\w{gÇY3ósN`N’$ˆÃ}{÷<¸OU KE¤iX²uYvÍíFÓ}IQæ ã0Œ(ŠÒuM/‡†áiš²,›e™ë¸iš6Z­Skk½~¿:5¡ëáÐ%iEáêêªÀq8Ä–%I„!À°(ŽÚN³ÝÌ1`:vœ¦ ÇzQ¦iű€ÀQ†IššYÚ»LBÈ °½QdÛ¶ïú Ëž‡äy~vzN¤~¯×7†’$)²ªÈJ'•bqvb²XÔTEÞÜÜüþ~pôèQŠc¦gfE1-+’鉩ûöá–„QÆYš`Ñ4-Ê" ?rˆ“4Y›¬MOO1³µ³CÑT’†ŽkGQhÛ†áÇLÔÊ•J G9Bè䉕Ç~úX»Ý:pàÃ2¦iZ–EÓ´®ëq#„Y"r`Ù–92êÛåÍf "Œc?އÆ0ˆBµ è•Bý^7ŠÃ4K1§#7t£$*•Ksó³Ç…A˜›Ÿ!Í2A” Az~(I2Ërªª‚3 ãìÙ3½^¿\ÑB¢$ÌÏÏîÝ»×´,’¡UM‹£¨Óïµú=žãŠz™åy†eMËòÁž@éz©T*§ÚÜÜòýðÂç^\­UEa†$Måe‘c9†å˜ÓgÎ4[­F£9ü0¤(FH’9DQ„$‰„(IŠ¢dv£~:ŠcŽã†ÉsdÛ¶a$ýÁÀóÜn¯‡8„°R©Žl3E9Žã¦òs]“&Øÿ#挢( ÃÝíÝ …$ÉÝÝB¡°›0f—išI’hšölê.»ì²ýèG»Ûëëë‹‹‹O»‚päÈ‘§žzêÆoØuå•W>üðû'à[ßúVžçW]uÕnÌ™çù-·ÜrË-·°,Áòò2MÓçR"ý÷úúW¸®k™VäzçY" $B”¤=ós•R…ÂÉ­íÆÖv¿Ý³ŒÑ¨ß'qB‘UM)Ð4í8Ž*Éýþ€á¸¹™µ žÝØ ƒ`xŠçª¢ÕjU Ãûý¾ãAŽ%I §hhZÎÃ>zêÔ)ŽªµÉ8I¿õÐC«'O×j“SS““•Zei–e$IîÛ»×ívû?øišŽë*’Är\”¦«'Nì4›åj¹61Á²ʳ^§›¦i„4Ãð¢60CÓÆbrvŽ’&yžÓˆbØj­Ês\–å¾R4Ç0,B(|Ûu NØŽFSd†²(ðÓ$ußtÃIH…iI˜ b0Œ¢(@–A ;¹z"ÏÑ ßËÈ‹M×´0I&qœ' 3‚Âq’€4s`ÃñV£Ñëõ!EUke¹ u{ý¡iKŠÊ‹Êhh©(2†‘ÃQ–¡·²z¢¹S÷=Ÿ¢ÉRI'HBÓ4‚¦‚$fYVQžç±õë~ô£k®¹ð_™øçwÞæûï¿?‚ë®»îÕ¯~õ‘#GÎE\€ÅÅÅ»ï¾{7àÜ9¾ún_t]Z§vs +в;xèСߠ¿Ÿþô§EQ¼õÖ[ ‚8×€ªª×^{m¿ß?Åé³tà 7pw÷Ýwÿü×W©TÎí–J% ÃÎÏtþ¯ o~ó›}ßÿÎw¾3~Âý6Bëëë½^ï矹cçÐ4]«ÕæççŸa]ÏÉ'ŸJ³4Ó! à4/°4ä8Ne6'†Íî 7ØX=Õi43„q,OAZ+Êš.òá~¸¾Da©RVdÉ÷½Á W©TóDòk{scó,ÇQårQVD‚,‹=Ï­ï4 ÅR©\É1|míL·ß›žÙ¿ÿ`©¤K²ˆGSÃßÇqœa˜4M×ÖNgY61995=ÍpŒaÊJAÑT€Ër<Ïñü¡Ô²ÑhFQŽ4KËåª^.s<‡"èx6C³ Ãr‚˜¦Y§…‚ŠãÐqÜ4Íò’(+ „xšeaz¾—#Dа2Y•D äp0 ý J#È$ð # ØÐö»ÝápIX®”yž‰’p}ól»Ù(ï4[S•É‘1BY*Jœ p8A’T£Ù¨7vâ4 ¢èÔ™3žïz~H’tùÆpE±V­“$ÍsB̲FžeA$–,ÅqWe`yžçyÁ4­4Nì? ª' ÊAd$FVÕ^wàyI1ÓS3SS“ÏÒ Í°,BYš¦!˶sF$D‘19Ö°¬Ë¥’,Ë‚ ¤if𿯿ú™Óg|?Ð š$I C—J:Ïñå’Î24ŽcÔG92ŒáÑ£ÇÆPR”F“¢™ÚÄäÔÔ4†›[õþÀàajjZ•å$‰ê×±yV0ŒÁÖööÔÔŒ¬Èó ‹4Ã<ñø««+§OŸªT«’$-,.õbF ‰jÕ`žëв$Õm·<ß¾ßï›–U˜\ܳ Iàľ}/8L÷z½Ÿüô±f«Õj5Œá ?ì:ÞhdNÏÎNÔ‚ÝœZ[;sv=M³r¹*+ ESI’ú¾?B Ëxž†>ËrŠR(jZ¥Zžž’$q4¹ŽòÌõœ ð]×’`8B9›$ÃÐ4Ã1l*)XH,¶1ç¿øÅûï¿ÿ¶ÛnûøÇ?^*•þöoÿ¶Õj}ãßøíïW^yåG>ò‘¿ù›¿‰¢èàÁƒ»…kkk»·×}ìc=ôÐg?ûÙ}ìcÝnwiiéºë®ûÞ÷¾÷àƒþg·Ùó¼¯~õ«ïz×»fffÞÿþ÷?-š}Õ«^õÿðõzý÷ÿ÷ßúÖ·þ|õï~÷»Q}âŸøâ¿˜¦éã?¾;„ûÄO>øÁ~üã?xðà_üÅ_œ_ë™û{ÕUW]qÅÿò/ÿ²¹¹9==}íµ×>ùä“眀‰‰‰ÏþóO<ñÄos¾ño\]]}ì±ÇžV~äÈ‘o¼ñíoû?þã?*Šò©O}*ÏósóokµÚüÁ<úè£Y–½úÕ¯~ç;ßùáø\†¡±±±±±±±ßÌÖÖV—^z)Çqã«ñËDQ´ººº±±ñóK·þwôÄŽCŒTu¥61¥iEŠ¡B±ë¯5WúÝž90c?ÄÎ…C­ —u]äy,iš ôŒVÐ4] ¢`«^OÓ$M”çŠZ(ëe–eºÝŽeÇŽké%Xß÷NŸ=ãX¥6IQL»Ómµ:ªRØwàÀôôŒ,IM ³= ðÁ ?èõþ ÝnÇqR«Õ.½äÒéér7ðã,5m;ˆ‚F³ÙïAàGAFa¿× q3 +©’Z(K%^à1' L”$^p¦iîyA'žïÓ¶›ç Ïs†aišÙÒÓ,ó=7Â,GY–¥iš„ÍR¢*B ¢$Ã0ƒ8ÍÒðüÕ_ýÕîzËW¾ò•¿p–ì¯ëàÁƒ8Ž¿ï}ï{ßûÞw®pnnnw‰æÃ?|ýõ×ß~ûíozÓ›v8qâYFS¿}›ï»ï¾n¸¡×ë}ûÛß>¿üíoûýRªÑ IDAT÷ß¿;}tgg禛núâ¿ø´ºF㵯}íG?úÑ?ù“?Á0L×õÝDGýû¿ÿû÷¼ç=ïyÏ{šÍæm·Ývçwž«õÌýE½ímoûèG?º»ûÔSOÝpà ¿«[ö…^øÜç>w÷¤Oó¡}HQ”Ûo¿}7'p§Óùã?þãskeI’¼õÖ[w§1‡aø‰O|âi)ˆÆÆÆÆÆÆÆ~ívûyÏ{Þ¹,Œc¿MÓûöí{ì±Çž!æ¬Õ&œÈsP›˜˜šž¡(Ú´Í¡ÑކC˶#,F•RU’•$Jr”Š‚\Pä,M]Ç ƒ C9NÅR1Ç@»ÛŽ –ãlÛdXN8MW8–XæºN†Ò$Mý Ž,ch.,,Æ êÚÝÞ Ç‰Éé™B±ˆaàI“†ü(È3Ô Ξ=Ûët@öìÙsÁ¡ 8Èq¼ëùm×ñ¯Óë5­‘i"„Ûô}ßó}†å ¼.+2Ã34M™$€ Ò$N@†€Q»Ž\?NâÀò EQ’DÂ,K†ÅId»N†IAHâea$!ÍÒœÀ’$ôÝCÉPÇñ4CЧ È@Fdy‘çe9c04m #M³Yž…I˜d±ù¦Ù C’„,0âIÒLŠrk`…±GR$Ãòqú~D’´È‹Q “$™f¨$ "%YÄH¢9ʳv»å†TPs°<3 EA`a‘ãqY޹ө7ÚM”åÅ¢žg Óî$Q¬*ŠÀñ£(yž¦‰Às¥J è8Ê\N0žeVNœÃÈ4-ËvVWOæ9V)W8ŽËây’0 Ç™l·'ýÐs}Ïñ|Ïóq’Ü39%ÉŠ16[mÛvšÖu½¤ë†eqÌRŒ, Iâ8Žà¸îÖö–¢ªi–õ}Ï÷xž¯T*IºŽÓi·Y–-hª^.fY-C©ë9I†aEž¬()H£4a(†fÙ ËviŠVMeçy^d)ƒFýè±'O®­öý•Õ0CH•Õv§³Óh’=3?7;7Oฬ(…‚š¦ AáÆ Ÿf dz¼À3Fa–š½ÞÀ²,½¤8NpÿÁiaÐï÷£$¶L‹€`XEžgúa(ˆEC¥0Ã0žeZ€(ŠËËËAœsgffJ¥R·Û=ÿu&ÿDQœŸŸ÷yvûL©¬W«5ƒÆÆÆFY×/»ìÒ‹/ºfÈN·uúÌÚwý†3s )€ӓ³µjõÌêñÕÇz½¾,+µ‰IcdfY¾oßþr¹œeYG“““Çщ„œ$p ÃÆÚÙ³ÛºiÙiŽdµPœ£••Ó²ÊÕÊÂìœ"Ë$$TI’x>‚µÕ•^·FqŽAœ¤eE}îE¡,kìÔ»6Ê2Фz½žãXŠªºàÐÞ}{ E ‡xß<õÔÑÍ­MÓ…QH3 Ï 8F2$ËÒ{v½Ýé8®g˜#Çr°§ ò‡ÄÄÄd±¨é¥/Ê\ßÃp¢ Q,CQÆ$)€0  Å$áþе[m#Y†¦iåjõÀýÅR±Ñj(Åó<Ó4G£‘ïy$IJ´HxŠÒ8‹ Eäyzʲ(2œ‘x$ç€,”4… a†¡ CE0«– “¾kû~€ˆ¦©<‡^9n”¤©ëûA‰²<qèÅBAU1 K’ŒaØá`èû.Ç3’",..J¼P.骤fiÖj·ÇÙj4Ç7#Çq œ\œ[$!åšv«ÕÙÚXßÚÚ,UK‡/8Œ|åøêÉã«ÍfsØ3’ "qL/vv¶O®­ÖÊúÿcï΃-»êÂѯqÏã™ï¹s÷íNOd`Iò=¥°* Â*P,€B•*4¤@‘É" E$RŒ "“’BB¦ž»ï<ùœ=k­÷ǵúÅð ù¡¿÷û…:Ÿ¿ö^k¯Óë{»ï:ýÝ{­µ5½Èòñ$tÜz{¦}Ý5×ð8B‚Ÿgúýažm¨š±rÕÑÇC !33­8Ž,]·L]°’¹$UU1Aç/_ £QÒ¬T-×Mât2™`JgfçlÛÞßßËÒäúë®=yâ¸c È‚ñ(¤LJ“<¿ï¾ûâ(ªºÎìì¬,Iy– Áò<£poW–Èx2¬Ô«–i̵gÒ4&ù‘†aœB(„D׉nšKA˜E·,8ã<ËTÆsˆE³U»öº§h†œ¤ÉÆæÎxìiªa6­z£áØ®‚2;;[–åý÷ÿðâÅ çΟB´ÛmMSŠ2÷â( à š˜¦CÍó" C„P¯×;ýðCã#GŽ,,,t»ÝÝÝ’1UÕ*¶Cˆ¤(œL‡¡©©©©©©©©©ŸbÝËÛšªÉDR¨¡Õçé 1m‡Øßêyž?Ûn‹(FcÀÂҒ븡$É=ÏãTÕŒj­6žL‚ 0-KUB0İV«Ec¹n(Yi†ã~%%›ÛÛ?òH»=»²²"It8lmï†nÛ6&˜Ê” ¶½³µßÙs]çé×ÿìÕ§®v'Ïs?J×V×××6†ãqÅýÑ0-rBÕ´Z½FeR­º†aŽãXÖ€ÈøÐÃ[»Û²¬Û¦™§éæúÆÑ£Wiª:èÂ0VU­53¹ØÙÞj¶Z­VÓq˜ªÈYžfI,,Éšç~øÃû/_º”$©aYœƒÀ£8¡T>´|X@Çq™çƒápØí€¢Ð(ýÙ§>õæ›nžkµ¾÷½{äâê ˆü8 ƒA´rxùð¡C€,MæfgjÕêÙógWW/ÇqxìäqÝÔ»ÝýõÍ8 MD'€øã0 9ƒ„ȺÂ8míìll®cÜŠU­Y%KTfY,+’a’¢Ï¶ç5]ŸxÁÞ~B8Ž|ßÃðâÅ‹ÛÛ›˜À£GW £Ñ€±²,Ë4MUéº !(ÊâÌٳ뫗/ßž™9yüøüâ"¥²„išÙ¶ëº®ªªTÂãñpšsNMMMMMMMMý4û?žõÓ08窢J?X[[_ߨL½¨¢›¦¬¦Q”&±m;º*o­¯íìnœíìnS‰^:lšæÆý[`×2)¥‚ùù¹CK‡~8OF“ÉD7ô#‡ ã~¯ŸåŒ´¹¹ã:ÕJ¥jÙ–nh²"¾1ÖTU׌²(wv7{½®,˵FÝr]Ñ`äm¬®o­oîloûAP”e’¦£ñÀ©ºn­ŠeÉ´¬™Ù6!DÓTYVœ•I‘³¼ˆ³H@ QY’$Æ*I– .ò¢DÖj5V°À9gY‘…Q¸·ßQy8¦yjZfµV54ÓÔ-Y–8çY‘ dUÎÒa¤†e*%y‡¾ ?åeg0ðý 53Ce5H’$Íe"y†‰B1%¥"CERd,a1J€D§³¯ëêÜܬ,‘4I0¥Žë^¾ti46›õCËË+‡— MsL»R©X†E±´·×A­ÞrèäSN’<]ÛÚLÓÔuÝ™ö cìÊKãyɪÕj³Ñ´ 3 ¢Â.+0E”xÉFƒá¨×ü”дœùV³57³º½J0L –çc¥¬(àA4 “$%˜:U»Ú¬Fegé(D €T°°mcq©yäØáÖB#,ÂX¤B ¢e! EQ$™bšçyY•„b )ЬB€ÊœeY€4‰³"X–«E‘ ²mKQÕ$J'㉪è¶aEQÌÏÒl4zþx2å,C`‚²B ¥ð™Ç˲<Ï ŒQǬdEÉ Í ²\%€b,çBp AH`A˜¦€—„À$Ï˲ˆÓ¤,rÝTM[¯V«yZP• $²,‹“”CPmÔ–4EA„ Œ³,ÃŒ'“Õµó/§y®¨Z¯××t cG¡ª¨ËË‹Á‹Ñ°ßéL¼hlÕmÕÔô£GtC'”fE–™m9V£Ñj .8‡%{{ûi’æY>žŒ³<Ûïìt{ÝùÅùf½¥ªj£a_ó”k=?¨8•|p<ïîì†ÍÐtKÛïîyaÔš­Õ*¼äiž'aš$©,Km³æÙ$ðû½Þ¸ÙÌÚi!É×^s5Kãnw¯7ìïíïÿÓ—¿üÃs+ºÒlÖ=<ýÈ…É8$P‚€œ»pÑqE¥šJ žnïíìuö˜`•j… ”¥ià².+’j[ B$¬QU—´Þ^wØN&Ã0ôö:ÛWmÅPÇþXo4ͦm¹Ã·³³+87-Qä‰,“z­R©º¦iEÑíôÃ(œ‡Qœ&9P¢TpÑ¨ÖæÚ3Âá ?Xïfi¦é’(çŒRì:NµVu+Îd<ò¼I–¥ªªT+n'qOsÎÿ~ozÓ›žþô§[–åº.„ðIÑç|ä#®ë>¦ðãÿø?þã??÷¹Ï}Ýë^·¼¼Üívïºë®|ä#Bˆ+W6Ûo¿ýÏxFwÝu×_ýÕ_=ºvjjjjjjê§@šfkëë—×Ö^ðü_xrõ|us5Èš¦­GQ¼½±¤‰i˜š¦" 5U_>¼|hå°¦ëãɤ(X„š¦ÏÍ- „÷;{QµÛsÃá"Øl6—––lÛö<Ï2ŒF³Ê ÇѸn­îlnìÊT[Z\¹êرťE@Q£íÌug¼Ð—Éq+†nð¤Y7Œc!„i›ó‡æ«­ú8œtF;ûýý½­½x«m7®¾úªùÙ–ëÚFQ§A YjV,Y7ÒŒå18/g¸‚AJ‰Œ¡Œ0E,g~8ÇËnSWIaë-êÈŠê¸UI’F£1ÜEФPD~¿,K!D Jιa’ì"/9g’D)—¼±Ÿ³!D‰äºN»%çie™`2Fyšù?K B¨)²®)ŠD ¸c,QYUTnäE&©(…„ÎKTÑ Vr?Žg‚‰çI’ÅéêÚÆp8¬T*µj=+ò¼ÈF£aY†aX¶zB0FÊ%t{k;Ëó^·×¨7úýÁhâ5gfÛ­Li·ßoÔ7=ófÆÄÝwß}ÿý÷ !E‚ÆògÜxý‰ÇmËQ­Z©º•çÅáC‡kê·¿ý¯6tî»ïIžØUçè±£+G'IrùÒe]Ò Á”Òª[­µco\ð†½ÞöÆfÍ´cÛ¢5fgn¾åç L¿ý½ï¬on(¦j9 –eB³¬hÍ´Âpc<ôÒ¬”YÖä“' »üƒ çÎö&£Z£Aˆ´µµ7 Á²Z“°äš/EäGy™+Dv+®`¢dåþÎ>€HÏõq0‰³T5ÔÅÃK­ö @ Û鯯nqVBˆFƒa^¤ŒŽc¹®i›ZœD“ñ8IR‰P ‰?)Ë<—eEU Qg¿×éL¼Iàû²,3^GUÓ–+Õ çŒ`Ñëìuº ðUUmÔë­zÛøQœMsÎÿ~·Þz+൯}í{Þóž'KŸc~åæ¡C‡žö´§½ï}ï;8½å–[¾ô¥/}ýë_Ï{ÞsõÕWèCj4o{ÛÛjeYþ—ùÇqÞõ®w---½ÿýï¯V«ú§:ý—055555õS€1¶³»{ym­ÛíÍÏÎ>íg~æIÂ`,z˜ˆjµU«UB°Á Ûétþ: Ä„ DZ5ÕpœŠcÛþh´µ±„¾¬*3홼,ýÀ“dɱôzÍeœ~¥‰D°k;†nT×¶lS7·6÷¦9ç¼úÕ¯~ôé§>õ©J¥ò­o}ëàô-oyËêêêsŸû\Î9 ˲7¿ùÍï}ï{ƒ üÚ¯ýÚÉ“'oºé¦ï|ç;)èßøÆ÷½ï}“Édúƒšššššzòê«këë×Y9|øY7ßLÈ“ò¿Žºk¤i2œÄªP*Ñ’I.ˆD EL°n¯·±¹¹ºº> ›í¶ªjƒÁh2ö¥²¬ŽF#ÛvæçYøŠ IDAT ]Ïó|7Kcа¦ë“ ç/Þwß#2Áǯ:2?7ÛlTT,Çê{çL¦ùÄÒ¼X¬U-Ûqª"Ü©ê^<ÙÝÜÙí–$SlÚnWmG¹êè¼*c¨•H€$L£c¢$Qx ˜q ªšïLBa f PI†)ºŠ–¨,˜ÀqƲ¼ DD Æ“0scça–‚THAuj¨Ž©™ó­YMV½Ñd„‡i—ó‚1â$gyg2M=á%Q’$ +J@Åãáˆ`\–¬Ìs¸¬HƒM^ ‘çŒó$Ë8gY–a‘C*ºQ±]HhÉ8爊‹¤äZ©ÕÚ3ºDW/^ÚÞû~DŽ]1M"´½»3誵j[Ÿ±[UUa³Ý:|h¡¿8þü¹Ëkky^Fq|°[’¢¨Žãv:ý8‰Ó8YZ\Ò Ë0mUUu]·"dZ¦nè²,ïï÷‡–]ã¬,Ã,Ï1Æ%+4Sk/¶÷ÑåKº­5[-&Äú榢j®ëæi: MVm×VU…hZN»V¢pskskkÃÐTE׆Áøì¹³§/ž;qܵÁpÐév’,UT]0ªiZ«=3yqžîìïw‡ýjÍŠ³¬Ñ¨Û•jÉÄäšk®®8•­­mß ü‘ÏsŽæ°"ËŒq/ð³,@ »õ*„PQÔJµÒn·¦ƒÑ°Ûí‡Aˆ ±- P¹®é•J{v®OFŠB]µR¯UVW×û½¡aئéhªièV¥R«×ê€FÀ,„À­¬’™H¤ßÛƒ NbƸD%$(xàùyšû^XæºòÛø²—½ì«_ýêSŸúÔý×FßúÖ·Nœ8ñè_×›nºéž{îÇ»»»wÜqÇ•%‹O¤íã8qâÄ·D«ÕºrÁÊÊʧ>õ©n·;ÿþïÿ~yyùÑÍ———ï¹çžn¸á-oyËÆÆF¯×ûÛ¿ý[Œñíóãp]÷ßøÆ ^ð‚G~àxç;ßyp¼´´tÇwœ;wn2™lmmÝqÇõzý Æ{ë­·~éK_ºrzêÔ©¯ýëÇ‚ñ>íiOûò—¿ÜétºÝî·¿ýí_ù•_yÌ盦ù¾ðYÏzÖO<.×jµ¾ð…wÞyç•ù±W_}õ½÷Þ{p¾øÅ/jšöÌg>óàôñ·¶¶NÀßüÍßhšöœç´´¸´´´Ôjµ „»{{ÃÉ(Íó‹—Ö|ðlå‹ ‡Ž=²²rheeya¡mÛZž§»»;~¥Y‘çLVµS×\ý´žvÍõO9~õU­¹z²Þ¸³ÛÙ â–˜åȵº^«Š ‹2 üÑ ßÝÙܺtîÒÚÙµµ³—^_;½¹sawóìÚÚé k§Ï¯ž¹péôùK§/n]Þòú^™r †”— Ir! FDçE‘ç’,$‚ˆ Y•m×rêÎìRûÔµ'N]wâèñÃËG–Z톤JIš~Xä¥,i§Zuêºb € K2‘MÍ´ K• 13ÆY)„€"àqõú½(ŠJÆ£$ “´ä@T2Q¯×ßÝßOÓ abÚv­Ñ¨5[µF³R«é¦©éFk¦}êêkžríus ‹ªnREq4Ó"“ÙuZ½Úl6—–---/?y솧ßðô§?]’ä0ŒÀõzsvvÞ²œ G£±~EI’fY§Û튪>|øÈ‘#ª¦ž=wþ_¾qï™Óç××677¶z½>D°àÅÄŸô‡=/3Pj–FÄÁöÞöæÖv·×OüÍí]IU+õš¢kAÀ…JhͲjŽ£ÉrEç.]øá#þë÷¿÷ÃÓ¯ÖlÌÎÍqÆ&Ãq0²(‹Ã´ßdYaÛŽaY‘÷†ƒIàûaX©Õ·RÌ÷|@¥R9yâÄÏ\síòâ’é°3ìlwü±Çq†^ä¢T µÚªÍ-ÏÏZlÌÌ@B'žßíôFC¯,…®•‚ \Ôëõv{F×5Æ ]WffÇŽ]Zš§æyZyšÄIgY–&I·Û›AV0€ ĘA%ÜžY>¼ÔlÕ$ÇY¸»¿=õ9/%Š…àaŒFÃ$M CÿÇŽ………[n¹å£ýè‡>ô¡4Mo¿ýöO~ò“×]wÝAíÉ“'¿þõ¯ßwß}¯zÕ«šÍæí·ß~üøñg=ëYiÉã·ý1·Ðúý~ô£WNã7~ãºë®»2Ïsqqñ{ßûÞÆÆÆk_ûÚ²,ÿ÷ÿk_ûÚ‰'ò<ÿ÷Wºþ¬g=ëío»ëºüàó<Ñ‹^D)eŒ=~ŸÇx<–eùÕ¯~õç?ÿùƒ’F£ñêW¿úw~çwN¯¹æš•••|àkkkívû-oy˵×^{à 7<‘x—––žýìg_9uç9ÏyŽmÛO$^Çq¾üå/D$„¸þúëO:õ™Ï|æÑŸ¿¸¸x0=ýúë¯ÿÉÆå—¿üå„O|âWJ(¥«çdY8vìØÁjÏ“'Ož9sæJíÁñ‰'>ûÙÏN¿­§¦¦¦¦¦ž¼žÿ¼ç^^]ûçoÜSqݕÇ“vÞy×ÿ}pðŠÿë×þw„s.IR½^øs®ë†ã8‘¢0Þˆ·:Aɀ㸶ma<1Ƅвd@++++‡W,ÓÐuÍuE•öööʲ ‡/¯Ž&þâÒ¡•£G×u+öÌl³V«ýàò…KÛ;{ŒHQ‘i»GO«·ë½A<Þ~{ì÷!fËtj†m(*!”‰xäq\Äyxy ¤C‚™Œ!Âc¦²S«£UPRPV”eÉ@–¤ƒ]mcE^@ä&0ÂsUQTM•$*Q‚.²"òcž±¬L“4)xA$j(º&kã I&®åZ–Å VäY…q„%‚„yžGQÅq‘ð,Ë‚ ˆ“T‘ ®ë’. Lã8 ‚0 BY–I@(² !–(”$IU5!`Q”QœúavªÕ8Í@AMÆã’1M?x{ ‡¨ª\©¸œ³Ñxˆœ›•õÌ…KyV8N¥Ýž·,+Ͳ4KãñÈóý½ý½K—/GÃýî¾$Ë­™V£ÙFÃË£Ao$KšDå,ËZ­¡d0ìíï®o¬õ}€Äüâü`0Ž'i–*GQ<€ÕzÝ4MQ–€qU‘Jcˆs]UmÛêyãN?Ä! 7Ú3õJ#aF,/9€%,2yÀST B çœ7šM‰"Ë2€I’jŠ¢«z‘¦‘ê• Ïy™°$XŸŒ< @É‹¼(â4f)Š"i²éÚª¢qzÃag·Óíôò¬°L‹ ÊYI0r§V©(Š\ä)Æ R©6µ²,ÂÀ㬴LÃ4uV‚,M#pÆ£(MÒt†C]VTU·lC3uÓ6¨lë¦ÊE¹¹½QÄY’™„RÎD‘aEÑÜŠóBÈüÁ|ík_Ȳ|Çw´Ûí½½=Àë_ÿú²,á~á`:¥ïûŸøÄ'žùÌgÞ{ï½?¶íÍ9ï¼óÎÚžÿün¸á¯xÅ`08(¹í¶Ûò<ö³Ÿíû>àÞ{ïÝØØxùË_þè4P«Õ®¿þúƒÄì½ï}ïAáíóãøä'?ùž÷¼§Z­‡CÀK^òÎù§?ýéƒÚÏþóŸûÜç®\<ï¾ûîS§N>}ú¿8&>~¼×\sM¥Rù£?ú£ûî»ðÅ/~ñƸüÊW¾òŸÿùŸ·¶¶®”\¼xñ©O}ê•Ó›o¾peÏ¡jµúýïß¶í{î¹ç+_ùÊ›ßüæƒÂéWõÔÔÔÔÔÔ“Z½V«×j?{ýS·wvV×Öþí÷ÍÏÍ­><Ój>)RÍ+F£1!ͬ ÄÕªÓ¬7mÓfE¹³½³½³•f¬Öh™–Íìõúœs]78ã@Ó6Û3íz­FRE×µf«Q­Õî»ïΞÙÙëX÷ªS'4ËŒ³8)²(Kpè÷Fãµ­í‘q\ IQ ]RÅVg}¿»±¹sygw³×ßG˜Û–Vo:¦­ÂAVÀ‚E£I8 &ýqâe,G€Éi9\<¢ÐTQ¤Ud@(‡JHe¢Ž_2KÆ™#`š¦ŽmÛ†Å8‚œ ˵y™# 5]CÊ2¥”0^feŠR¨lSK×4‘,°ÈÄÈqE— ‚šªS,! ʼȒŒLÓT‚ nœó^aÆ¡$Q,I‘#?ŠüÈÔL]ѬäyV$qdI–ç9ä€*K²®¬àeÁ1@‚ÍõÀóý0Ä-²2Ï÷eEÒu=IâáhX«ºÇJÒhÐíN¼qµâV*•,ËÊ‚™†åºŒHž—„H­V[’F¾a¸º¶Vùp8Èò¬Z¯ªº* ÐMcee%O/ŽÇ“­íUÓÜj% Ïœ?»³³ÕéîcJæççmÇaŒÅiŠ0¥IªiÅü‚ªë Œ‘.+UÛQœc-C¯U+ÃÈëô»–ë,Í/7k "`8špÆ)¦‘¼ä¢à²°ò¬`‚ëš&Éò\»í“,ËËŒšb–©y’"å7Umi~)ô£ýNgX‘„KVfy–)$¨¬à…Èâ,-FãÑÄ÷£(æ%ÏiÁr®jrk¦î8&&0OSEÁó³mÃÔ!ç.\8wö gåüÜlµÚÈRxqš–þÄ“$É $IÔª¸³s-ÅP!–m9‹‰ò̹3aÅiÌÀD0ƪ®ÉºòØ9W–ð]¼x033s7Þxã÷Þ{ïAòøÂ¾p¥ðǶ@eY¾r«éÊSÊG;räÈ'?ùÉ÷¿ÿýwÝuוÂç=ïyßüæ7Ûív»Ý>(ÙÜܼöÚkÓö£ýè~æéóæïþîïþò/ÿòE/zч?üaÀK_úÒ¯|å+W2a!„eY/xÁ MÓ<˜XÛl6ÿë9çãÇ»µµÅ9ÿÃ?üÃw¾ó?üáž7>ÆÙ³g]×}ô†@ÿCnºé¦ãÇßvÛm.üÀ>pçw¾ûÝïþÌg>sêÔ©×¼æ5I’ ôï³1ÆœsÇqN:5 „Bˆ+Ó›§¦¦¦¦¦¦žÔ0ÆK‹‹K‹‹iš®®­ÿà¾û^ð‹Ïr… K*`ÔùA°¼¸|õÕW7k Îøx8šŒüпToÍY9R”ì‘GNûA°´¸EQQµZmaacœ$I³Ùœ™iUªB0I’õõË«—m§¶¼²¬YÚåÍKšJS¯n­å〤 Z•F”3(IšmQMÚëmF»q:Ž÷ý°›ç¢H UUDhD”—i’gy8öÓ0™ |P ׬c¨'ãæD‘eŒ(™Kp©RYU!%@PU(AÇë Gªí`*õ‡#€ ªA 4­R©(ŠÌz^{~–ª” ¦*Ö€7O§5-kåèr‘,ãYœ‡,βŒåÏy™nèRI£(ö†iš„ã(LÒÈqVc¦(²……9I–4M Â`4•)•d˜g?Ž~¿ÿÕ¯~õÖ[oýð‡?¼°°pã7¾ìe/{t8_ùÊWÆãñw¿û]ß÷ ÃxL¼?ñ˜þøñ®¯¯¿â¯ø“?ù“ï|ç;EQÜsÏ=¿û»¿{þüùG_Ì9ÿ¯lÞóªW½Êó¼»ï¾ûÑ…ŸøÄ'~ï÷~ïõ¯ýúúú¯ÿú¯á _¸ò§A`Ææææâââx<ÖuBx%ÕŸššššššúé (ÊÉÇOž8þ¤ë9ËÊ¢(ó¼¨Wš5§ak¤ÛÙ»táBE‡–×Z3~¬onôýååeÆXš¦–e5›ÍJ¥¢ë:ÆXÓ´JÅ•$iuíòßßý÷gÏkÏÎýì7]uü„¦){ÛöÞîÖÚöV'²jÖ›sv¥¦|ÄP*°!ÛØT@R G;ýþNQä¶©ÈD9O‡•d‘æ~4Ü뱤ÀYD•© }&¾š……,AE–tÆK†e†dY…’Ä!â„ g€–^(s°R ÁÂÌD2e8›Ä ³ñ‰+·®ÄrÛm·ÝvÛmªª&IrÕUWɲ|îܹƒÚµµµƒŽkŸ F£a;;[ãÉøâ¥ ÝnïĉãÍ™™¥Ã‹sK³²BU f«E±nUŒJ­„xy ‚ŠkØU‹(hâõ:­Áp7ÏŠ „Åiœ—Æ% <ÊÃþ8¥º¤b€$JI‰¸à(ç*@#™"C—Ó°5¹ÈL–h!@Ry‘ªT%9Œ¨Œ¨ÄdB”\0.8*¦a—<Éó„C:Vû)K‰L("‘\NçIšA‚S%²ŒÍ“Ìy¦fئ™ÅiEŒ±È÷²¤†¦ëZµVAyc¯,Ëf³Y©U©L÷ö÷²4©ˆó8M’,Ëò<ÓTES5JHž¥q²’)ŠÂ˳îsŸK’ä%/yÉK_úÒ»ï¾;Žã+U+++ÿøÇ΃œóG›ÄR¯×Ô`08xÅÓÁs«¯¾ú'ˆwmmíƒü iš·ß~;ÆøJO®ë¾èE/ê÷û^qúýê¯þª¦iÿøÇÿ³ îüæoþfÇßøÆ7 ¿ùÍo¾éMoj6›Ýnðó?ÿó€'2yjjjjjjjêÿ¦nêªA%ª):p¯Óétƒ•Ç­FY" 0-SRäÉxœe…aêF½V«†N©$„ˆ¢pcc}0lïlÆÃV«µ¸¼Po6 ~4‘™åiœg€*HÕ¡ašB;¶Õšk:®šç“ÎþFw3ñ'2* <åe§E8Á™ uˆk)&àBÁr^”%•¨¢bÓ‘+ÓµlXˆŒ &/JÆJ–eU’eMÊ9/8ˆaÌÆy)Ò²(‡K’BK1V .D!0êO’"• %Âd€(„ÈPV%,‘B€@IRP1!,LBI§#„1²$›†Yu+E^tzN¯ƒªW%/5ݨב zÀ‚1V]Ñ4M) %MÓ"Ëg|0L†#!$KR]S%EæœU\ǶlI¢¶a--,\uô¨¡£Á`ggw<îììtöwG£a‘çœsB°[©šº‘Ä1¨âØnÕ•dFáÎÞN¯×+ʼV¯¶ÛmË4/ž¿ÐíeQ(²ÄÊ2Ïó^¯+ɺfj²*S‰È˜Öê®i™y‘çB „ºn–gºj¸®#SIU$E¢%ÀコÑh$ò<£, ûƒ^”Ä–ëÌ,ÌBYòâ(NR8ä A1U4ÊrÊ€€¢)®kÉŽB¯×ëõö÷¼‘WdeˆˆJdQò,Nö÷:®mcvöv.¬®ö^Á…é¦mTUI“ýÀð¡F‡–)Š–Æéd4‰ƒDÓtÕQ K“©ä¹ªËG¾?I²4Ny†BpÆQ½Þ^Y96?¿”üôÙs—/¯QdÚf¥RTÚ |/ô¼ œ‹B†A«Ùkg¯ÓÅTj¶fÚí¶ãº“4ÉF£ļ?è?ÑœócûØç>÷¹?û³?{Ç;ÞÑh4þâ/þbooïÑïüø‰Ý|óÍo{ÛÛÞõ®weYvêÔ©ƒÂ .l”úö·¿ýk_ûÚwÜñö·¿½Ûí=zô%/yÉ·¾õ­ú§úŸÝç(Šþáþáu¯{Ýâââ›Þô¦Çd³/~ñ‹ÿú¯ÿzkkë—~é—^óš×ühóo~ó›Y–ýùŸÿùÇ>ö±²,ï»ï¾ƒG¸÷ß?àÿøßñŽwœ:uê·û·Ýêñã}æ3ŸyÓM7}ö³Ÿ]___XXxÑ‹^ôÀ<:áÌÎÎ~ä#¹ÿþû‚œó•¯|åÙ³g¿ÿýï?¦¼Ýnÿò/ÿò½÷ÞË{éK_úÚ×¾ö­o}k†µýèGßð†7|èCú­ßú­¥¥¥7¿ùÍ_ýêWÖôNMMMMMMMý/×l´lÃŒü ô|ß÷=L°n+ûÃå:ЮކÃ,K+•ê⢡›„`ÎÆÈ4MÄææúÚÚšçM4S× £(`<Çyz¬îuº9’¦CIJXVb^Ÿ«ë¦&ë(N'Ãþö¨¿ÇóT†Pæç‚g\*,0вdH:U0D€.¼eÇk²lª²)SrÆ~'ç%D"À J,(9çKy^Œ±€pˆ‚PB‚¨2@¤ ¤ä%‡"ó“"O°)Dɉ*™UK2FÀ¢ä%„X3t-5DX%, Î!@pˆà%c,I’(Žašô{}oâ)úÿÃÞÇJvÔ‡£¯õìç¢A‡ IDATô¾ÝýÞYìOƒÁæG‚H B"J („H!"B–)"ù IÈRHP,– £ØÄŒ±±=ÏÌÝ×ÞOŸýÔúþi~~gHxä½þüuªNUwUßÛÕýíSUÇB”œ™Ô¤ÃB¶K×t×NâØ ÄvlDZ!rRðÓ§Nk¥77·vwvÖJÊi2ÍòÌrl„ i†A+A°¶¼rþܹ³§ÏPŒ=ÇÆy&8;8ÜßÜÜ䜷ÛíV«‰âY¹´°Ø¨U “6µ3gNÍâéöÎn½Ñèv;ÕjEpÎXiPJÄ ÁÓ4‘2h6„dÕzÕ\à “Ét2PJ,Ë”ea[v½^ <#l8¶iвȋ’%q\$qžÆZ !¸¸­^»Ùj¦e‘™kY"e^yA=Ã0ÍÑdÚ?9žFa£Ó¨T|­Õd2Œâ(Ër‹’ªçE2Iã˜e“étw!µ·¿Ó „†Ä4›Ý¦aJË,M“4ɳ¼Ýéœ={V0±¹¹eÂ!P”iœ©˜c[ëK޽±··÷ÄåKÃá@ -˜@›¦W©¶ ÃŽÂíí‹/j­ëÍz%¨¦É”ʲx–&Œ1ƒâ,ËNŽûq÷ûƒ<ËÂÙhÜl´ÛíNP©8®ë¸®išínË \þº1çç?ÿùw½ë]üÇ|m½åÖÖÖ+^ñŠÿp–ìÖ… Bï|ç;ßùÎw^Ï\__¿¶Dóë_ÿúí·ßþÁ~ðõ¯ýµS>úèÓŒ¦~ò6ßyç¯yÍkƒÁÝwßýäü7¿ùÍŸûÜç®M.Ýßßÿýßÿý¿ù›¿ùº¿þë¿þ¾÷½ï7~ã7 „­VëÚD?üðÿþßÿûmo{ÛÛÞö¶ÃÃÃ÷¿ÿýþð‡¯×zêþ*¥Þô¦7½ï}ï»–|衇^óš×üW Ç7ß|ó³Ÿýìw¼ã?|ŠRúÞ÷¾÷ÚDå¢(þüÏÿüÉ› íîî¾êU¯úÛ¿ýÛããcÀý÷ßÿº×½nþñ6777777÷3Â÷+V«T‡£Ññææ$œ˜–éUHñÑè$ŒÂ Qá¢H³˜øôéo¼(8O¢(*K†1žN§''ý¢(ÚÎÚú*1(ŠÂÙ,%¢”t<™¦yQ­5üj Ìt«»Ü(Ê´?Ú ''ѤOe^s=TÇE–ANMâ#mLÈR+‚€a•R†ÓRj¸±\dø”BÓ³‘EJ‡ Ó’OF1T˜`h™Ø¦Ô¶ˆA¡V‚ñh¨ç‚!@)5­k >5RJ*¥VDT:ÏKÍJEH–—Ôµ ò|Š5ˆJ Ët(ÈQf Œ”JaŒl˲L3Ž£4Mâ8Ž¢Èõ$N”ÒŒñp %¨a@ âxÔµMÛ ¼4Mµ’† !#Ç2nÇ †TŠq®¥’JFi2íOmÛª×ëQΦáòÒÒr·WÅx8tl§âƺáûžãØRŠp63M«^¯w»½ZµÊËÒ©Ô:톒,KJÁF ,rJÐââ‚ï{aN'“8Ž1F±ÆY’æ% £¸(KjÐn½mÚæÁÁþÞÞBÀuß÷<×mÖ›fõm!PšÄ&H«J8™Ƥä%ga<ñ=o}}uqiÁ²Ì$M™`5̪Q嘉T)Dœ&á4 ¦I×V—ßÛ¼zåðä@IQ«Ö9“—¿Ò?&IbZ–ãÚI–=üØ#E™0V ‚½ Ú[Zj6›Y‘†£4K Ó¼ñ†¥¬(û'ƒÉxl¤Õh­Ó$éÛ²{ÝvµT«5p^¦E^ #ÆJ„q8B€ÝÝ£ìñ«‡‡%+z½®aQ÷‡Ã¬UëŽëlmo  ×P'Yª•ì-ô8gƒA#|zãô¹nh6Zëk§’8yâÒW®\=99ÙÛÛ+k6›+«+Ý^O#=N…V¦ãÓ”ZK‘ΦÅínÕvÂã““Ý£tšQI»j›B” бY=Žbmšõ^·µÐóëUL1PR”eGY’0&qÛv,æÐ6 cBò"åy„¡$i „˜ÔrˆiIs&’¸ˆ£ˆFCˆ³²`RPÛr ií†[¯¶ºÐ$ŠBËsM×É¢xv<泂gEžfB“VQކÃÉd µ¶l@€ Š™®Õëu!@ºTÙ,ÇEži­1ZKV–eYR‚cVË÷¼’±håi–¤Iž•¢F½^­T®\¾Tdy·Ýéu»õZ­Ñhlllô:ÝJ¥’çùc>ö­û¿­¨V«~%h6›¾ï9¦Ù­Ôâ(”RCŒ'|ïÁã~ÿÂ3ŸÁîþþ`8´LK2†¡mZÍzÃ6­"/Ó,…uz =Ã4gQ´µµu||¬”’œU‚àܹsço¼Q²r:A­]ǶM#Üluöúß{øÑ£“c€iÝnçÔé Û±âY˜¥ÉÚÊŠc¹i’…a†³(N”‚a3ÁƒŠ×î4ßMâðñ‹ìSŒ{^·ÝƒŠln³Ørœn·ãxæpÒÏʨV«tzv§³¾±±··ß ÂpfYÖúúƹs7}ûþûŸxâJ^ÍfseyÙs²,G£Ñ`0À..öºÓ4–——£(yð»=ðÀ÷—ÕjµZ­i­Ã0L’¸^¯55jJÅ·3ŠãG}¬TèÌç666Ê¢¸té‰þq!5l5›ÍVÓõ\ǵ—Wýª§€”J@5Ô&5y¡ÈêýÇñµ;Cþ”)¥®ïXóŸõßÔf!ÄÝ$Àáááááá×ßÝÝÝÝÝÝŸòŸ€sþØc=E¢(|ðÁùgÞÜÜÜÜÜÜÜÏÁáÑþññ@(n:¶ÔjšL!†žïÙ¶Í´M‡†IW––×ÖWLÇb¼”’SŠAE‘O&Ã0z½^§×­ÖëŽï_o6â4›N£áÉ8ÍòV§‹«FÅTf`z|ïpg8ÞǤèvü¦ãÈÌÆQtëØÒD*YBǰˆ• ™–‚ñÚžµ°¤·;ªÕÎ-'ÍÊ,NY ea#mSÛô Ã15i™d88H“Ôó½zµj$/Òz½nZ$N¦ãñè¸/£hR¯Õ(¥Iœ&I⺞ïU”ÒE!”Ô†á´Û~«ÕÀ( ÁB%Dp±Ó¾ñÌ©JP;<8D¶o˜–ïµj@‡‰ëxRRhM*yY¥AæÃÐÜÜÜÜÜÜÜÜÜÿ‡ ǃñxš&k̤À&n¶›­N{N¯\¾lº¼Økµ›*¥$cåÅ‹ž÷·6·•ÒF£Z«aŒ…J)¡ Œ‘a Xñê¶é<×Z™v\œ‹8Œ ‹·õ€˜(—Ùq÷#q[;¶e`ª‹¬P¥ÔD–B$B”˜Zžg5ÚíÕu«Þ–И1rÎM®”2M옶åÚŒŠKÉ¥5RÊКˆÒA¤æXšHs‚!P!„\(¨5À†a˜&¡”*¡¤ÔhŒ‰VH(” €%@•QÉ$șĮaøŽY²RŠV£á´”‚lRš§Dˆj5  0BH)„ ±-§Ùlµ[pžgq’欄1‰SYZdœs Å X žä ЀIY°2M’¬È ÓZ–ÙnµzÝ=V*%1BJ‰$šídiº³½íº.@ µgQœ¦¦™L«ž[·M–gO\~|{wPºÐëTkÕÑp˜¤±à,ËÒñhŒö\×u=Œ0Á¤V«“@¨g³±PÌ÷Ûq©A„”¦i-ö:­&Áx<ù®ÝiÔ0ÒRp€âl÷àx4Mò,­×ê^ÕO‹,åE™yŽÝn5kõjΊ8e9g9‹&ÓãÃÜËF·ëx^œ§ã$3 ìÙVw±áWì,‹gÓ0‹3V¨……µõåJ­±¹½&‘ÆÀôœf¯Sï¶{Ç{Ol^ªWz«QoA ···¿û[ÍöB·ç¸Žk;–i~cieQ*¡4{â2O“hÑhÔ†ãá ?ŠâÄõ}ËrÇãPpiÛŽï»¶mJÁZ­Z¥æ%I4žŽ‚þááÉþQ<‹-b´—ÛRê8Šw7w!„•zEq•ÎÎ b¡Z#hu³x:MÓY<9çæææææææ~™¦Y–%!óok?BQ¦i>EY•²D1É Ç¶kÕÛj½Æ•˜Ì¦žïõZËqÃh–EQ0-uÅÛ›ÛƒþÐ4¬¥¥EÓ´¥Z+)…<šEÃÑ(+J€LÛóýªÑl·!JË!‹Y:›ÄG\¥µŠÓ <˜òÑ`8ٙМXÊ €€ ¤cže¬Tä*§j×ZÕÕSV³kÔÛ)0f)ÏsMPÅ lM*t±´™–À2‰ïÈD 6ccD€TR‚ˆm;T&%—J€"¤áP(É´R„€ Vk…•–\&Y¬SBò‡ ? &¤ÓhV:¾iãRˆœ3 )ÆÄ²×q]Û¡„D³P(•eW²` "dšVš¦iš %mϪÉ4O§Z¥ŠsU¡Ó$Ž‚ Á$Šã(ŽÔ0”Ö'ƒ¾cÙçOŸù…¿äï~wgkKIiY&ðøä8I’"/m×ñ}ß²l!D–ç¬,ÖÓÉd‚l:Ê’xoÿ@Ýl6ºÝŒ•'LJ¢,j•J–¦ûe^,..åE.©QkÖ6N­A‚ŽÇýY2›†a–¶í`L«AP ªÕJEK9³4AÝé´)E¼,‹’ †£K—/g¹¬TêK뫚 ƒáQ–äQ8ùVÅ6Ýy4KÒV³¹°¸àAœ&–m Pñ¼(£4ÇØ#¦@ è{UŠ-ˆÈdïîì3-:^³Ù²7Ë‹ƒƒÃþ`P”%"˜aÏX8:œMCŠV£[¯Õ¡¬,”ÝÅn¯×5mƒ L-bÔ0 F4ÊÂãTd2)²Œ”ŽëÔëõn·%‰àyžÍJ–;.­UZRˆY8㌠lêK¡]¯ÖXh5ê ×4yÞOórmmí¶Ÿÿ_½^ïøä衇L²„Nâ,¾ºuygÐ?É’¬êVç1ç½g=ëYÕjõÚñ=÷Ü3Aæææææææ~ ¡S§NÝpà ó}kBNà2ÉmŒžýìg#ˆ¯\¾Zäy»Ñ\è.D‡ƒ±á8gn8³BV¿ÿð÷¾{ÿw J:îâ‚ïû@k¿â·:Ýz½q||òÄÕ+£ñÄqÝ…¥»VM ©¼,K §h ETXAuem…ÈFiq2T"CS,±`seié«_þÚðdXä9F˜—Âóªk+ëÕjÓ¶)äp2šLBÇv––—Ïœ=³º¶º¸´€)ºzùòÑñá ’¥™V*K¢V³å·ƒyÌù_ïþàn»í¶ jµ„ðD›?þñ×jµÈü»¿û»þç¾vüÒ—¾ô÷~ï÷Ö××ûýþ§?ýéüãZë럈Ï{Þón»í¶ç<ç9¶mÿÎïüÎp8œÿÌÍÍÍÍÍÍýŒÀ„T<Û´­Ããñd"¹ìöz®éÌf³$Œ«z³QOÓt2O§Ó¥•åF½ZñÛ2ã,‹f³F£e©àhÔÓÙfc±çÕ«©dLÃ5-ÛÐZ–œªƒZ¥á·*ݪMÌ㽃£­½pÿM ‹!¥ ×€kÈ4”†ãWõ¥ÓNm©Ä~¡-Î GPpXr.¹Âc¥ @iΙÒ\ ¶-÷ì4yÆ%âš"À „œªGdy‘CÆ,•ÖJ !¬Œ\­5•yQr)!Å–…¨aX¶+¤J’l:ž 1 &5¥PY”2¡±LÏ·-Ëp,­”fB—Ü´-@©dL0fmØ–ïûqC”TLˆ)ŸPJµEáx¾Ój6––Wú'ƒi8 gQ8ìBÊ,GZ»¶k[VµZµ ƒ`Œ`ŒqÆ!@–e)%¹äBHˆiš• LÄ"jÔkõN‡`Òª×]Ûñƒj³ÙŠfI’®íÌf3-™cQÛ²|§ZñÜZµrTœI¥l×YlµO:-8ÆE^Ô*5Vòt–˜´[ÍÀqŸ•••ååF£^rÆ•œÅÉÑñ1 ÃZ»µ¸¸Ø]XÈó˜s^q½Fµ´l{uu•sÎJ~xx\–LuîÜ žï›Ô°M«Õh&YlFÉÊþÉIžY’ .:íV¯Ý›Î¦=zñÒ¥KAÜtî¦Z­®¤ÌÒ´Vm<çægû£ã£¥:gŒ†çøíFsyi©ÛîT*Š0ÔÀ4H«Ñð}OJÎÓPÛ¶Iá%JåiÆJæU÷¹þð‡¯%_üâéK_ºûî»?øÁ>ãÏøèG?Ún·ÿôOÿôÚÙz½~ß}÷E1™LÞþö·Ïcι¹¹¹¹¹¹Ÿ~%à‚O¦ÎÈw<Šp–¦IcmË’Rôûýá`E%¨ØŽCMô,Bˆ‚€Xæ`2‚á4)2»x•Šß¬iƒÈ’+¨è$O¥*‚ª]©~ÝÅõ÷gGCfT ‹Ø&E"ml¸nФí%ôeås‚µA”&RÀ<-lä!© BëZ¦•¦Ò †cPŽQšhd`‹D(Qª¢tÉQ‘2A¸v°aZ6¥ jˆ&ˆØÐµ]Û4mÁ%ÇR*­¤H©ó¬à\dIVÌtÜFµR#4á<̲LŠ2Éò$¥Ä#¶)ÌX–Í"A¬€ä\ ¡´B†A1±L !ˆ1RJaŒ)¥EQ¨‚ àŒk (5MÓäL.µÖõZ- gEQ (F¥®í @jP¥R™LÇEQ”œA)¥E^ìïïcˆò4“Ýn·ÝƘìïîîìBˆÏœ9«V _ÙÜc½²¼Øi­tÚM­D”¦³$Ê#–U©Öê­–a£éô`ÿ0+2Çu„T…­f»UkÔ«UÛ4°Ò³É8NÒÑxÒi·›Íöc—žˆf±íyín·ÒlX¶… ¼J·U \‹³2ͲŠ_±Lçèð˜s!¥ò]¯^«7-×sMÓhµš‹‹‹BrÎXµR±©…¡aÐ………¥¥Å8Ž¿xiwß2¬nwbœ¤édb„=×]ZXX[]9ØÛg‘i;¦eU«5Ïõ1BIœdžß¬7ªA¥, JЀ•Œ±’ó çùt:}âÒ¥‡¾ûP˜´Š IDATŶm7k Dq’ÆÃÑ(+2.„í:?PRmom_½rug{!â{žïù–i€Ò8eŒ§IZ²r49¦qÓ7¬¯®b¨gÓi–¥£Ñpggk<«ï:gEÑ<最7¼á ON~æ3Ÿ©×ëßüæ7¯%ßýîwonn¾ô¥/UJʲüÃ?üÃ}èCq¢(ºí¶Û|ðÁ7¾ñÿƒÂì¹¹¹¹¹¹¹ÿŸ˜ÌÂ~1“…ÅåF½µÐ[lTj¾ëxŽÓm´’Y8 ¤Tá,Êó¢,˜iYË««k§N!J£$AŸ:µÖmÕM ³4‰¢Hyrt2M0$õjÍ4--d¿ß¿Ðº°ººR«U]ÇE"„}ßw-çäèx2çY¹»³wõêÕƒƒƒ˜íÅŽçz aÆIœìï_¹|9M)¸c[vËõ|+Š´Œ•T­FÓ2 Û²Ê,G²’K!PZƒéx|t|´³³³½µÕ?î·ÝŽå-X‰Ö ‡„ &$Š’«W6·6w._º”ge­Z¯Õêžë”N&QxÍf³™RRj¹¸ØÛX_mÔ«qŸL§)E·Ý®U*–mŒÇ£ÙdŠ®¿_ýêWõ«_}Îsžóoÿöo“Éä›ßüæùóçŸüv}Á ^pÏ=÷L§ÓÃÃÃ;î¸ãú’ŧS÷)œ?þ_H·Û½^àôéÓŸùÌgúýþx<þ§ú§õõõ'W___¿çž{n½õÖw¿ûÝ;;;ƒÁàïÿþï¯/{xŠ6?…Z­ö/ÿò//ùËŸœù‘|äøÀµãµµµ;î¸ãñÇÃpooïŽ;îhµZO³¿·ß~û—¾ô¥ëÉ .Ü}÷ÝçÎ{šý}îsŸûå/ùää¤ßïÿë¿þë¯üʯüà/y¾ÿŠW¼âE/zÑ=.7›ÍW¼âŸüä'¯Ïž}Æ3žqï½÷^ 8_üâÇyá _x-É»ÿþûçÛÌÍÍÍÍÍÍýlOÆYž;¶S­Tõz­Z |ßó\Çvq4ÓBZ†iš&AXpŽ1v=ׯ~µâøî$šq- ßñêUÓ÷$1+2É%†ØÀUШv–{õnÓ°MÆXÆ<)ÒAȧ¹N„Îذ+hà ¦½jiú3`åÈg$V Ÿs\¤kRq|ÆžA]Š)›Ï€Q&äVT–&Юa˜ÔÒÀÐÈÆVMÓ@QGA,•ÔJ !Ô˜jX`ÁPšB)ÅAÖJH¨Á#¤*³"™ÍâÉ4™†Ùl'““þl4Î’Lr¢†a˜6)¦„†a™5 Óô}¿–aJ¡XÁ8cœq ¥T 9“$a¬Ì²Œ•%¥Ô÷]Ó0êz§Ûi¶µZ­Ói¯®®œÚ8µ±qªÙjI¥²~߿ݿ»½gÖâÂJ¯³àÚîâÂÒÏ]ø¹õuŒÑÎÖö7î¹ç`¯^­œ=sz}m¥øE–ŸôûýY¦qEqš$Z)¡¢,в,ã8ÚÝÙ{ô‘G7¯^-‹²Óé,¯¬ÜxãÕj h²m‡b 4LâtØìnïnomëµz§Ó]ZZYZ^nµ:Íf#¨øè½¾^ ‚éx|txð®s®¬¬¼øÅ/þÄ'>ñÑ~´(Š÷¾÷½wÞyçÍ7ß|íìM7Ýt÷Ýw?ðÀ¯ýë;Î{ßûÞsçνèE/º–ý‘|dkkkaaáÝï~÷³žõ¬[o½õéôwmmí%/yÉõdµZý…_ø…J¥òtú[­V¿üå/_ë‘Öú–[n¹páÂg?ûÙ'?þêêê]wÝõÝï~÷–[nùñÆå×¾öµ„O}êS×s®­ä¾ž,Ëpã7^_í97777777÷3‹bZ«UêµAX Ù¨Öª~NÂþQ? #JI¯Û‘N¦ ‚¨,J aR«¬,Ó"·=×öô¡k™?²ÍOáÎ;ïüà?Øh4Æã1àWõW•Rÿøÿxíìç?ÿùÏ}îsÿçdzñø®»îºpá£>úމOÝßg>ó™õzý]ïz×<øâ¿øß1.ÿÖoýÖ׿þõ½½½ë9—/_~Îsžs=ùó?ÿó€Þshnnnnnnî¿Rjsss0ü”'™¦¹°°°±±ú›t|||íèŸOÑÚëV–:ç (…!Dj¥gY™aŠ[Íö`0È‹ÂuÝ…N·(Šq” ÃiGǃÁÂòª<‰J&%¶,¯â»0ÔPB¤lϬ6«¹`¼ÈMŒ(5¡|VèD8ʬž&ñ`¸€ Ëô\ä7¥á¦¥04 !€ ¤l‰(E3ž–2MâÉÑáŽÖ‚1¦•RZ1Æò,m´»ÕöRky#hw*ž› iޱ6úeª¥t›@(” ( @ežjŒ©ah)ç\+„çcd˜&%Øv<%A^ò@ù@ @©5#H ¬J.'”J!&Hb@ŠAg†.2ß÷ DE^ÄQD&5L˶ß÷1&GGGœs×uD”!8²jE–N&£,J¦ãÑÉá‘ïz¾çÍf³¶²²òüç?ÿÕ¯~õ“»ó•¯|e:Þwß}Qyž÷ýýñüÈþnoo¿îu¯û“?ù“ÿ÷çœßsÏ=o~ó›/]ºô?@†aøc·áõ¯ýl6»ë®»žœù©O}jeeåw÷wßúÖ·nooÿæoþæ¾ð…ŸäYæææææææ~¤ãããÛn»í§Ý™¦yîܹoûÛ?ü…íèèèyÏ{ÞÏNÀùÔ­½®áÕ †\ðñx2 ‡A×õ|ðà‘ƒ‡cÁ1òq/^Y]íF|ÿûãÑhw·ÚÙÙþ>ç½^¿×ôûýVšzçûè_Òž^¯«´ÜÞÞ9}êòžîuºÏ¸ø’v§“Æ) xÐévZ­VQKƒþÎÖfQÌ77χQÇɹsç666´ÒQ'q"„°Ö ‚RZk)åÞÞÞ™3§NŸzl:™ö{½n§C™ŒÇÛ[›ÚhJ™vÞZ3›M½ÞÒr_pî¬p§OŸÊó¹RŠ1Ea¤”bÆB(Œ£0(!yiä|>Ë‹yU—u]Š Hâ$IÓv§€¦Óéh2b‚1Á”Q„Ð8NÕ}k«ªº°æö©eY>Åæ>øà7Þ¸]×õ¿}à3ŸùL«ÕºñÆ?@g­­ªê#ùÈ­·Þúä?ÿß8ý/Æü¹Ï}îž{îY]]½é¦›Ê²¼°¶>øÁ~ï{ß»ñÆ­µpà 7¼úÕ¯~BóÿhÕ¨sîñ‡v†aøŸêï=÷ÜsÏ=÷;vì¥/}é»ßýî?ù“?yÖ³žõ£z×nµZ¯zÕ«>ûÙÏ^øúàB_n¿ýöÛo¿= ú®/½ôR!ÄC=´ø4°°°°°°ðã#¥üIewAü»Ó©¤”Aü´½PÿQ´0«¼n”DÆc‡<8pÖ£µÑ­¤Õ‹[½VÛ»³³=žŒ 儳( øJ5£vÛ48ÎXÀ…ÒJÍE!äEÈ QóÉl¸³[Œç‰4ÊH‰¦Eሇ´Ë³n°ºÚ?rQÄ¥ržPÕh⇌AZ³²V³s;gOTù¸Ù"aÆ!m@°Ö甘\Md^Ì÷¤žRq%Eý;†(fòÊ)0 ‚ˆ‘åÂx›@kíx‚‘¶ÚcÃ<ò@*éxÀ΃ñàŸãßøîÞvÛm/ùËŸÿüçÿÛsÿñÿñ…/|!BèÿwãŸyÌ_úÒ—êº~õ«_ýš×¼æ _øBUUn]|ñÅwß}÷~¹ŸsþÛæû} OèÔÞÞç¼Ýnï^uÕU?DOž<ùÑ~4MÓ;r!èt:¯|å+‡ÃáãWœ>E7ß|sEwß}÷ôÀþ÷oxêªúû¿ÿûŧ…………………Ÿ~å$Ÿå3À(CžpeµÕ¶²¥CÀƒ`i0è$­rž0qÖyoÁØ9ï½³Îz„sÊòcpŸùx>ÓöF“¬Õ^_ÍÖW¬¯¬¥I‚FØS‚1FeYÎ&cp†3Ê˲, B¡„ DA(Bˆ a¬©«ª®Jkt…Ö×~š¤`­#”B¼÷RI\a)›VÖ¡ išº®kð¨×ë­®®u»]ëç¬Ûë”EU”9"x6ïì6Að,k!„ȲìÀµ(Z«óçµÖˆP­e‘Ï£(¢”g#Æh’DÎe„RÇqÚŠ“4®eƒ²Î6J5uqîܹÍÍíý„¿•%Æ¥dÝÔÆè ä<ìeqöÜ™Ù|&µÄ!Ƙ˜Ï&Þ¹8;íŒ1 à„âRV¦V„мœ«)eAuº]Biž£ÑÞÞhøTsÎOúÓ_úÒ—î¼óÎ÷¿ÿýKKK¿ÿû¿¿¹¹ùø3?~hÏþóßóž÷üÞïýž”òÊ+¯Ü¯|øá‡÷—Ë¿ï}ïûÚ×¾ö‡ø‡ï{ßûvvv.¹ä’W¿úÕßüæ7¿úÕ¯þ¸c.Ëò‹_üâ[Þò–Ç¿ýíoB6ûªW½êþèΞ=ûó?ÿó¿ù›¿ùo›ÿÃ?üƒ”òøÀ§?ýicÌ·¿ýíý!Üûî»ÞñŽw¼ÿýï¿òÊ+ë·~ëñ­ž¼¿×_ýóž÷¼?û³?;uêÔ¡C‡^ùÊWÞÿýO8`}}ý“Ÿüä}÷Ý÷C䜿þë¿þàƒ~ë[ßzBýÚÚÚ/üÂ/Ü{ï½ÖÚ×¼æ5o~ó›ßýîwEqá—½ìeQ]}õÕðÒ—¾t8>üðÃO=½_XXXXXXXøñÉÇ3cM«ÓʲŽõ®¨ª²©´µˆ’(Œ’$mg±¾ª*­uEÆù²ªM]Ó `‚k­ÅÄsÆ6u£•rÚ4UÅ‚ìŒÖ§¨Î[¥2Ø@3¯\ŽBSá … ¶"ÉF×”Z‰âqž8'y益ÊG»M1åÈ2î 8é\ƒ¼" ,BÎ#ç½ç×È7„o\3$“í¥æâõVÜÂ\`¤Á6Nkë¼±†XK„ ¬q< Ò´m‘/”äA@W¦A„ð p³\M œbÊ´³º‘eQXÄ,Ó(oìþ$Xe­<à[窷ª_÷ IDATF6Ò ÚXkñ¿d\Ú{§¤Êg3BéŠ6­,½èèÑ^¯;™ŒO<òpÓ4AÔuÝ45†b‚(ßO°€’j^gÏoph¥¦³ ”Ä ¥ÔZ+Uƒ ý#G/-÷´Ö÷ç;{ã=c&> s*žÍ§E]Z8ñð çðÁGWW<`ŒqÊ(¥Þ:kuU™Ù|vöÌiŒamu‰sA-ëzo´Çƒ`™b.øþ7 "üd:žMÇœ‘µÕån»]U•jtÖjuºn·Û4MQ•Új.¸1:i%Î;NÎG·;Y»“‰P¤iÚé´¹`gšsRÕÎ[À€ 8[[[¥„Á¢(L“$ËJI†Ic„”’˜BÐ4¥Dð J€ Á¹’r8™©f‡I˜ÑDD[–e^Ì'ãÑ|>Íç3eT'd#Ë¢,Šª¬òy1kÉVE"àC]7£ÉHšfwoGi=™ Ái–uÚív–(YrY;õ`<öÖÚª®ÕÄQL«eUM›áîh^L…`O5çüò—¿ü»¿û»ïz×»ö×[žñ‰õõõýë}ìcðÁ~ðñKs~R8Úqœu²8‰ËªñQƵ·9Á¸1桇~ óBI ˜$YËXßXSÕµF (fœSJ=öÆ(­u]UÖ`µï%Ì|6¡prҺƸÆxåC'¢-!(H  (åí®¡wÌ;ì¼ã˜Œ±uØbä[-Ë´JBn-¯›¼Q•5 A@ÆÀZã!ì½o`ÈzeêÙxgs:Ú[]éDQs]Ì®j FI"B+R'É|:*ò*Lk¥À•µ–|Q×4ÆוĈrJ¥©¤ÒU]—,•©<ÆIÊ¢Ð(]EÙ”#Ì(1æa`ײ´JYc1B#¥”RŠrÖzg[q’¦ÉÊòò3Ÿyél>SZnoo;k¥”e]yç â(£I’dNU”Óñô8ùècûG}†AÐé´ ­õ¹³çdS¸0ä++KëÖ¾ÿà÷¢X¬®¯:py€Š¢ÚØÚîýËòÝ¥•åvÖ˲®5v¸3dˆ\]ë÷z³éhãü™ÝíÍímgì`0h·;TçΟ?}ö%„r¾²ºšµ3ïa4wv÷övêºäœ1ÖF`Ïœz¬ªt¦“ÕÕÕv»=›Í¤¬ÑÖ™ª©†ÃaY–„ 0&Z›FJcmò$<ØÝ½Ç{x2xë‚0ƒ „‚€sÎZ­V¯ÛfœŽG#Œð±cGyÀO=·¹»«tS3ëÌòÒJ–%i’ŒÏž9«´tÒŽ&€ªd¹7+%¥lвØçÓqФ•ö{]Bèt2-*¯´ÎÌ‹yQ„ÓV;9täÐh<ÚGçö§Iš†­¸Ói'Q‚3Úè !,Ö®y¾7>}&ŸçÆÙé|^UMÕÈ0ŒzKýÁRF£§¸­¤iz饗ÖuýÐCíOX}z`Œ/½ôÒýyvwwÿSmL1SJŸñŒg0ÆŽ?þ„‘Ƨb}}}iiéøñãÿîJÔ'ïïáÇ—––vvvœÉcì’K.Bœ8qâñ#œ OâÁ|*-//ÀwÞùK¿ôKœsÎ9¥ô›ßüæ‹_übJéþ”§Ù×¾öµŸû¹Ÿ{*•? ž$°;ï¼s2šp!Áa”µD0í̼˜7R:oËÉ4 ,Ë2†Jk ˆB;7+м.;ƒ~yÉ€mŒŒ˜`#D`daÜKILv¦ã8Š|YNžŸ<|Öo̺6ÌPÊH2•h× :Ê’K.KµIšK%b*L ¡ÚÓÚiq]W£áΙ‡óɆ5Sm&ÊL)06ì‘i¬”ª¶âœ¦F#çqã¼²vÍ nxÞ ÿÏ ›Ì6NÊÓÅ2ï œ0B)ãQÒjeÃíaž4à$Ó¹j€`©µ¿¿‡5NPÁ˜°Ö7R)m¼и¨m â~7ti7ØJk{øÄŠ"Ïó|<×uíÇ#Àýn·×ëSÂŒÒMÕìlí:«eÝ@Ýnwmu5 Jéd<™Í&ÎÙ8Ž×ÖV†{ã½Ñ°×ë>t8Iâ­Í­º®‚€ï wNŸ9UUõe—]~饗וÚÞÖ•\ê/]wÝÏ\_mêò‘G~pî쩺*BÖÖÚYF(‡ýàw{ƒÃGŽ –àa< wvëºì÷zQŒö†›ÎòTð¨×ï=zøØ±cιY1›LÇ;;Û;;[Þ{&x„UUMg3kݬìôº^¦µš„ÚÈ­­MçM»ÓÛ?9VK£&šÁWW×8cU™×•tÎÇ­e#›º©ƒ@´»)¥7žŽaýÞ ß(667fãY£d»ÛŽ¢H[Å9OÒ¤ÝN’”‚´Öà‘1SÜëwÁûy^Ìó©GÖ!ë1OFÓÙ„ ÒŽ3ˆY1ÔQÐÉ2N g”äŠãˆ0Z–åÞh¯ªKã5‚a§Œ;ïgùlVºxZXXXXXXXøïd6Ÿÿóý÷oïìcÚíìYW\yäð¡ŸxT?þÏ÷çÿzöµW^~ùÓ­óˆ`ÊÂØG0%€("!¡ŒQ£›¢,£gýå%Â…4Úª3–¤- PI鑳àö„#à‚{J+W‰çœcâ™KÂXGII p€¥1š ƒ Ý ³‹"ƒ‰¶ÿp•s#Þ€·#L)çAˆ*ê5ö€­ÇÖ!l=vA„b ÆûýÍ&1ÒÎä5CTk]•åx:c!G˜(©6ZKk%ªŠ0À‘•Ò™a̹PÎ aSÊ”T”„θÙ,ŸÍgeYaB[í6Bð¸.sYU†¢t¥÷„Š1"D–Ui+´¡˜PÆã8AÀ3¥œN¦˜´Z©ˆc5`g½±Ö @A((£l”Ѽõ®VͼÈ)¡F]kBˆ5š2Æ ä糩Ó!ïKãPä¼î gi+n$Ìó¼( @$M’ZJç|–µ³VV•õÙÓgf“\Kå«¥ ÷Fã½²š'iÌE+ gÄ:m-IÐít<€~c³–ªjšXë )£Kƒ>§$ŽÂ€óP0-ëºëŠËÿïç<'‚ñdòýãþÄsNïý‰G½î¹Ï9þЮ¸ì² çÆ==ÑZçc.(&a7RYo­±£@”RÊHÕR5Úíò[cX´…ðOò™õÎXc¼óØc‡â`D(Ô"„’8¦€dc¤iIÅ$å4¨ÁLpG"cð!@…:¯½ãL:ªkð!!ì=Ñ"B¹­1Rk©ŒÇSŠcL1!„Ò0Iú‚*k&»“ "$ɲ¤Ý¦Œï5öœ—ÒXåÀy„<ÆžQDp  c,ŽB0NÌX”YMr`žÐ¢°±U®ÇBñu!vH••ÌoŒ7)Қʂv ­·ÊYi­vû£Ÿ„L‘AÆYç=¥‘ÓÊuïÀ!Ù̇{Õ¼@qÞbJXrµUˆdö„RJBá2˜QÀç„kœE»Ûa@)a„0â!5H†»ýNÈ©¶šP†aEÞªu'޹ó Ó¦.+p–"2Áco5Ú4uÔÂìFa`‚µ6MÙÔy Ʀ""„”yî”G8gŒŠ€ñ嬬˼ò–`g\PJ±Œ2çÜdoŠ&„xä‘*U;k1JòÙl{{Çh›%m)5Ã6v´MÂ("B@é[G!qÈ;_ÍkçkBÚIÚ€°ó çõ¸6kkkÞxïœuÆY«¥ä4¸ä— ‡ã½Ñ!‹¼¡s!%"äq !¤nUk£0 Æ:ÎCï1 ÈZÇvºÆx2™6²áœGIÌnÊ9dVΆ»»ÃÝmk e,H£¬Ý Î[q’¤BpJ鿯nUÊݽÉlVDqDæœ:t ƒÝ½ád25F·’tÞé$q´4XÙ›ìåy¥µÛ?B“ÂÞj·-•Rl”D«Ö’4¡œò#GyçfÓél:ªËÑí¼ÈÏœ9}æôéíí¢(&ƒÁÊÚêú±cõûƒíÝím­kÕ ºÈ9þûØÜÚºöê«~Ú¢zøÄ×?óRx楗>|âÄ…œó鉶ÛYÂW•|øŸ¿دX®™…”5 ˜òZ$Q€Ñd6L:6b´2ÊÈÚy×é¶=‚¢®£öÇòXÄq6˜9TUUADÜÊ„P ¹¨&Ûì·#Ç¡&¶šNvçy­ž“K˜š.m›Ò:‰œWYS«ÑºÎ½)îBÂŒGû§YjD¢€ ò¸.kH; ÞQð,v0ÓE1<·9^;Ð=´Bqd41²ñÀHH±Æ0'È¢€„xƒœ±Ž3æ0@à½UÚh­ƒˆhGƒ0ÖÖRFX‰0šFl>Ýö¼iƻҵ³^§íC‘vZ¡*/f{£|>kŠ’jrÊ$qœ$Éh<šÏ¦i»ÅE@ óšFʺiòÚUšScF=ŽÃVØ“ºÔ²lX'^í¬0†ê¦œÔ¥·*ÏgŒº,k Ac…ZÚZ*ì˜÷{pÂä*o挱¦ÖÐàYÜ™›‚r’¥­,Š‘2¡X9BPBBÊb ¤–Ò‡¬0²™ÕSèPo}o<ÝÝÖu„¢äñ˜Qi­¼wI’$ääc'†4Œ8%˦"PÖ¬¬-Eq T®®ëBJ©tÍ:ˆJl¬®¤-Š&/rçLš¦½^·®«Y1Ùož:û¨|ooÏ9»~à@šµ¼÷ív«Ýna°J•"@GŽä<¨7÷Zi:›ÏWV–®¾êòååÁ|6yðøqÓ4³Y^Ls]ähUšGNœÙÞÜʲ4M;ZÛû¿ûJ)øòÊRY•RDPiUBˆv¶i¤¶¦¿ÔkΟqÕ|úƒãœ;} äy¹·7sž¤i7a§³|àÀáƒçy~öÌéÝ­n'ÓÎ÷f‹œóGïšk®i·Ûû×ßøÆ7/ÈÂÂÂÂÂÂÂÓF)ÅñOUHyžïÆ7Þp=zäÛÿüÏyQ¤Iò´E{úüYhêzg´—¶’¼.Çg'ó|²NËZÈëŠ(•Æ ¥lœeµóžbœcœ!ŒD8 #*E©s«#Ø{¯µÆ– Ê1 4àYÓ,­ô\-«ª¨f#°^Ç>ìvD”xÖRÞ‚•‘ºñÌÓaЉ%ª)GÎ(†=ç‘°‚å‘Úé Æ#k”ÇÎ!oÁ8‡¹Zæ“él:SK=lƒe)Áy L7Yì±óx‹¬±V9cÀ"cŒ1`Œ=k•·¨ÑÒÖ3ÄÒêuW®6@x§=©ÊJ)ˆ÷>Š#Ê(!$J# ŒmíªºiÊ*‰¢4Š\–¥aYkë¢ôÆ…",°Zë/«8Ó¤§apxýàêÊj1+}äô™³[ùhÚÊ’´ÝŒd[I MãÁAG±!AT6»ÒÔZJC)ÁTQc-Ñ!¥´U–bß” 9@QºíÞÑ#‡À»ª,¬Ò˜xOÁc¬jSä¥T Ï9gƒÁr¯Ó/òêýÏûΟ;{þüYU«å•e«ÌœÍ9çÞÛßþöŸù™ŸiµZNçÂr…ŸrŸüä';Î*ï¾ûî¿ü˿ܿ~ÉK^ò–·¼åèÑ£;;;÷ÜsÏ'?ùÉýÅëpÅW¼îu¯»îºëƒÁéÓ§?ó™ÏüñÿñâÏ`aaaaaá'‚s^•eš¦?=!=|⑦iîùÜÿx\͉ç<ûÙO[´›»œ k âˆÄa¯´¶Ø‡¡Àœ8L Œ‚ t¬µÊèJ6€P†U]1Ë1%„3µ[«µnt©Ç„i­¤”! À#­T£Œ¡Ûi7uMŒ¡Ê™L›ºÑZ{ç€Â#D ’$ƒk%÷FRKBI†q§IlK’°ÛiqN<†8Š„`FË LÝÔRª¢( [I (Å€¥²a˜$qBÏÆÓº)Fã]D]9Ï1 .‚vÒR•ë\ÚF>Žœ®1¬®­­YkËb>ÞÝ-«¢,Ko=#,ÑÚÒj»Ý&˜Ê²ÑÆA†©à˜a·}n{>­77†¶V‰Àdw(eÓŠx1› 1N:­ì’‹/GOŸ:··; A+¶Þ'¢ÕI:v' Îiš&ÎÛ2¯Ù™órRR ÈD©£«=9/g£8Ôm÷‹¢t wFZcÅ‚!+½³9,˲*Ë<Ÿkmã°²8oò@D‹œóG鍊n€7¿ùÍwÝu×ÿ)1[k1ŠÇŽ{îsŸûáx¿xã7þÕ_ýÕ׿þõ»îºëª«®úøÇ?¾´´ôž÷¼gÿî?øÁË.»ì/þâ/¶··¯¿þúÏþó×]wÝ-·Ü²øKXXXXXXxú­­®ž>söYW^ñÓòùGOžüÅ_xE’$û5yžÿå_ÿ͵×\C0~z¢­m#DÐô“4ñ”$pØŠÂ(°Î ‚ 8í,x@IÙ”M£¬®ê !ì½O’ÄhœõˆC`­URe!""B¬ŒÚ² Æ\®”ªëªðV)i#ÂÆ,¡Ê9­µØ_‚éqÚZÕà& 2^iU6å¬)æÖ*Ž€·Îzg=òà<¨Ã„­Š$‹À#D½'˜†Â(éö²nSTË:eX€(­‘Ç@œv–häB–PÏ1ÁiðÊi­µ³ƒ@Þyï¡, ¥uF€±sNicrE^mmÊ2ï ÁžeT]•¦*CF±6X¤¬©4 †±Qv>™–E‘¥i7k3άsŒ±(Ž)¥!c{»»;u#ËÚiSÔÍh8ì$-g!A¯Ó6ÆlmŸŒl®®­¬ ½Éd”Ä©·V+U×M5+bI'Ì¢°i¥Ä9mlÝÔ~}}ýê«®ºèâgPÂΜ=süøCUYUUå½odašDŒÒV’‚¦ÓÉîÎ0m¥TpŠ1g”RìÁ ÁÖ×WWW—#@`¬©ªÚ9k­&E“(KFQÀy(¢¦Q€X Bа‘Yߊv’2Î eZX¯ÈÆ©ùt–ŠÐ Wå^WR®­tÊÔóRɆcÖ ’åîR@Ç, ÂZç,€‡= ¤”ÏÆ'þ’ž±¾¼J‰˜ÍòG6O¸ÑŽwºžu²¥Á`muµŸ Å¬ÚØØíNE%—VkK«ËKK­V"8cŒBê¦Zé®åËåxg2ß›a‡²NŠ0®ªªR5ñìè¡‹ÝÕÍ­íí½Ý‰R¦uºýþòòr«•mœ?þôfÓÔ„0 "žÄa+I¯Û]äœ o|ã_üüç?ßív¿ùÍoîßùÎw>öØc/yÉKœs ¥¼í¶Ûþàþ Ïsx×»Þõío{ÿ|å+_ùßù;î¸c</^Ø………………§Ù5W_õÕ¿þLð‘Ç!&“éÇÿ·:uêô ß¿p@š¦ý^÷ôéÓ;öôDËc ñDôVR6RKFãL>/æe9‚‚mS)­=Œðþ áþ.5Þ8@€ F‚ ¥”2Æ8% 1&£4 E(¨sªÊg )惵¦©ªÒÐj"ë !ŒSo­²Oi IDATŠÇõYíT#+ç,A€0D´·Êg,F l×Þ ;ä­÷!†Q¨OD«Ó[]ëôz˜@-+1£ ;æ½'„"Ö žqÂ8óœXì«‹¦²µöÞzk0¡!ÀX0†1[ï‚82”`!,B˜3Ìã 3J õÞóX[P”c„ÇZÛºÎë¢  Âaqc„!NY†Néñp4î5eEšºÙÞØ2¥ ‚H_W`y_E1Ï›ª1Ê"Ó°E ®«J×z2ŸÓÙlw„#„VÝ Šw‡{”Ò¬ÕŠ¢ÐY3™ç£Ñ^SWZ+ÎY+keíl°4 zJ5R)ÎV¬J)½µÎZkM D¯×‹“8MJiÝÔý½Íͺ©(gL0„㼵Ɩz}y@æój4žbDƒ  Œp‘…¡ÐV2N1΃w(æ­é0xwÐí†!š†IÄåQ;i3L=xÆyQä`Á9Ç÷¹Ï½ýöÛ¯¹æ„Ð#<ò¡}èOÿôOÿóÓ4}Ñ‹^4™Lî½÷Þî}¹ßï¿â¯¸ýöÛ/Ìž½êª«¾øÅ/>!«¼þúë÷gÞ~ë[ßz|ó{ï½÷å/ùÚÚÚ"ç\XXXXXxúµÒô%/þ¹ûîÿÎw¿÷€µ¶Ón_yÅOrÌó¡‡píÕ×<¡òÒg\òݸèر§'ZñÚ4»£! 9¥Ô:ë‘£÷¹k¯½vÿîW\ñõ¯ýÛßþöë_ÿúååå;î¸ã²Ë.{Á ^°Ÿ–Ï+«_z)¦Ô7™Mÿ?öî<ÖÖ«.ÿš×zÆ=ï3Þ{{o'+eª"T*¡äý%"‘Ôj±˜@üD(† e*ŠU#"išÁ”‚¢DJ_A¡÷v w8÷Ü3ïñ™×üû㘛û)ÑìÏ_ϳžg³Ö>'ÏÞß½Öú®3gÎL§S£\·ÝB 'GÖŽ¤QÈ ¶Öxg¼5Ö˜¢nZIÔëtó¢ÜÜØðH¥ƒþõ?~Ñ#GÖ¬wº]B‰³Î;ïó²0X‰B ×ꦄÞsÎ¥”(ŽQclÓ@Ë˃~÷‡¯¹ºÑŠRÊ·ÞÍæ‚(‰U^j½—eùêÒê‰ã'Ò$Áñ€y«æóy]×AbL«ªéwÕ‰fkkû'¿ž—£Ô[Ðn·„ÎÛª*g³éxÊ1÷Ø{LcÃe&=€ D p;j¥Iì <Ø5M"Œ‚ËŽ!Cè´–uSÍf3)ÕtR ÌeIÊÖ£l–g³ÂXƒ BΙN'uUà½w`*hÈC qS5MÙ”U©´–R•V óÕáºÀ“ñþ{2 gÖÚN§st=±ÆRJ’$N[i%’löÿæ"„¼öµ¯ýÔ§>àœ¿÷½ï]]]ÝÞÞ¼úÕ¯6ÆüÔOýÔátÊ,Ë>ô¡=ëYϺ8˜öu¿cÌùÁ~ððøyÏ{ÞÓŸþô¿øÅ£Ñè°ä¶ÛnSJ=ç9Ïɲ pï½÷ž;wîñ/ Sý~ÿGôG³?üÃ?<,üŽm~ wÝu×wÜÑëõÆã1àæ›ovÎ}øÃ>¼ú±}ìž{î¹xóx<¾û½öÚûï¿ÿ?ùL|ìþ>ùÉOîv»oxþüå/þú¯ÿú¿â¹ü’—¼ä3ŸùÌùóç/–<üðÃ?ò#?rñô†n|kÎ!ÀSŸúÔ[o½õ-oyKUU‹·ü…………………ó¢8²Öi·ÚÓÙÌX›…užÒJ)ÛïõœEbç¬VÆ<ôÐ+e"F(¥ò1! ¥ª=„±¬,”m‚˜¤-ž¦)1v:ÛöòÑh€ã$ AcT¥€±Ö)j\5º$ Jí¤R0Î"à†Æi@YM]Kj€8€`猵Ö9ÅÐYç‘DÆÅ…¬;L/;Ö[9 !®ŠBXÉ(òV+Ý0ÂÎZUKU×B@ÀÈCh<ÐÖj£uBQDµªµ¶Î 4¶*/ˆ‚ËœÕÖUU¥­GŒ@„€£ã<ˬ¬±²Œ/„᪕¶Ü „2–ÝA¿_¥Ö*Œ"Î9!!èœ[ [q²4ÄA¨i”¼êò+6ÎmL&…i§[+éªe*øÎÎ.¨×ï÷ûýV’#Ñï´»íP €Ÿì~è¡ñô[éÑ£—íîîóÝ^ï)×]÷ôŸøñ(Œ"c¥ÕöÖ£¬×mó ã!€ë<À9ˆô( œ2Z盺Ɋƒ4‰ £u™íDpQUÎyUÕuÝTe=›L·v¶ó¼ÌŠÂ{[Õ¥÷B ´DDal­ŸÏ²(J‚ ÚßßßØØ˜eóýýƒ“'N¥Œ „¼÷Þû­­½½ÝÍcÇŽ¯¬¬HiÆÆ¸,ÏT]a1yžÕuA¿ßmµSãTÓÔÆ(ï­‡€2Þéö/lm7ÒÔ®J©µ £TÁ9÷ÞQ‚;íV»“Zç¸àÚhgÄdkkSkMí´;Q¥ÖˆÐ"/”VŒ²N«G1%lw{gscƒRÖnuâ0¦µÎBÀVÛ½íݲÊ(õ^Ïyq ßÃ? XYY9Œ¯¿þú{ï½÷0x|üã¿Xøë „œóÃcçÜÅQÊK]yå•wÝu×ýÑÝyç ŸûÜç~îsŸ[]]]]]=,ÙØØxÊS=CãÏþìϾõg>ž6;ù—ùð/xÁ çý¾èE/úä'?y1öÞ§iúüç?ÿرcI’ ÀÒÒÒ>æ|ìþž?Þ9÷›¿ù›¿û»¿û/ÿò/‡ãrêÔ©N§siB ÿg>ó™×\sÍm·Ýviá»ßýî~ðƒï|ç;?ò‘\{íµ/{ÙËêº>̦ý¨Èÿ#ùÈ?þã?^L/´°°°°°°°ðßN)u0:hjé=@ì m÷÷Œ´M%£ J­Õ0Œ¥5Æï=!†¡6Æ¥wŽ ,‚@{çµÖ!Œ)f1FXÅåDêfœ5+¢M…8èÇ^)]P7FQ­@Ä#¬ƒ„ò$eÐÊb·ž—…ÖKg ³ÆAd,’Æ+­§B‚ic4Å)©qÇIÒ;²~üêþpÅY—Ï&78g$>Œ"N©6ÎZ')€Ðg¼ÓÞyï @”Bð`6É‚ ªÊ@L¹€ˆHÛ(í G„QÀ9¤ Qæ¬a €‡Þ#ˆ8ÃÆš€rø À¦¨¹†C‘F nyлìèQg-D(BAGI)©"„A@6Ry^å@mœEgGÓ‘ƒÀj‡1 £ 1O•Òaœv»ŒqÁ˜ ”Zç ´"`I&iÂ-Šœ’j<•e')£tsssåìùË/¿œ%¨”>¿¹ ¼ÏŠA…A„¬kãmSUZkg¬‘Ê(e´VD:g«ºvÞFʺªšÆ9g½ËŠ!ä-‹ xE‘Tꑳ§Ïlœ%ÇQ8 ’4Ñuµ¿» £PpÁ®­ÊŠL0†JW×Ö;Ý.¦8›Ïvvw›º&Œ3aÚë×ÛÝ9R&i¸´´š&qš$ZÉ­í {{;²©#˜ Y-+eTGÝn¯ÕîŠ þÆÉo^ØÚñ1Ì•Q^¼|°4xÂ~ø‡®¾Òh鼕McŒÎ‹üÞ{?»½½¥´VÆD2λ{ûÓÙŒQ6èÚív§ÕZ]Z¾ã“'OÎòC4Ÿ…”à$I––––†Kq+e´ÐËÿ'æ”R6Msx|´PJO»Ýî?ýÓ?]¼s6›i­{½Þã© xúÓŸþ…/|áðøôéÓW\qÅ£žqß}÷Ý_ûÚ×~ý×ýb!Ƹßï?ÿùÏÞóžwé͇1Þ¥Î;÷­Ï—ïØæÇpppð÷ÿ÷·ÜrËŸþéŸ=zôúë¯ÿ¹Ÿû¹K»óÉO~r:~á _ȲìpYü¥ýýî|Çþž={öÅ/~ñoÿöoþóŸ×Zö³Ÿ}Å+^ñàƒ^z³sîñ¬Yýv^úÒ—Îçó»ï¾ûÒÂ}èCGýµ_ûµW¿úÕgÏžýå_þåüãú-q⟨ªê¦›nú®#Þ……………………ï9 Ö6/JÎøîÎD(Š’€’|VÌæ³4MÚã T°lïÞëˆÃ{ç.ºŽÔzè­o') ØhK EÈ4JyŠ0E\0„Ñb4U8dH0ôÚ Për6޳YÜ;B£"^æ®®5ŒsJ ÀuWŽÕ­ç"ŸñºÌ€SÖ*¥k °ØÆ½Ç8Ÿ:Ô†<á­ÁꉾæIOº¼(·šlž›ùXF g "„0Œx`­y<ðÞ;ç-ñá+4Úm4ç¡6`åa\:ƒeQÄ „’’ ‚RRbà1@Â9PÚ;¦”¢$îõzœ ^'®®\@ÑáÌbkæy¡¤šŒ§À9Ý4Zé¦,‹ªRMãœsV+«=‚s#%@(ˆB¹»÷Íožf"€„gD‚¶¦qVçY®´lšf6ÝØÝÝ)ª:/Š¢(‚;»{Gkw»A"„Ξ;ëxäìi!xGQVU©µŠ‚xP×U]VZÊÉh\å§Œ ®”ÚÛ?`‚GI4\^±ºi¬5ÓéT*«ö¦vcÔx4Þ–Oþ‘ëËKóÉäü¹ÍùlæœcŒ&T)e¡ÃŒ„ŒQ´väÈÓüÇûËC£õ™ÓgfY1eS&‚¤ÝâØ81æA0XZ^]Y†qFûƒååª.&ã½ñx?Ïg²‘C€‘ñÀ!d<|äÌÙGΧQœ£¸Ûïu»}Àd2žf“( ˜ «GW£X­µÖz<=ðð'¼?›çR+cL6òÜÆ9„`¯ÛGb„Ú­VU–ÀÙ$ #!â8d'aA€‹Â`0ˆ ÞÉÇ›·¶ªª‹kAPJ˲|œÕO:uã7×uý­7|ðƒLÓôÆo¼4\±ÖVUõîw¿ûu¯{Ýwüúê{Þæ»îºëÎ;ï\YY¹å–[ʲ¼4ŸÐ;ßùίýë7Þxãa¦¢g?ûÙ7ß|󣪻U£Î¹K7í ‚à?Ôß;ï¼óÎ;ïtñ냋}¹í¶Ûn»í¶ 꺾úê«9ç“8çýèGûýþ 7ÜðŸ‰x¾çÂŒR‚©Ö¶*gŒr« }„„0‚HUVa(Â$bŒ7Æ`H”ÑÖX£ ÁÄ;n¥mã­´Æz B„z)" 3½÷†sÁ©"‚÷yQR À!NˆÀ ‘µ,f¦œSrÂ+ ©1pg! "î- NÃ0D˜C4VumëXŽ®v¶t¾Á Ȉï‡É0\Y91\]G´¶«\#æ2ˆ0¼s!h­³Öïwþ[B$¡÷À{0†ž@8'Úz¡Äi£*@B†˜Rl-¦ Bœƒ ŒVY×N*S+¥TÝÔÓ0 !AÒ“l.¸´ÖxçêºÊæYžçÖ`}EÈ;`‚P5r4™Æ‚X묞³°(+k\YWUSoïî=Ø4U ‚@pÁI(HSåÞY¼2ZÂ9Ðî´¥¦ÓÉ<Ë !ç7Ož:·ZÝn¯ÝnK­(¥JË4MVWV!ç¢$mA0ÆCe>ËÄÖ:Ù¨ºi꺱ˆ ê÷–~èšk:Ýn#e-ëÑh´»·=˲ðÞF=Ji‡`Úí;q¹\^]ZZF£ñÁ|>“F¯¥•Œ R (±hï<‚ˆQ¨ À¨Ñê`2©u˜šHD!áÜ#¤½w¥Ývw¢4`»¾Þ¯µµeÝde]4ŠÒÑC?2Ë‹ÞÒÒÒòJš¤aÅ­x0§ÙDnÔÉ7â¸.//1F¤lÊ¢<88˜f³Ñt<›Î¤QeS2J1&XÊ‚ Â(dœE~~ãlYæKÃ~ÇŒ±(JƒÂ8ËfY6Ïòì²ãÇ£(pæqÇœßøÆ7žö´§!„“—^ýõ‡…³z–eŸýìg¿ÝÕßøßxÞóžwà 7|kê×/|á ÏyÎs „ß1ñÏ÷¼Í÷ÜsO]×7ß|ó‹^ô¢»ï¾ûÒŠW\qÅ>ðÀó0æüÖê‡} êÔh4bŒµÛíÃØìIOzÒwÑß3gμç=ïI’ä-oy ÆøbKNç/xÁÁÁÁ¥+N§[o½5 Ã|àßî†Ãï ~åW~¥ªªø‡8,$„üÅ_üÅ5×\ó?ñgïÂÂÂÂÂÂÂÂ÷F!Œ1’²a”Fad´&•¨¬®÷;ý¬œD„( )gEUÕMcŒõÞ{ç•”“4I‚YUŽç3,x»ß 'aà i’p<Òh $8Ë L}ÄJƒ€ÑÄ#%!hò|´C,rAÏ„ Aˆ,"0HcìmKBÆ;e–ƒl†T¥½&ó&ð^#o1ˆ¤ag-IÖÖâNW; šš:BŽ„M#u­½œ{ë¦)‹*NºÆØZkíÇ~l}}½(‹í­­Ñda챃lïmMîïw®yµZi6ŸìO§Ó­@ x^ES2Æú½ápeÉG(æ‚Îm<²¹¹ÁYYYj·Û@„ cZOêÝݽÍí-¥U»ÝòÞ<Þ˜óýïÿ=÷Üsûí·¿ýío‡¿ÿû¿¿½½ý‰O|â?ÿ¸á†Þüæ7ÿÞïýž”òÚk¯=,|衇¥¾ímoûÔ§>õÞ÷¾÷mo{ÛÞÞÞUW]uóÍ7ßwß}û·û_Ýæ²,?úѾêU¯:vìØë_ÿúGE³/|á ÿüÏÿüüùó?ýÓ?ý²—½ì[«îsŸ“R¾ãïxÿûßoŒùò—¿|8„û•¯|ð[¿õ[oûÛ¯½öÚ—¿üå—Özìþ>ëYÏzæ3ŸùWõWgÏž=zôè ^ð‚¯~õ«—œ€µµµ÷½ï}_ùÊW¾‹˜ó%/yÉ©S§µ÷ `uuõg~ægî½÷^kí‹^ô¢W¾ò•ozӛТ8¼úž÷¼ç¦›nzãßxÝu×]wÝu‡…÷ÝwßÞÞÞâMnaaaaaaá¿` x?›Î\Da` ˜©ùÁÞž,ëN¯³vdí²Ç0#vvf»Û„°n§§É²l:ž!ˆx €G„2@°ÖV)ãÑ> h ½5²Îg󊸪©ÂT’UÉÆZ¬”w{Œ=aa]ºrêxLXñÑ8 -hˆÆÎ ½‹Ã^«3ìË2+¦ãq-«Zçy=Ѿ¦ !è‹ IÃöR8òA—'´¨&À¸|D›"†.‚B PÆ­€B& µò‡óñÔ¦n”1!$D D(¥ÒXˆ¤wµ1±cqEI«%‚@Î{g B«´Æí´ªŠl<Ï&YžRÙ Œ£”b6#Zʲ,saJ£„3¶?Q„VxAYSÕàßF]½Öªi*ˆÆÔ{औ'Ití¯™Íæù|nŒLâÈY]™– g„Žec‚¡æ‚9ç!y‘Ofó>¡A <€Á¼ÌfùcE‘‚2*8ϳ,MSm­l0 Ã8ˆdU{€â8…ÎgÙ|–ŒÇN'v~ww ûçÔ„ë4D¼º¶Þê´œw[Û66ÏMf“´Ý£„R†1öÞKU7FóH(¯<öES"e!ESŸß¾ ”䜇a …Ñt6k´*«j–e“Ùa4šŒ”1ˆ0Dpyy #Ohµ¢8Ö( „xï`\U·?H[•åõþÒÒÊêj§×Èó€è¥l‚ˆ÷¬˜>röáñloZŒûƒ¾ldžgÆñõÇfÓéx4®«Úxï1,šŠ"2™OŠ2Ãìì:gûëGâ8„ЗU¹»»kŒ[^YåAØé¶k©NŸ;³µ½ÇÁã9?ö±½á oxãßx¸ÞòÌ™37ÝtÓ¿;Kö?êÚk¯E½öµ¯µ6 IDAT}ík_{±ðøñã‡K4?ó™ÏÜrË-wÜqÇK_úÒÃK÷ßÿ㌦þóm¾ë®»n½õÖýýýOúÓ—–¿â¯¸çž{'—nnn¾îu¯{ÿûßÿ¨º.\ø…_ø…·¾õ­¿ôK¿! ‡)ˆþõ_ÿõÿø_óš×¼æ5¯ÙÚÚºýöÛßõ®w]¬õØýuÎýê¯þê[ßúÖÃÓ¯}ík·Þzë÷êqüÔ§>õºë®;Ü€ôQ(¥oyË['*7MóŽw¼ãÒ$C‡›ÄüÎïüÎ¥UžûÜçþÝßýÝâMnaaaaaá»Æ9—R¦±ù>kšæböÇG5©i!ÄÔ õíZ{Ñh<ÂB9gÒ¨‚V;e‡s8µUJUU•ey”ÒÃŒAHk.D¿ß£¸.Ka]”MÓŠ!#í$…Œ@Œ‰G BHiŠÙtÎ8â"\Z]Ãjö*1¤€³Nke,°ž`O‰m¨k©½* µ2¦Ñµ±1®b˜˜-µ±×¾žW#e+L€ó&mõ I±ˆPáN€iA!pC¨âH‡ÞPç&be¬Õša”Ä­é|¦-0 !Æz&câ¼Ë‹¼’Ò )SÀç²Éé áÄ%A?Œ"„IÝT‡)gÑáá–"ÅQdem(ÖU™3*1΋†rF(AgµÚ˜ªªt#!Œ±8 ÛiËxß4 pÖs§•‚RBøa† FB„ˆ³€Ç1ç"Ž¢3uU•%ç´ÝNÓ( «³ƒq–ÍU#;îîÞ>€h<gÊ(h0"¨´¶Ö¶Z-BÈáNžÂéd²¼¼\JiŒ! Ê&MU£0´ÆFQÔív¾ò•/gÙliupÖ(•´Z„R“Ω‡Î:圶΂Òv§‚p:Ÿ?øðý^/ŽctUÖªv; ã ÓkolîLÇóF!xÓ4JK„a)!d2›–e ¢”8ï<ð¸¬ÌÖá”J­‹2ã‚´ÂÐXµ½3ÞÙÚÙÙÚFZ­ühV×¶ÛïæEñðÃNfý(ƒa8¿³½mMZÉ`©7™æùüÁo>\V–WÃA‚‹ÍÉtº³·‡ìQzƒÕ啃½ý³gNçóy@ÙòÊr«Ó"Çq4ö˦>¿qÁîl_vâĉ+.çBœ=·195ÛÜÚ„ãñøq¦Õ$IrõÕW×uýÀNXýþ@]}õÕannnîïïÿ‡êþµ™rå•WRJOž<ù¨‘ÆÇcmmm8ž:,,,,,,|ß\vÙe›››_úÒ—}ßpÎWVVNœ8ñ­—Nœ8qúôéþçþw7lûoñ­½(í&¬aRjãTÙdµª¤®K™Íò)§5$0ࢪ+ãœÔªÕi[à!„!kLÓ4Æ!‚ÐX«”"J DÞÛº¨mÕ0êE‡AH!kl!ˆ2à×8ðÖc÷¶ÉmzZÌ0d`@¤y€B!± g„S̉ȉ#a"Œô³(v9Y$јÕ2Ãz·©§©5aŒ1ÄÌ‚)Ô9£¥!¢ÆûFËJJm ¡4¸÷¾‘Ò: ÕÀi洛@Q„"M¢nÛX¹Ô:/ª(Ь±uQ ­°#¨d]ÌçãÉh´?›ÏœG\„çBˆâc”EaH0Öj©êº®Š²)+Á€3ÎsÚ*¥j[Y­½2H[Ni `Ó4LˆÖæÂÆy)›ºÌË|î´N£˜BÜTe„qÔ ‚c¸²2È‹|<LÆ#€ÀC`­ñaØév–––¤”“ɤ®*«VªjêÁê`°4 ”x 1Æ‚€‡"À2އKýN·Çƒ€G‘ˆBcÔÎî¡DÎH/l'I@´nô;ƒ~]Ö‘ùtÖÔÍl6ïõºýa§Ýí3A³¢®›Rm¬‘JQƃPH)•RÎÙ ài—E¦”$"PÔ£"¯2åd]Ôùš…!„qYVgÏžr!’4VeE0æ\ÊŠªlªÆ@IŒ!f˜ çœ6ÀaƦÈ;ç!¤"H;]4SPUÐ[è¼÷z‹´ºñ²Ôõ¼ñ˜“€”0Nv52ÊÔÐ;„ aCá+µ2H Æ€²Ê;¼FÖQ¹%B£²† ÐÕHJƒÂ4À ĬtÐ{ŒÖ6JQ†´3’JKÃŒqê°ÀzÙÔR×Ì£¨µݨÓ*¥l¬AÖ2F9gjM0Þ­$Îxg¥lŒÕC 1Dah¬aˆDa=\„AÀ)!i©&£ñì`¬•„Iš$qÇi’RDª²ÔFïµT¥uŠâº(jÙ@ %ÆZU—ÎÚVªº*ólóÜ9«t'Ëýå8N¼÷Œáå•^Z§Au5Ï k}…1­µóžÒjµ–––´Ö馮µ’ZicÌl>‹’ Š" a<äy #3ŒÓ( ZÝÎòÚzÒN³²|ࡇ€ôÀÅM4!8ŽE°XÖUÇí4Å„#È˺žŽ'Z+mjëš,íí_ØÙÙ+ËÂ;<@Ycòl>›ŽË<[__5FqÆ ðÞY„‚B—&!KaÈÇÓÉx:öÞâ´lòl¼¸(êÊßi·Û­~Õ¨½ý}«LÒmµ{q”Š¢šom]Y¬ŸOgeSɺY]Y]__/êzkg»iJ­Ìl–—yµ¼´š&­ápE+C)kõÐÃß¼paswo?Œ“åá cY—ÞÃó›[»;ûI’¬¯Y?rds{çÔž<õÀ¹Í­¼,Òvg¸¼²ˆ9þ7+Ê\iíœsäy-ëVÚvÆ×R`öÇûq”¶Û]cÜÞîžõ^„¡R&Nb.‚(1ÆR+㜪\Ó¨ï>myH¤Ì­‡JªÃ\OF+rt°¿¿»³¿·Ój%«Ë«”`… VÍt2ÞÝÞJ’¤ßë´Z Ä`´;8Û`è±÷Ii·f;ZÚ8Ž××Ö›F«Fuî­‹D°¶¼¤LÛH¹yfs>žQÎ0Á˜³¥ÁR88˜N¦³¹Ö–`gój<šÊƬ®¬uZ]B˜Qæà`´³³;¥«+Ëkk«$5Rf³Ù¹sçdÓ¬¯®q.VÖŽ úCÊÎnœ9kìViùŠ+W¢8YÄœ ÿ›åYæ!d‚i%µãéÞþþ%¼Óêô;Ë£ƒ‰Nj™s.Äp8Ax0™ìîìtUoýÈ:B¨–4X^êx7/‹Ñt¢´výÞ ípÊ´odÑxæ…<Œr!$âØ"k° 0bˆcá…±Z;—5²©1â1‹‰«‘šJ!ôŒFˆE”·À@™IÕÔÎHA$(ãÖ“J奩”ÇR«sF,t•,æ ž‚b¹zÐmwâØŒòƒñåUa B ½.Ë2!"XŽ0ök¼ó„ÒF©éhÏcb%‚±$N:IÜŠ1#QÚëF„PÆ! 1ÄÞ9ÝÔ²©³¹7Fi…e"„gy弪ªŠÈ Æ4fWe%+c„£1qÇqD9÷Ð+-­5¡àí´Õët³³ñXk ¼ïõzÆèýý½,ËŽ;Öï÷ʲdkÏœ>·³}Úm·‡ÃåN§Óét9÷ˆÎðÀYW7q> Ã@JYQ–÷Ÿ¼¿È³ÿóþ¿ãǯ¯­ííîîîíBhûƒ®2j4ÚG¶ÓÔÅ-XyݘF‰)qX5å¹³ˆ¢#G>é ?¼»³»»µUWESÛéÌͲñ±ãÇ‚(+£‹2×ÖDœuû{ûû;Ú”Ý^Úé´:½~·Ã ¨ $Ω$J[G×CAfÓ±jÊš"Y„¡PJ5”ò¦iœ¶qžÚÚÙ¿°|uy¹×éy £G_[],u‹¢{|VM²r>ÏÄ@wƒ0l¥“Ù©ñxŠ éô»½a?A!â¯êz6Ë¢(^YYFˆÔu ƒ€3^UµÑZIÅo·ZQ9í8eƒnwi0ˆ¢hkóÂîÞîésg—WÖ…ã¸Õn÷²¼ÆŒ!ßh} f^HAqN‰ÐÚïŽ0¥z«Œ´VcŒÃŒÖ‚”:ƒ!BC'Ž2¸ºº%!¡8›Íg‚1Òj)­öLÏcB¦Y–e9 8nµ¤VQµZ-‚Èd4©ËúÀ6ó|Ü4¥Î97O¥q"еuA”VŒqB±÷BÒN[½V«Ûî;ï¼u”SB9ÅØï½…ÀrF–ýáp8M67/Ôՙϋ¬ª«ýƒ‘"í¤•.w';3 u«›ŒÇÓƒñÁx<γ<ŸçëGŽ®¯étÚÚ™Ñl:žwG#&h…"jÙpo½wΚ4‰½þøààl™ï\Ø9²vLÖét{½N§ÝF(ŒŒQøV+I’xóÂÖÞÞÖÊ{„ œ!§ãÑp¸çü/ðú׿þÏxFš¦NBø?¢Íï{ßû:Σ ?ðüÍßüÍáñOþäO¾êU¯:~üøÞÞÞwÞù¾÷½Ï{xéÙÏ~öÏÿüÏ_{íµ­VëüùówÞyç]wÝuñꯀ‡4 aÌŠ:/ªÐîtd^Á¦’ÖÚ¦)ÀYN©7æ`g×JÕêô¸Öû*ŸLÆcˆ`ÏXˆˆ â!¾, -u#•ƒ ˆ8ãÆig¼'c’¶ÒþÒ*+ǹ/tBl½÷Ј(Â;]Ïj=‡ME”±°ˆYH€ŒÞ# !%DÊÚ9ÏÅÈÓP]1ä°k˜®‰-ˆ«UÜA}À8v¦©JcÆÔÉ y€G¥<ðÀ[ë”Öj±±^[o½ö”xJe,"M°Bç<´VI¥¤E˜Bç­R²ªT]×Vg1ç=eÌ{hŒ1ÆY§µ6œ9ð^J©êYØNÓN«íµÍg³¦®9çcÁy†Ðë|š&ÕȪª"i»ÅƒE@bäfœ1FEƪáp(ŠBˆÈ{\7rwg§ÈÃV§%I08züØæÎv©Âh­$€RŠ¢œ5JíîN[iÇQ^ÌsÙôºÝ~¯×(uasKkí­Chºµµ}æô£ F„0Ê…hd³³½=ŸgóÙ¸¬3ë€ €ˆ ŸgÒXãÜá®Bq®,/aè¡sí´•Æñ ßÂ`œÍFó©õNCx˜*™Rê¬ÓJ÷º½v«#D`Œƒhsžûûq’"B²ùÜY;èõV——ª¦.«ä½—Jyfó¹ñ®¨ê8Š)åÝ^w2ͳ8P×óîÈÑõõµUÆÙx6uN§­ÓJ9H >Ž#”D¢ét2¥øétR•9€nžM1QÄH´mLg­#¬”šÏ§Öªv'v‚ÐJ«­­8‹˜ó{ï–[n¼ò•¯¼ãŽ;þ§´ÙZkŒ¹xzâĉ§=íiïz×»Oo¼ñÆO|âŸþô§ï¸ãŽ'=éIò'2ßüæ7^½é¦›®¸âŠÏþó“Éäºë®»óÎ;ŸñŒg¼üå/_ü',,,,,,,ü€À1Ì$Þx qF!­öŒIQU7l0„èQ]”ck­±qÚBœ/÷ûÎúƒ=gÝÚÚj§ÝÒB©L­²ª†a¨¤ÐZ¯½·–b)U#rVjgs èðC 1âÐ;ß ç½B s¨õØjB!Èx€!¥8«pxŒ€'Þ`—s­l“WS¬2{lµóÖL AP{h=´i£›¦"ÔC!a" fYãPÖZŒ¥·,¸£” k¬ÕUm€G””Uƒ Eè)Æ`ˆ’0¢xë¤ÖF›Ã¼ÊÊhï<„й’Ú#«BkI ŠXDqÇuQ­›ºæŒ…QD ¸ƒy ˆWe5:8ȲB)A+mi¥¼óxÆEœ$Ö*,€Rš$I¯ß#œÅq‹`‘åx<–ZU9™O‚8ÄGiÌîô8瀵B)ÄX[s0™ˆ(„¥­vUU;;ÛÅ`ŒPÖ[)!­A”yîA‚CD9¥ ±!÷¡3M]–e.¥0NWUU”5¡”†0Ί"×…²ÌSNÉþåå^«Ç=ÏZk%„0BÒB!Bày<ôx¿Ó1B ¥ÔµBJ„eÌ(c­PÆ ²Zkë%ˆû~§×Ý]"(Ž;ín×üÓke]Z?•æ¹2&+Rël-„çsBDBˆ  B+!wFcæû箬,-.íln·w|î÷z½sùÉOnooÇãÏ|æ3çœsÎÙÍÏ9çœ;î¸ã’K.yÇ;Þqâĉ¿û»¿;³Õcôù1t:¯~õ«/zыή¼þúëß÷¾÷í‚ç<ç9»Å³NÀý÷ß1Ž¢hþ 7777777÷³ ËóÉx<µÔí¤Ói÷ÄeUVMi •ZBàF9ÁF5¢*0pN©t<Þ^ßmo7Ey`ÏžåÁbGï{à‡ß»çáû7‡­¸µ²eÐ D´2¾µ’n&¥­ç‡I«Ó_\ì,,$ýnØkûí…Äy1È={ ˆ"3“í¨tݤ›LŽa¹EÄÈ3"†¶ÞôqêÓÌ™£¶=’F8‹Q‘2¦u‹©–Ž= ¡ÑN)tQÔY^6ÂD=zA©'µ­¤ª„Ìê:­ª¬©s)$á »tÎÊÞCçî=tÞÞCçî=÷Ü¥úËËÝÅÅNÐîtÚí6t É‹l4mloon®Ÿ>½vòäú©Ó;Ã)%„cÌ9ït:ËË{öîÝ»´gO·ßK’„{ÜPU]5¢j¬6eív»Õj Q ÑXg=Æ‚ ÐÆŒ'c­ÍââÒò¾½ºÕã««'7BaD!ÂØ:+µ¤ŒQ„D„!DšeÂåå½?ùÈž½ËI;qÀgã¬È‚(ܳoxíN«×ï-,.ìÙ»ìád6Mó¬(ËÑdº¾¾9Ž(&¾Ç‹¼Ø8½‘M³=K{:ívžÃÑ2vø¢ û‹ ÚšR4Z/âI¯Ý_^ì-.ì;p`åÀJ§Ûmqô£÷Ý{ïÎÎpßsß½÷œ>}Z ás¯ÝJúýÞ`Ð×Z­®ÛÚÚ¬Š2fEVJ©Š¢Êó2ÏòáýG>øàÑ|ð䩵4Ï AÀÃЧ5¢Î‹4Ͳӧ6¶·‡ÀÂN»7,tÚVÒ ºÝBx<™ž\;U7M»Ýñ<¯išº®­³e]X[ÝÞÞ w{JðéÓk[[„ ÁB¿Ói!à„¨´AÑ8[í˜Ôíµ£V•³“§Ÿ<}b}óôÃÇzxuõþ<±vB[µ¸¼Ðé·™‡ý€.,uWÎÝ»eÐm˜ÿóžóÀ—_~ùÇ>ö±¿þë¿nšæÚk¯½å–[žþô§ïž}Ò“žôå/ù;ßùΫ_ýêÅÅÅk¯½ö¢‹.zîsŸ»›–ó™Oì¹üŠW¼‚rÓM7©¡”*¥Î…€ /¼ðÌlÏ3Î;ï¼ßú­ßºûî»766æŸpsssssss? (!M-r‹¦MM)ÑÖb„cÚêíá&2.âA«•P„EÕ„gWÖ êªÖµÀÆ&ëF¡‡qäsß ^»JÂÆ*¥gT]ZO1cmû%+ 45陣[åa„!´Ê8#=J°pÆ0&UÝh €µ“ñ 1ù!çÞt2ÓA€ pBG°FzÔë$A»< (¡A€ÅÌsÖX ñîÿ·µéÎrZ—Œ¥ÎJQ‰²jªÚXØÜÚb¾§¬Mƒ ý(Š# INI+ ±ªn¤ÑqœDQœÏRLI§ßí÷{;£¡ÍöÎ6Æ0ŽWZ½¤)re4 ƒ^·wìøêÆÆf„ÝNû¾µ iÜnwŒ‘J ç ŽzLi5O)áIÒîö»\pþæöÆöÎN^ÓNÄ­Ö©Ó£ñ( ¢½û÷XYiÊj<›æy&„ÐZCV1*ÛmμA¯/¥:¾z¼bc}ýÔ©SeUõƒ½ûöû¾O(Û»¯{î¹ç†A0™N­M‘'܇L§éd:ÝÜÚJ‹’0: ‹ Ö¹Ûo¿!ñ¹>B0ÍSÙ4RaÌdš&I|Þyçu»]£µµµÖh[×µÓ&MS©´T:Š"Ƽƒ„Q”eùÚÚÚd8Æk¥qM¸i#õ4¤…6Šy6n8N§iIÒ BHaYél8KÇçq+bŒÎÒéúéuÁžNoi°Ç÷ý¢È777Gá–Šbâs>B¨ÕyH«¦ØÙÚ)ªr{¸3MÂ04J+!»^:Bãa ðzÎy+ÓQú­%„¼ùÍo¾ýöÛžçÝpà ËËË»ÉÃÞð­õ¯üʯì§Ì²ì¦›nzÎsžsçwþĶ?1ç¼ñÆw_ð‚\rÉ%¯|å+G£ÑnÍ5×\#¥|Þóž—eàÎ;ïµ{ö³Ÿýìm·Ývæâñx|ë­·9rä‡?üáOùL|ìxŸúÔ§v»Ý·½ímßùÎwŸÿüçÿ#žË¯zÕ«¾ò•¯¬­­©9zôè3žñŒ3ÅË.» ðˆ5‡¾ûÝïîß¿¿ßïêSŸúÝßýÝùBsssssss?#0FF+Ñ@ŒP•—A€ H!”’hG ¦˜Bâ€@Ä ßnêúèƒîÙ»¯¿°È™gŒa„0Æ”R€Â£X[­„¶ÖDØ÷¸(¡ɺBÔEUÌ2Q7 [Ë!œCLªqó =Ì j”Í«§-ÐpA UPâad€Ú¤€P¢ÆØJ¨,Ç QtQÂãÀ3µÔXˆ¦Ó©çû`‹ b”zÌä||ª)@ú‘ïG‘ÖAH1öGxPa™V)(•ò˜ª Y7²i °˜aŒ ¥^ÕȲ*­µÀÁÈ|Ï÷÷¹Ï©ü‰mBÏóv­µgÞRžíüóÏ¿å–[þò/ÿòæ›o>Sùüç?ÿk_ûÚòòòòòònÍÉ“'Ÿö´§=¢íÇ>ö±GßóñôùÇùû¿ÿû}èCW\qÅG?úQÀK_úÒ/~ñ‹g2aç\’$/zÑ‹VVVâ8ÞX»¸¸øÓçœïÚÚšµöÿøß÷¾÷}÷»ßÝ}ßø÷Ýw_§Ó9{A “g?ûÙ]tÑ5×\svåõ×_ã7¾ÿýïÿô§?}äȑ׼æ5u]#„ξæCúP¯×»ôÒK_øÂ~ó›ßüЇ>4ÿ„›››››››ûYÀ}¯ÈAÓˆ€û¢‘:úÁªi¦éBp^V˜"̹§mŒ"…a (òœ¡b:pßoµZa¦³ã܃`”–Z ìAˆJY§Óª‹ŒbŒkªÚ£«ÆJáŒSÀ c­Ql ñ<æꇌqjÄh%…”{ÙÆV†bÏc Àö9'b€BÎY¥ 2Qb QÚ‚™ç˲ª±»¨VRë 5,r”#3ê1/y'ÂÜcŸŽe%•nÎ:h4bEœ¨š(!}¿)(cÔ3žƒŽpÆCß7IÓª®€œq‰IèY‚1DÈ8§¬‘F7Jj¥Á>õy(£ÚýŽÒj2ìLFÆ™å…E§ÄJdœ/--­;yúôi‚ ƘR¼¾±¾3œ„Ás{~QišjåêªÒZ5•¡GAržgùx8“d0X4JOfép{› ¼²r€âQV)¥©©ÄžF;àš¦)ªJ¥©¶¦ÛíZà”±ÛÛÛq'­VY–ãé$ #pc ó½ñp¬aIÜ —¹ÏkÙ G#Ì÷–ý^€´È0!ÀÁ4¯Œ”yBHÆXF„¢(ªªÌó L)Ù·L) çž{ŽïûãÑÄ÷ýþ ŸeeœxI»ÇqDAøÖJ%Ó4K³¼ªjç„0Í2¥u·Ó¡ˆ0!íN»ß_À„e]×2ŽÛ‹ {¥>Ú­ŽµÖhÐT#ÊuÖUU(ÞÞ-./ÅI§ÕªÊB(ecu%)¡Aà€gÓqšM‹*¯šn§'í8Žã¦n<æý_9§¢išÝãݤ…Rº[ìv»ßþö·Ï\9›Í”R½^ïñ´\rÉ%ßúÖ·v;vèСG< ¢(ºõÖ[¿÷½ïýáþáY_Já~¿ÿ¢½è/xÁÙ?zòä‰'ý|ù‰}~ ÃáðK_úÒUW]õÑ~ôÀ—^zéË^ö²³Ãùâ¿8N¿õ­oeY¶;wñìxŸè—p?!ÞãÇ¿ò•¯üÓ?ýÓo~ó›J©;î¸ãu¯{ݵI;ÎkQɆ;ë3 vМ‡ CÈA§â ¶HkŽ iœtì€3ÎZìXÄmH #AÈmûA’PŸ#ŸAŠ,ÒJÐÑÂ(€eeX«­–BIaµvÀB Î9÷ýY‘AŒ(cÖØt–ʺa; ’$ñý@ ‘W¥R*侇eˆë ¤¤™Ùq:ÍŠLkÝiµ}J¡sÎ:`]Ý4Êè²®vF#îû¾ïmíl+YG!'aŸÇQk:E¡•›Œ'v‘.êxE¨Èò²¬B/èÄ p0M³µÇóYê€ÖZeŒUÄ €8£µ®šF(‰ ‰¢ˆz 2N··‡£ñ˜û¾2ÊJG9C„—uå¬k”4F3Â<Æ AÌçžï+«'³él6mwÚÃÞB¿Ýéc¦ÓñhgÈ(ƒ 8cQÇa1æ!„···Š¢ úq!ˆ!Ýn×÷ýÙl6ÜÙ!„\tÑ“ò²ô}Ÿ2F( ¢ Œ#!…„£ñTkëó€Ç1„ ÏóÑhäsÎ9c,æ^èšÍòé$€ô{KýÞ"°Óîz,îìLÆ3FýV‚EÓ4u¥E¥„C8‰[ž"D‹¼†1%@í¤4bL<ðp8)«¢núŒ3B¨Ö•êñ®[[UÕ™9‡ß÷)¥eY>Îæ÷Ýwßå—_¾{\×õ£/¸ñÆ“$¹üòËÏ~AgŒ©ªêúë¯Ë[ÞòØ÷ÿ‘/NÊ>ßrË-7ß|óž={®ºêª²,ÏÌí¼ÿýïÿÁ~pùå—c¿ø‹¿xå•W>¢ù\j­={ÓNß÷ÿMñÞ|óÍ7ß|ó¹çžûüç?ÿï|ç§>õ©'?ùÉÿ^Oä$I^ò’—ÜtÓMg¾>8Ë5×\sÍ5×ø¾_×õáÇ=Ï»ÿþûäMn»í¶k®¹æçþçç9çÜÜÜÜÜÜÜÏ‚Áb?›L m3ˆ°ÎësîE>„ ˜åuU" œ6ØB)ƘRä´E¶Z‚ ¬J Ä (óN¿Ój'Ãñd6Ë’vûÀÁ§M™æŒ’ƹº²Jz>÷¤¨µÇDQÒØÙÙáq¨<š+a„d¾/”V9ÕXgî·’(Ï3gu* ‚½‹ýí¡.‰Ȇˆ`Ê„µÈ±³Pk Àê)‡,‚Yi¬R!DB_;#µ²@B@6 ,‰Á˜Ö £^ËAÐXá8Q„û.CNZ!d˜T•„æY)ʺ*Ê"Ï«¢,«²¢‘9쮵Í&žÇà *Ól´5¤ƒ<Ï‹[m?¤yžÕUµ=ö»½VCg€•”Ò²©„’ÊaTZäÖ²©|â1BƒZÊ<ͤÖ~äU¹zâDU]kÕP†$„R?Â0Œ“¤Ýng³bsc# ¼N;˜MÆ‘Ð÷Ûq2äãõMݨ .¼°ßna§Óé‰cÇzý¾5c”’Î:U•æ¬åB4R´ÚmîûÔcˆ’ºi ‚išú¾Ï X”Åd:Éó<äñ!AL(Á”4JN³T(ÑH‘tZœóÙl6‡£a]דé´*Ë( £(^è-v»BXc¥µa¡"M3B ¥”ªµÉóâøñãk'N®8'íó/¼pyÏrQ§ÖOÏÒT+¤šLfI+B2æµZ-Æèââ"%øÞ{x|õ8£tß¾}”p¥ìx”î ‡”Ë{÷íßwN¯×ó<îû|<ž¬[›Mòý{WºÝ6°¶®ª4K^} à¶Ýƒ ö¶¦ó~'¦„BœÃívŸûþúÆÚx<©›'m£m–7ç¼çž{žõ¬g!„v)½ôÒKw+gó,Ëî¸ãŽwö­o}ë ^ð‚Ë.»l8>âÔ·¾õ­ç=ïyÂ'0?ð§ìóm·ÝV×õ•W^ùÒ—¾ôÖ[o­ªêÌ©C‡}âŸØM8wsÎG7ße0<"¨ÑhÄk·Û»ï Ÿò”§ð³÷üxÂ.»ì²?û³?ûó?ÿs!Ä‘#Gv+|ðÁÝ…Rßýîwß~ûí7Üpûßýîííí .¸àÊ+¯¼ë®»þùŸÿù?ºÏeYþã?þãüÁ¬¬¬üÑýÑ#²Ù—¼ä%û·»¶¶ö¾ð5¯yÍ£›ík_B¼÷½ïýøÇ?®µþÎw¾³û ÷î»ï¼ýíoÏ{ÞsäÈ‘ßû½ß;»ÕcÇûœç<çÙÏ~ö?üÃ??~üÀW\qÅ¿þ뿞pöîÝû7ó7wß}÷È9_õªWÝwß}ÿò/ÿòˆúååå_ýÕ_½óÎ;1/}éK_ÿú׿óï,Šb÷ìg>ó™Ï}îsßÿþ÷˲|Ö³žõ¾÷½o4=ž_ÐÜÜÜÜÜÜÜÜL‘x˜ ¢Ê›¢ Âlœ‚xŒ€¬ÒI+-T€˜:`EÓ(k †Ôó§Ak46ðˆˆˆ`ìs/ä>ÈÃÄçœqV5U6K&¡ï'q+ðël]Ež³¬‚°qºÔ*òxðœ~¿¥Tã`žøáx<‹¢HJ#ª¦®ª~°Ðíž»rNœÄÀ9Œ±µf6›®­­•UQ‰Z£­!”ôúýÞ ¯ÕÖA! G#km‘åRÊN»½´°RZ;g-°MÓdY6™Mê¦ÂRJ­µRIm õ"B䜋¢hi°¤„:qb8œCˆ:kwWd²h‚(–FWE)¥ªë:ÏóÐBß·ÖmmoOóâà¹çœwÞùÏ9ÈÿÁ£}è¡ñxblµ’¸•„aØÜÜ|衇ŒÑç:—`rjmmsk†<Ž‚~w¡×tÚýN»c X;qêØC«M¥.¾ððʾ•n¯³gÏ"!Øhy`ï¾Zê²UVí„Qf4PBH¡Â0:xð€ç±‡~ÀZÛn·y BNž:qÏ=2B÷íÙÿxsÎÏ~ö³o{ÛÛþäOþdw¾åêêê‹_üâ9JößêÈ‘#¡7¿ùÍo~ó›ÏTžsÎ9»S4¿ò•¯\uÕUüà_ýêWïžúáø8³©Ÿ¾Ï·ÜrËË_þò/ùËg׿îu¯»í¶Ûv—ž:uê-oyËÇ?þñG´=}úô¯ÿú¯¿ë]ïúßø á`0Ø]‚èûßÿþ_ýÕ_½ño|ã߸¾¾~Ýu×ýÅ_üÅ™V¯µöµ¯}í»Þõ®Ýâ÷¾÷½—¿üåÿ^ã§?ýé?÷s?÷¦7½éѧ(¥×^{íî@å¦iÞûÞ÷ž½Ècì†n83õßøÆk^óšŸfNéÜÜÜÜÜÜÜÜ¿# fØ} !¡$à>¥Ì«kM0ó˜g‘J«Zå<â%«¢²ÒyÜG„YçÆB§¬« ‚Ü(YWe’´ƒ0eYVeoÐm·’(ˆ-0ЂnÒáÌZ0!n—1Z7µ4Êäw’|:m1F ‰ÃÄ!-…$¢ÌAŒ‚ˆø‘g¡¯Œ0 -•ÆÚZ0ÀÐ(1ZcʈÏ«µÑ,ð¼¤åEâR´»Ì$ 1Îyà#µÒÀ9-dSÖI†°ºQºÌrÕg³ ®*ë¦Ä‚1cÌ£•Z—M]ÖÕîtÄ¢(š²Ru£¥’MS RÖJI)eFJŸ±( ‚œ{Ü÷!‚!ÏãI’`„ê¢ÜÙÙ)Ò‚Brà1æ±SD¡P bXVåx2év[€…K. IDAT~`àÒ<‡ÊŒµAB „"FYYUÖºªª«ªªë†bËóüô©SEQt»]€£tii±Ónçyw–Mge ÔÎ:„âvûü‹SJŸ8‘¦©ÒÊ |„ª*Q7¢iŒ1²Ù4…B€}îDÓl¬ŸvÎQîݳ”´À©õÓ£ÑÇ=nŒÉÒL…™N§aJ1A!XUUÕa瀵ŽR'I¯ß—M#…0F©Ft:8!BeUfe‰%”--ï±À9󢘦)ãœRÒj·ë'NŸŒ†K{ŸµV1eMÓ€´¶Ž(áó‹išž<¹–¦Ùòž=ûöí ÃÀcÔ9ãH’øiO{Ú÷~p_;î)2¡(Lªª<}úÔââàÉO~R«¯­œÎ¦”ñþ`©lD]× „(ÇsY@LJ®ëúþûïß°úŸ!tøðá N:µ³³óojûÔgBÈùçŸO)½÷Þ{ñ¦ññØ»wï½÷Þû#g¢>v¼+++ ÛÛÛgogòRzÁxžwôèÑ3o8Ï‚àÀa®­­=z€ôÜÜÜÜÜÜÿXsuƒÅÅEÀu×]·oß>B!ŸåkÅ?ažç-//Ÿ{î¹¾¡µöرc›››?rUüŸeԮ뮻Î\„g;³SŸº÷»÷”YÝi÷Â(´ÈI«¡‡Æ¡:/›¬„0HEYËJDÃ(ö£Øa„(3ÐÕRJ£ÆqEQ [í®1ng8œ¥³N·³å@·ßÃk£|ßÓV!â#”â0äñh8¤Îèí ì ÊJ ÀéZù”Ô÷g˜ÌÀŒ²ªjœƒˆ ¤ÅÂB 1ç¤6ÒÂ9‹é¬Å0hÅ,ôƒVL|)¦> ¢aÜ” Á„ Ä( |Ÿ ¢dc••u­…ÖY­EY6›§UY))šJ`‚BB(c-gc´ÒX[K1žNFÓ ç¬3Yµ‘eîŒê¬5ÎÕJ)­ uPÉv«Ýj·:í¤Óm3î)«´1ŒyÜóu“á¸È3 ‰O=ßc!ç¾ï{,€yYV•1 X³ßÒÒâ`0è1‚Œ8ó›JlÞI§³ÀçGžtç^ÝÔá4Ë¿ÿƒ{î¼ë.B™6†y¼Ýn·Z-BˆpÏóÎ9¸²ß>ˆà±ãÇÚ-pH0¦˜zÌZË9rÒXiŒ5aTUV-t€"’M3Ši•×u-¥ÒRê´(Â8Ä€`t€¦„`ìEQ§¥ŒMÓTµ BG1¦ˆL0¦Œà˜D°²Éf‘xk±œQSë€ûÀ¦ª”Òœy,é©‘V!cLi!B„ø¾/%vN¬ÉçëÖ9'¥ÒÊæy™g…ïû< ÷œ³›ÕjÝîtÂ(îv»Ìc„RƨÖJ))•$'IE!BÐZ4Ö8Œ5Z+!*‹µµµ2Ë766ŒÑû÷ïë÷:ç´5ªi ¥˜1æÞ ×mOœ6"̰K RJŸ<¹úÕ¯Ê'?å)Á¢È§³T)å ÖR*›NÉüá>7777777÷?çüÉO~ò׿þõG§g—]vÙÿs çcu†yȤtzݦ@k ²„`â 8e0@@@ õ‚C¤šÚB©" ó(ZZ¥´hPVE>!Â+vºÝÙtÚTÍl2£”í¾HäÔ3)Ý4²¤[c™çQÎ !] µJˆ|ÑEÇVN«Li½¹³µ±½áq~Á…*£§YZT%@êb4C•RÌó‚Bä‚Q–Dq+Ž…²i‹ I•e‰kG±G¨"NÚ˜Àóø`1Ž“n· ¥ùúúÆöú6¡xyiÀ=:z衦iÚ>ó|!$ Ã~¿¯¤”R–eÕ4£ÔçA–¥u=å²IºÛáÔÁ Ü»o/e,˲4M›¦²N¡Ï<Š išjsk}:ml¬#„’$Ƙ(­@]b„¬u²iò"ë´Û­$òøîö+ÈXé¤8 gÓ±Ú]I¸QÄq˜å©”Êó¨ç%e]>ðÀ½Û;[­VK;'”J;€ü0B˜ÖœçœssssssssÿSø¾ÿ#GÏ !ÎÞ¿í¿GPg8 ‚„âÞ Wgu•ÕÄ9äG %¬)J¤'”!ê s˜Š ZªF)@ˆÀ ƒ`ka–S)ŒV„z•J›€ûËûöwÚm¡´”j´5lªª7èaŠ‚#Ê¥ÆX£-ˆsŽÆžG_i ‰;qÔŽfÓq‘åÙtb´’¨qÔB $64ˆî´B!JˆçûaÅQB<BcL1¦À ŠãÆ:!d£E£`™—²n´TBŠˆ¬k]+†‘Qz2™lmnM¦­µ4äqŸ¾EÔ0P+%dÝÔ¥µaõ½°•$­’óX'ŠÊhŒk·Ú1e”Pá@.d6K«ÍÆEU!ÂêFÄqB„¨ë‚fxà­'«²DÀ-5çwž«®ºªÝnïßwß}˲dÉ’%K–,Yò_HU•ÈAä0ñó("Hm›†0æ&ž‡iÀ0`ÆkŒVF[èAl˜„Tc,ç\kÂaŒ “ÖèF*RÞ0_Öœ{¾ßn·“4­êª®¹xÖÑXJ±çùS­L6/©™Ï×a/"6Š(Ól &í^/L"!¹µ(¥ÄGaø„~ißw"€@V9# 0ÀhÖI!”±Î:`j„j„Q ´Èj݈ÆHi¤æeµX,¬6ÓÙt¶X £4%Œ²0ð=c,ESç“3§NK%WÖW\p m¥‚‹ímä€u–@ –ó¡Oh§Óî ú½Õg­rÖ[Ì}ŸA”‘rwˈ0Bý^Ïj“ϲép\–¥ïûq&qœ¶Z,òP•€AUkB˜fžÏÇÃéö™-zRH -ˆÑ0Œ}åIßó€ƒ8ˆ`#„H§ÓKÛ©u¦¨ k…T’zÌóØîrY„ñd2á¼Ìò!a#­Žù"ì€RF=Ÿ)%tÚh£´j¤ïÚØ¼(ŠlÎ7FY«¦Œ©±N;X]5ÆlnmMgó¼(¹àq{¾O(B¹ä¤ÊÓCh ‚8M[QƤ¶Æ8ãL#yÓðv»ÍqÆ)%«ªØÞÞÔJJÙ  ‚‚†×Œ’0N)‰„ló¹TÊc¬×í­®®*¥'£Éææ¦³ãnG§q†¡’:Š¢ÙtŠ K“0˜Ï(/ëºÌ0ÆÎ¹ùl¢¤J;©q`g4ÊóÆ âv;MÂЧ Oæ'O¸ä²K÷ìßW5âÌææ"˃A; ƒ2ÏE]”9A.e5¢ZjÎïøÃît:O0~ìcû«¿ú«Ýã—¿üåïxÇ;:4ïºë®øÃι'_çú믿òÊ+ßûÞ÷þË¿üËò›°dÉ’%K–,ùï@Y–Î8d!!l­UF9i0&R”RØèœVJkœ%uÆ*£•1~VuÅüÀó˜6º®ëÉxÒîtˆç…Œ ¥¥ÑEQPÊÁ!)eœÀN·[V¥6C€Õ(e<Ï·Ê,²ÌP»ÛB)!µrˆ@Œ°h„Ò*Šý(J¢$2Æh)9F[”#‚Zã a‚°A('¹TRm´6Ú:€6§´5wV9/³\7Ê(%*^×Uèµàól)¡Q‰øJpÎAÀy­´¶Æ¶’ÖÚ`Pä…䢛¶8çºi(!«½þb6×R))c?°Fû¾×4Ít:qŒ§ãÉlRV%tAŒuÚ ¤’!`–e„‘hšÑd·ÒV»=Ø·Ž|™Í Ä@Ó4Z/«éΨ)«V[kµÔ墨¢˜0låBÔEéQʺ½8 æÁLÚZ Ä„8ç„eÍk!¨çõû+QaFQ…„ùeY=~|g{g¥ÖZ±•~ß9¬µ$Q>Fp±XÙB(µÔœKàMozÓ¹Å?ù“?év»Ÿÿüçw‹×_ýÑ£G_þò—ÛÝLeMó ¿ð ¿û»¿[ÅÙ&¾ïßvÛm·ÞzëÛßþöåý\²dÉ’%Kž›››{÷îeŒýwîäƒ>èyÞE]t®ñÈ‘#MÓ|×w}ד+?ÙøŸLÅ>óR?EóðW5Ö@ ¡ccŒV Ð:"ŸEBð<ËfÄc-ßwÎ5'ÿkÒ8 ƒh4/¦3m ¦$N[„ÒÉd¶˜Ï£8!„Ìêj:ŸköíßWU…6šœ$IQ³Ù !ÀÓJMwFˆÏÈ!¥$&€KÞŸvÒ6¸ÈsÓTNc ˆµV «d%›ÌC Xˆ1u*윢¢”¦±MÝÌø¢ª* ÄÐ:WUUQ~̲¥Ä«Œ|6X_mµ’5Ùt=x˜±V;õ‚Hk‰!b„®¬ôölì¡ûúã³ÑXÕè”ÎËZÑðZ6b¸¹Õmw¦Óét2ɳ¼áÜå3/I’8Mœ±~`J‘u!8çŒm”ª9'„ï!d ›ÏçãÉÄ"ˆöìôÒg_rõ½“_?qòñãùx–†á¡ý{W7B.²,ËËÒ6ME]txÿÃ8*Ër°ºòÐCõú½v·3ÏLI”$ÒèáxT7œR–ç…C8J©µ6`Çqœ¦U])# QäGQ¨µ–JVuñ½cª¬)kîQœ¤ioeà{¬ä²àªi€"”’”1ˆ€•R ÛíÖ`°¥„aL1aa„’V§â~õßþm:ŸaB´Öý~ŸR:›MÆÃÁhm°²¾ºšìÙS ¾3£³¿Æú¡úû¿ÿûç=ïyÿøÿ8›Í>ÿùÏ_zé¥çþ\_øÂÞwß}óù|ssóöÛo?²x>mŸ‚K/½ô Obmmíl…ÇÿÉŸüÉp8œN§ögvèСs›:tè¾ûî»æšk®¿þú'NŒF£?þã?>»uòSôù)èt:Ÿýìg_õªWk¼õÖ[ß÷¾÷í£N…aÒjw;½^G#€ ói¾ÇøÃÆ(ˆÑÊÚ곿ë²Ë®ü®Áúš¶¶âõ¾ýûÛÝŽ±&Ïó²*´žÇ€3Ùd2Žx]3JZib­YÌgeY­„¨ýúæÖ&ƘZUÕt2ÖÖe5›L&냵4ieÓÅÎæŽ(¶;b•S\ÏÇ‹Ÿ>}ìL6/b+½µõÁÞVÜÕ„Zå IDATmÏŽ9}äÁ£gŽnçÓŠ/šlRŒ6G;§¶G›£|V˜ÆB‹œ´Å<ϦÙhs´uzkgkg<š,™ƒÎü¤“öV{Ý•n)ªñ|štÒ Z]h£v¦ÃÉl4Ïf£Ùx8-òEV,Žýº¨ª*ÏG[ÛÓÑ8ŸgóÉTqá0ßj3ÜÞQ¢ ý`ÐëïÙØØ·gïJ¿ø¾3D‘xbÂ(e è€a‚Ã8RZÇ£Ño„ˆ’ùbþÐ#?ð•Ýî¾ð⫞sÕ¡C‡ö¬o¤q’ÍæGzTE7Ž»I’ø~'ŽúÝV’†Ì§A„Iµ’g_~ÙUÏ{î`m­Ñº3Æ‘Ôj2™nmoOgse-¦ "TÖÕ"˸Ì÷÷íÛ·¾±Ç‘5ZˆZQU%ç•ǼÕÁj·Ûu…qÔîöëû$ínYóEQ´»Ý0¥3eÃkÕ,ªâkyôÈ‘Y–±0ìôW¢$Å”)m˲΋"ËË¢¬­…IÒiµ;i’DAXdùt<™ŽÆ³É´®*gLžå›§ÎÌ&s-5FCTÅhgX%Á$ BЉ¨ÄÖ©ÍGOÿú±“GŸ9qjçÌf±Èòùbº3š'ZÈÄ=ÌÀ>õÏ·ÚM'Ó2¯?ìvzQ”PÊz½•K/¹ü¢‹Ÿ½ÿÀÁN·‹ ´Öa˜$IŒæ‘0¼À7ÎeY^U<Ž“½{÷c‡;ãlž1Â6ÖÖŸuè‚õµõÀ÷¥hŠ,/«ŠÒm·Â(øßóœû÷ï¿öÚk?ò‘ÜvÛmBˆo¼ñî»ï~Îsž³{ö²Ë.»÷Þ{¿üå/¿ño\]]½ñÆ/¹ä’—¼ä%»²ä©Û>5ãñø#ùÈÙâOþäO>ç9Ï9»ÎóÀ_úÒ—Nœ8ñö·¿]kýs?÷sŸùÌg.½ôR)ån…(Š^ò’—¼ç=ïét:ü॔¯yÍk(¥Æ˜§îóS0ŸÏ=Ï{Ó›ÞôéOz×2 Þô¦7½å-oÙ-^y啇¾õÖ[;¶±±qýõ×_uÕU×\sÍùø{ðàÁ—¾ô¥g‹ívûe/{Y«Õ:Ûíößþíßîz䜻úê«/¿üòO~ò“ç^ÿÀ÷ÜsÏC¾âq.ö V/»ì²qÜžnËé"t°²ò¬CóþØ×;òØcG+ë a¢´A”úD‘5o*^‹F2ßk·;ƒÁ ßïÇqL)‘ªšÍ§‹l^Õ…µÆXG¥ÌCˆ„+!D#€B7²á„`eÀØZG<æ‡a]UAæûžçcDY'QdŒ©*Þˆ¦‘ p ðã$ˆW}”¦ZJÁEžÀBêyIœ&IŠ1.óŠWµs†×„‘(ôƒ={ö~Öi’ŠºžÏç§N)² â1¦9Í !IÚ ü#„ î¶;í´eŒ" ^+!!„a@˜µPp©Œí'©RŠö’Ñð±#GæÅÜ#Ƙ±M]×óÙ¬•¶p«j¸°Î2Ï VϜٔRÆqÜjµWvg}ótµß_䬌Gu]Jò<û?ÖÖBÞõ®w}æ3Ÿxžwûí·olllmmÞùÎwj­¿ïû¾ow9ežçwÞyç‹_üâûï¿ÿ›¶ý¦šóŽ;îØ=~å+_yÍ5×üØýØd2ÙµÜpà RÊ—¾ô¥»ïÒî¿ÿþ'NüÈüȹ2Ðï÷¯¾úê]aö»¿û»»ÆoÚç§àî»ï¾å–[z½Þt:¼îu¯³Ö~âŸØ=ûéOúÜ ½étzÏ=÷\~ùå=ôз9‚?µ¿W^ye·Ûý¥_ú¥/ùË€¿üË¿|&þE~â'~âþáN:uÖräÈ‘ç=ïyg‹/zÑ‹gs!„>üáÿÎïüÎ׿þõ¥æ\²dÉ’%K¾f³™çyO]§Óé,‹º®?¾«ÐÎj³ žœð™ ÕjíììÔu†aUUZë³úóéñŒ:…íjÎ!DŒyVŒ‚ˆ`Üét”RR7PQWYQ…¾ï1Ïc‚7”¤‰µŽóš•çù^"”Åb2%ž‡!BA€ó<š¦I£šª*Ó4‰¢ÐÜîû>!XpÁ‹š"ÒowÏ+ª|1Îê¢òB/dA#U6ÉWÌ÷ü0´9ç”±ÖX XwŠ —Be:wh¥1Z›élÆ9WJSJ½Àã\¸`¿¯}!„Ô¤¬¦c”:g«ª(óüÁÿÍó½ ô•Z#ŒRF1ÆX‹D@àÁ"JHÀ¼0 ­µá ð­Ö ç‚‹"Ï=ϳÆ" &#¡uVi@È<Bè”ÁYm´RÎX  ¶Î÷ýv«~†~àyÓTu]ŠJsúÄ麨ésŸ×KZ+ƒÖ.òüˆx­^«·¾µãI>;9Üœmžt ÖVà€h ¡Ù,WRŸÞ<óõcG·‡;ι ¨ç4†4JU—¥µ Œ¢v§ÝjµÅóùÌ]×¥\p®‚`Œ}?ô<ß÷C‚}­LUÕJ*„aA¢Œ.2!eÍk 6Fm­3Æq.êšóZ”yÁö0‚‰–&ÏŠ²,1Æ‘bóÙZ5ŸN˼Æyž†Qày@Éþ½û‚ X,æ@ßó»Ý^š&ûöí]Y!¶vvŠ¢Ê‹Ò÷Ãõõn·WsžåE]×”2B¤Ìg^¯×ÛXßR"ˆ¹®*)¡Æº†7M#Àº­­‚h#¸ÐXs^Å"[ø~ ‘FÎæÐYz~;maʤu™Ï狪ª!€a¥I 0ÚŒ[­–”b6L§ã( £$Ö<1žólß‘#Gëë뻺ñ/xÁý÷ß6~ï/þâ/οi[„ðìj­=;Ky.^xáÝwßý|à®»î:k|Å+^ñ¹Ï}ncccccc×ròäÉ«®ºê m?ò‘<ùšçÓçoÄÇ?þñßùßyÍk^ó¡}ðú׿þïþîïÎ*aç\š¦¯zÕ«8$ÉîÂÚÕÕÕo_s>µ¿§N²Öþâ/þâûÞ÷¾ý×Ýo|<òH§Ó97!Ð·Ä _øÂK.¹ä†n8×xë­·ÞqÇïÿû?ùÉO^~ùåo~ó›9çgßAþôOÿôÚÚÚM7Ý´|PX²dÉ’%K¾M‹ÅáÇ¿‰‚ÂøÐ¡C»zìøñãû÷ï?uêÔ®6;tèÐÙ£gšÝ©ÎŒÇã'=øàƒß¨øb;ŸQ§ø_ûp.,agÝî†(FÏ÷ £N­µ1®n«­úúJJ€`»Û±Ö .´–”Î÷hÍI#e6Ÿ{ž·¾±Ñï÷„T³éÄ«ün¿¯ëz±˜à|!„BBÝÈ¢®ÊFuÛŠ…Ô8c¤N4µÄgÓ|1ËÃ8nw-ó´1¦‘ªi$‚ˆbfS’BVU]ä…hkm^Î9„çyÚ©ZpL‰C(€b^À%ÇaDUÍŠr¸³3ŸO××Ö¥ ¥ˆbF‚VGa 4RYm¬ÒÐÙN+õi*A0ö}_)e­î.<Î ÙHB&8Cæ3„ ³N+ô|Ÿù¾ïù €‘JBŒ˜œ‹£8Š"?ð=ߢ0Š#€PY–;£Ñ$›ÕRÌF“ãåýA+Œz«ƒv«Åó²rj!Ê8‰û{×¢íS;Ç'‹|!†óFBO;U–Õ±£G‹²ôƒ‚À„:ªšW¢i”®¹ÃÐ÷}ß÷U]y>n/óº,5A„ Æcl´æ5GÈ”%×ÊYcʪfžG)ÖÆUœK)!DžÇ0BRîfÚ5Z%F!´°.+ÈúêúE‡/BäóI‘Më²`„A€0ÁÕ(£,Fx°²‚ª«ŠAÇABˆ‹l<™?q²*9oäúúúþWVœóÑd|âø‰,Ï 8m „B©•h­4DØó—¢¬ª²((Æ¢­Ím«,€N+•e ÆX¿¿b´)ËB)•MSù"±çy\4ÓÙ¬ÈKJBAd­µÆXeívKIQä¹’’0 ’äÿМMÓ!vwE ¥t·Øív¿ô¥/; *¥z½Þù´\sÍ5_üâw=úäÁ4Žã{î¹ç«_ýêÏþìÏž;úôûýW½êU¯|å+Ÿ0Æ=¡ù‰'ž<¾|Ó>?ãñøïÿþﯻîº}èCû÷ïÁ ^ðC?ôCçºów÷wóùü‹_übžçq?Áß§ùî›ù{üøñû±ûõ_ÿõú§RJÝwß}o}ë[¿öµ¯[ÙZ»X,žvÞøÆ7fYvÏ=÷œk¼óÎ;÷ïßÿ¶·½íï|çñãÇüÇü/þâ/v?e0Üxão{ÛÛcŒ±Ý[EQš¦ç†y,Y²dÉ’%KÎJ©"Š¢ó—»OÿÉ‚Ðn·‡Ãáb±àœïß¿ÿÜSç ËóÏ!ôÌ9µ;{£µ.ˊׂ  ¤„J_ic#†ÛJpç€ÀBÇ›¦‘ÊC n÷:ýn¯ÌK)%e´Ýn)¥ëº0ÖQŠ!FVëÉxÜítz+} ªñlbóV§ÍSJM&Îë4M[I윳Îú¾¯}=ËËÉxÊEM(iµ[ˆâŠWù¼ôB¯æ\%„r2?pÎU5/ÊÒYà3ßJ-Ec´Î²Åt6«ª a$•òà H!ñp@|!y# ¬PŒP^/ê¼Ä¨í¬%ØØ{ðàÁN»ƒ)vã$õ}!$¹(²,Ï2QV>óPµP\pÑ^s)eÇ„b!©u¯×c³ÆÆœµZc,"¤ŒµÚ0‘8¦k¥]d³9Ž/8xðàþqšT‚«Ìl?tðP2è®_°”Ï4t³l¾(óã'N@ˆ¶·v†Ã‰R*I’•VKk]EÍ…œ7 e "L0fŒ!yÍkÎs¢ùt¢T³›¤"`ÑÆUUUs¡µÃÈ“Ê^H)«j®µF>CµZ­$ŽeZªªªD"i5°.ôƒµÕÕ^·Ûïôм°RÄÿ¿ÿ¯|Ï÷|àÕ©“GG;góéæ™íápX Ák¡‰ežD!çAð}ß÷C­u]דɤiš,/e¸”i»=X[kuÚ^àYàÒv+L¢ªªŒµÆÚFÊñtÌ¥,ò"Ï ­ï$ô4°@èÀ®“eU‡CcMUU¸ÁÊZ»ÛŽvfó™Ñ†œSJNfs„I„œó²ª£(:pà@QUUg‹|¥×cŒ¦iÇ!B°iDÓpc”œáùæ­­ëúlÌáî@)­ªê<›?òÈ#×^{íÿ÷†‰?¹ÂwÜ‘¦éµ×^{î1¦®ë[o½õÝï~÷S_ÿ?œ8ý6û|÷Ýwßu×]ëëë×]w]UUgc;ïÿûÿýßÿýÚk¯ÝhÿÞïýÞ×½îuOݾAÔ¨µöÜM;ƒ ø–ü½ë®»îºë® .¸à¯xůýÚ¯}âŸøæ‚KÓôµ¯}íwÞyöõÁY_n¸á†n¸!ÎùÅ_ìyÞ£> Ø¿ÇýèG?úÑž­ÿGôG'OžŸ¥¤gçü?_pBý~ÿÌ™3«««ßf¡gÚ))•‘E•U“Ñd<WE)ňçy^Ç\ˆÉöt6Ÿ!Œ[­–E°i”.sè@'ÝAß÷|D @€”¦IEQœ>yªªxœ¶â$ÕÖeyôèQetuõÀ¾½E];öõµ=Œ1Áb1Çöîm¥)£Ä8~§×¬£ Œ#F0h6YPŸ*­!‚Z^‹ Š“$™Mç»Y^µT@ÛÉd2 ) !^Èâ4žesenœ®•Aê꫟_Õb4Š"„p–-°²®J{ö®u»©ïûúQhM7M(£㤕J¥²<ïv:>„“ÍÍGŽ„{Ý¥4ó=Dðn:Ü0ФR„’V§Åqš$Ù"öú}ÆHYUUÅa”åY‘çÆØ4IÖúƒÐª²pÊD~@)æÛãEN)ee‹Åd8êt»ÚšñpØ”ȩ­,›b>›'“ïºêÊ‹®¾êäÉ3ÍÍð Aˆ Cvzg #Tæ…lšÀ DEQ¤iŠ1Îó¼,K)¥Ô* Ã(ˆ0ÆÈÁ$ŠEUû¾ˆ•J5M£•2JbB? Œ:h¥QY^L§“ªa”®­®vZÝżB.pQ´Ò¶çö®­…A°˜/¶Îl€×6V•RÃíá¢ÎDõž}áÅû7ö;zlxfG"ÑmµBæ{_rÑÅW\öl)ù}Ÿýœµ¶®…”ÊZ€ ÎÙ|:¢¨Ûënll0Æ‹™µ–ùÞ"ϳ¼ðüpµÕ:xð`»Ý"f³“'Ÿ:sêà³jeG£Ñp2fÔ«gt !„{¾ßj·ú«Îëµþ [,¦“IY”Iœ"„NŸ<^Ve«ÕJÚmBX§Ó#„îŒÇ‹y'‘çùBˆñdR¡RºªªA¿ßîv‹]’¸®kßkAàœÎsF‹Ó„1R‹f‘Wç«9|ðÁç?ÿù»kë/xÁ À“N<yžßwß}ßèì/üÂ/¼ò•¯|Ñ‹^4Ÿpê‹_üâK_úRá7Müóïó§>õ)Îùë^÷º×¿þõ÷ÜsO]×gO>|øcûØÙjßû½ßûäæ»¾ì.;9×>™Lcív{wžðŠ+®xþ;vìƒü`’$7Þxãnšï³§:Îk^óšñxü4RȾá oÃðcûØ7ª°û¾à§~ê§êºþìg? xôÑGwoì.Ï}îs?øÁ¾ûÝïÞì]²dÉ’%K–|Kìn©eÙ`08O…–eY«ÕúOœ»¬¬¬œêþoIv~g*ŠÂ'F¨®ªº,Œ1±ÍÖζv6JâÕuÏ÷1›››Ðº´Ý†*¥¶†Û¡b6i’$Q¤¥šN§a­ÕRÔ„yÏ8¯¸¨)#,­‚ ÃÐó<­5F(ðìx4šŒ‡Ï¾øÙïëF!Œ£4ÑÎb‚Æa ±RJaœAã;XeYÑtE#ÃØc  )XYëlò¼pÎz>KZ1 0óXQ–‹l¡ŠæÌöIà\§Û¥ŒÔU5 '“I’$I‡ž‚`Ëy¶³¹Åqo¥ßIZ8 ¡S¦\d¯«Ê£Œ ^s»ÈæJ*¨í–ƒvZívšj©o€uÈÊ"?UÝ¡¤$„0ß§˜È¦qÎu’ÔÇ4Ëò²,kÙH#ÅÐcéÖ™dÐØ·³³=k*«Ôp¼³3dÙœBl pÖÙ8gyUUe©´Æu:B@`l­ÓFóZTu)›!¤Œ‘R*)}J¢8Jã$ˆ|ˆàt1³Ú¤qÒJ;QÔj¥%’Ò÷ü$‰Ã0ˆBoïúž••ž3º*Š|¾(™s;H¨çaj¤Zä刳=ãÕÎJèù´%¹˜M¦§OĆ!ű¯¤âœ[ëó¢(”oæsàÊϽúy{öî)ŠâK_úÒp´#µJÒV·êF"ŒÂYQÍç“Ñp¸XÌ‚(Üà@] mL#e‘—¡¶¸²:¸âÊ+õÞ÷¾÷æ›o ¿ýÛ¿½µµuîžO›½èE¿ñ¿ñ[¿õ[MÓ\~ù廯Ç{l7Qê{ÞóžÏ|æ3·ß~û{ÞóžápxÑE½îu¯ûüç?ÿ7ó7ÏtŸ«ªúó?ÿów¼ãøùŸÿù'¨Ù×¾öµø‡xêÔ©ïÿþïó›ßüäæŸûÜ皦ùÍßüÍ~ô£Zë/ùË»S¸<ðà—ù—o¾ùæË/¿ü§ú§ÏmõÔþ¾øÅ/~á _ø§ú§»q¯yÍk¾ò•¯üá?ðÀOCsþÄOüÄ#<òÏÿüÏO°ollüÀüÀý÷ßoŒyýë_ÿö·¿ý×~í×ʲܽKç.`ÞݽêÈ‘#_ùÊW–Ï K–,Y²dÉÓ ÓéÌçóóÑœ» ­Ûíþÿì|Çj§ 0`4gó¹5–yÔÐY‡¢z¬ÛïAŒÊºªÊ2Š£ÁÊ ÃºªŠ,—M“Wyè‡e»Ëó²¾ð°Ñz>Ïʲ²ÖEa ËÊhå1Új¥R«¢,Š"‡pW9;k¬çyœW[gδÒT+S–UœÄ^›s.„°‚{·¶¶6NAÆÞ4MÓX`˲,«²¿²rñEïÙ»¾X,t˜BHœ‚dˆRöÂN˜øœóE>_,Û£m„PY”³éÜ÷<Љ²**ä nt@}«M1Ï­²ÐAÕ(Ñ4g¶6³ù‚WU•ù|œË§‹ñxj!¨8œÏçs@Ó4#QÏóú½¾u6 #FiY–ç²iF¡¡>õ0„e^Ε”í$íu»qв.²¼®k¡$¡”Rù…„`yJªéhº‡¤.¥óhʪúÚãK öØ$¡–rxfzôÌéñd¬yC‚Æ€ ”ÀèœVÊ€!ò¨çQ1ßA ¤äuݨÇ):謃έ¤…15·ÖøÚc¡Æ‚†‹Üå€yAPˆµhè„V9‡-Èð9À…˜M§”kL@´®|<Æa¤¥ò(ô{%ežaŒŒ0y^Ìç )Uš´Ö××ħN>}êô¾}ûúý~»ÝIâÄF"THAà…‚p‘[;;Öêª,„A¶ZIœ${÷íët»˜²Ç{l<›„q'I'Ý^wummmm°¶Ú¤i²˜/NŸ:SÕýîw¿ûÜ•¥»œ9sæ‡ø‡oºé¦ýÑ…®¬¬ì¦ ú·û·ßÿýßÿ™Ÿù™Ÿù™ŸÙÜÜ|ï{ßû{¿÷{g[=µ¿ÖÚ·¼å-g³õ|õ«_}ÃÞðŽŸóœç<÷¹Ïý¹Ÿû¹ÿðë7Þ¸»PYñ›¿ù›OH2´dÉ’%K–,ùN†áyî(þ_Å7ŠëùíßÁ  §Mš¤ºÑª‘¼æÎ:‚)BBD “˜§ @bEQ«ÕŠÂ°(JS–!LˆÆXÝ(9t€ó: Ã4M˲D%•Ò½Vu=©ï‡aØî´µ¶Óé”L ¡„`ŒÂ0l_XC£>s`JZ~;Öº‘M#DY–R6¦1”Ñ0ð“JDqÐî´­²Që€TÒ€<ú>#Ì[å¹µçÑ4 ‚´eµ‰ÃhmeeYSóR+-õnBc§M#Äx4’²á¼Æ/³º.ÓVj]Gé ˲¢(µÖ¡VÚf̧ÖÚÝl)¾çEq 1Ú³woÉëÙ|:™Í¢ÄXˆ+.„àŒ’n§}øð%µ† IDAT³zÝÆ(Š¢n§m¬ £!T”åÎh8.#©tžeÐYkŒ”²,Šª®¥RyQøAÐjµ[ív¿ßOÓä‚ .èö:u]FQôÏÿüÿœ:}Ú8“9e c„ ît:¾A¸˜ÏÇãñ™3gFãñh<ŽÇyYLº++N»ÛïzߴíSpÛm·ÝvÛmOQáãÿø'?ùÉ‹/¾8 ÃÓ§OF£sÏ>ôÐCOñYOÑçóáoþæoþË?ú裗^zé…^H)}øá‡1ððäjŸøÄ'În¯r.o~ó›oºé¦Á`ððÃK)?𜧿_øÂ66680 †Ãá¹Û™œç y ¾ò•¯|£†'Ož\YY¹è¢‹<Ï;räÈî çÈ}÷Ý÷ô>}É’%K–,Y²äBˆZ mÎy̳"€e~Ÿi­BžÇ(¥!ÆXÍy#› }Ïãu=ŸÎ”Pcc4AÄ|/+²l±°F{Œi­s¡ïçU½½½ ꯭µÛí,Ë‹y¡”Œ£¨ßï{X%«²2®ãD«¬îv»ƒ•5Ù4'OßÜ:£µ²Î1EqÀ|? =ët-°àÕöö¦ÒMÚNóy#‚0lw»ÐA`œÕ†bê‡>A¨•¤Ð­!$ð<‚‰®©¹A Řb"j.êÚ'T#¬ À‰†k' ÀX-Á„ ÜH)•ÆIÜ_Y)ʲ(Kœ6¦i!¦Dò¦*ʺ¨4o´”Ê(í´MQ,ŠùÌEÑ¥—\ºÒïûWxývwóÄ™ép ”!)­uŒVÚZ[ßh·Ú΂ÉlVWG¡ˆ €€a„€ï{­VÚé´ ¦óÙ¢.k-`R)EVÚPD "Ï÷(3Ú‹Åb>WJø>;uìøb<^éõ’(&„FadµÙ)vвx”…Qx~·×ATuÕ4"ðüÙ|Æ9_ßX#§E#œsÎ9!„h±µŽ²›"aÌ(stzÝd”nvæyò&J;”2g5cÞê`õ ŸµºÒ«ªJJQäùh8Ì è€Ç<ÕȲ(=/ó½QúíV´µµ9›ÍyäÑÇ{¬( cŒ1Öc­õý`uu½Õj§Ikuuu:9räèÑcغªSJtM#DÃÛíveQÑdYÎN}VUeëýîÊ`e}}uuc½Ý[Ydç=ϹKQ»;Cþ'c­ÝT|eÀØ*/š€[çYÞ(Eq»ÓiÙ6r¨®ª€yiû„2Ʋª°ÎaŒ­Òóy¦´ª«Jk­“LB¡V0ŽbB1&íΣZc1C¾ïc„ÓùÌßôŒÒ‚N¯;žN²"·Î"Œó²œg ãl]V³q>ÉʼVJ- ´ØXf¡¬ê|4ùê—þÅruå•Wí]ßÓŽRg`–Ï °¢ Š:I²ßþ={â$ìŒ'§Nœ*«J6²ÂjÃ( Ã$Mâv»Õn·ZiÁ(ˆ&Ó‘1JH®š†bœƒÐó"g¬¨ëª¨§ÓiS×” ‡Ñt¸3ÁÉöNš´’$ ‚@1Ÿgœs?ð‚Àâpcm}eu%ÏòF edL#©d^æQöt'r¡Îó<Œ1|6›A#A)µÖ*¥Ë²œL§¼EQ4MÛf‘B;D‚n¯ !@À!²,+óBJ~êä©ã'ŽÏ§3ŠI¿Ó…¥g“©ÕBÛð²iÄx29szs6Ë‚íÿ—½;šåª ‡öÓûLÏ̳Þå¹÷f#ÉÍöŒÿQ))­(VQZ*R*¸oTi!…ŠŠ(V“J•ŠqWPY$,Ü„„»=ûìÓûé³¾<ï{Í/hˆ¨õ5Ÿ¿¦O÷é9ß¹Ïí™oŸ¥»Ý8N(åMÓEYUõt:oš¦Ûí(©)a÷­3Ò)¥•Ö²ªË½½Ý/ž<Š¢óÎGìȋ²`¾×ë¥'N:¹urm}mm}µÓKó²Þ8¾I–—¡¥¥¥¥¥¥¥¥¥¯cE–ö†{v§Ã´LµZJCÆžG ÷ãÐóýÅlvxx`¬ [[[ƒÁ@+µ½¿½xpâÔVÀ½È÷çÓÉh8Ê¥ =_;»¹ºvõ©«(¢ÁÝOš+¹~â ¤nåððЃN'M{=BH¶XL§`´‘j>Ÿe9/ò¼iX¤½ÓÆÙýÃýÐ÷×6VoÿÆoxøsmoo Ñx>×ZJÙýN/²‡‡‡ÖÚªªƒ0pζm+DÝJÇQ+DSÕãk½•k¯».‰:»Û»ãñh£ŒP¶R#C0 ­µÆXÇ„±NšrÏÓR…qD)a˜†AP&¥ìw{k«ë„`%Õå¢Ú†^àûã!ÄO¢Èçž³–cì3J9š—UUUУ4tNŠvž-dÛfYæqΟÍçEU9¤ÖÃÙd8Çql”nòJ–Â)CeŽ 0®Ì²a]‡aÈ(Å;gÕ„ŒPë\àûž´m+ššÚM1r€bâfÞ ­0§J©ZµÚZ'i XëTZQG!Sæqâ1 ÌúñcÚ¹íýýK~Q7šëÌ™[ÿÏ3ÓÁj¾È°”Òœ2Jˆ¨›Ùt^æuVäÛ—.WEÙïõú½^à§Nmuºq¿—rB몜M§£ñäãÿúoñ‹BŠn𬝝8qœbÝÙÞ­Ë 8èõ½5gŒÕº®«Éäp,›0¤4ÚˆV)Ñ £ ¡Ü*5Ëe]§c„‘³NY%”ÞÞßé÷ûi/íôS¥ÕîÞîÞîÞt>WÖ$AŒ1ÖZ%®û{EQycß8SÖUVdÊ?<ß§”)Ùîí{œ!°ºÐc½´g”,ýÀ0ƒ1 ‘Bü0à̳4UÅcÜók¬6c!džçbžåOºq¼È‹ùAxò䉳goì:Ø'Ńùh4¢áŒ«V‡aȹ§”ö}Ï÷ü ÖÖ×OlmQFwöv¿xñÂh<΋A·Ì9—––––––––¾ž‹|1ÏŠ¼TÚ J)D˜Pë\Y•Ól†Æ$A¸yl“36óE†1†¤i/í¦eYÎ&“º,“$é$ 0VTua¬Rª,K‰ˆÖúäÉYYB ¡R«íK— ìõûaZk¡sV+!@Xˆ1N’8I»”R¥µÕªmÄp4ôßÜÜHÓÎh¦i/õü! )ò‚x%ísNÎVýÍõµl¾pëºvΦÝn+U¿?ˆ“D)=[Ìf³YÒM¢¸ƒ¢5Ú«)&çc³f>œÏÇ„" ‚ X VVW´µ/^†uUɶÆaˆÛ¶µÖ:¡cm,÷}€ÐÁá°(‹‹/^ÞÞ.Ë2NB­–ýœKKKKKKKKK_×D-ó¼Ìó2ojä0¥;¨š´:G0æžF%DIå´© )%£Hµö<ž-ÝnwýØ`xxXÌç”î{ØÁ¦®ëª‰ˆ£Q*±9Šùü±G¹åÖ[Ó~/ð¼: ´V³Ù„²€3ê€kÊ¢“DA !òFdYV£¬ÓO#V×7ãžçýëG>2O‚À+³€1"Ä1ÐZQBå$«gEëÝUßâ(šN³Çþ‚–ºwà rðÐG5"Œµª•”P ñxšvý 0Zw»]Œ³ÖóXF)!¤°Ûï`‹­±ÆèÈ’8ÀŒ sç£ñ¤) Jãžq i…R@(•D„š¦É9¥¤%Bœ3Jϧ3çDØó8!L›‚§¤RJcˆ§~v’dm}íØÉãAèO¦ÓÙ㋺m²"·ª¦ÚªZì|ñ"Åôì-·®?ÑO{²(E-*Ù~áâ…Ñp8ŸÍ(&ŒÒÁú é&~ày¾Äqwg³ÉA1¾tùâ¥Ë¦Ó±Õz¥?XY ýN’„Q~1Ï qØ:Ž ¸Î‹Ø1cçI'¦Œdy&„@˜|ÏçŒ)%çZ©¤6Z;Í#C ÔP Ô¢ÊrQ(­)eˆPc]Ä~'”nmÛèF0@{Á`uà€-Ë\ E¸Ï=¯× «¾I©‡#)Z tÈ}? cÊZ‡TÆ‹âœw» çÞêÚªçyyQ lʪ§”½nJ“ª6Ze£iÂ1¶®Î !š´—¦„sR5ev)›-&uSž/¸×ÔÂ*í,ô=/ð/ ¥Ru#Z¥vööÇ£l¾XÌfuUi©€€eÎù?ïÖ[o½²Äùý÷ß¿ü@–––––––¾J4MÃ9ÿÒrÎyÓ4¾ï=u…’F4²RH Bœ‚,pÀÆ(B€Rb´ÉóÜ*íVCÔaŒm`1lš^¿ï¬ ý€RE–ÍpQ€dÓ(­”QB4ýÁJFYYT `놻»û½^…qCg ÁRµ¦Ôžç3JÚºš‡œRg­n[g]E¡átbœ;¶±¾¾yŒ2vpp0;Qèœi…€‹¦Îó²,­1>÷0Âõ¢RñõõþJ7M{aÉR‹¢i…ôIЉH§Û鯭Tm©¬æVU,ðƒØë¥Œ±ª*1 VIÕ6ZµÎ™²Ê¦œxV:!„–’b,%ñ£Aë0²® @Œs€l•ÐAˆ0"ŒB„”RMY5@1ÆŒ2¡Ô ¤dœB0Âa`°Hñ¢`íä&¸TM¹hƇûãa#[ÑN¹Ï¹Ç §¼ªÛñþáN| #ê‡aw`+·Çç³Å|2aOÇ„j¥ ÂÔgƦmçãQ/Mºýôºk®^]ë3JвÀ"€ƒMYic÷ÒÕΩã'¬uMU)­¦ãq¾˜wºIoµßIcè,„.é§«ëŸþôgš¦)òY>›+%&"xvaòEcÓ^BRVgÞt:šNÇ­”£F¶B„@ÈCm”RÎZç\S×qrÎ&“Q¶˜sÎúý~¸¾Áƒ ÅBˆ0Æ[cŒ±œ² `à‡€Ð9€1q”UU×"D1)I0ê$±ïñªª¤”UY4uE‰ƒb”Äáúúzš¦aœ?þààÀ1)Ëzÿ`{{{2;¢(L»½Õ••À÷³YÖ§Üó#m”jwgçp<ÑÖöÒT+½ur+ ün7I¢ |`EÜ÷¡ÃU#ö÷/æób|úÌ™••~7í =„Üh2 8ë$Ià{Ö‚ýƒáîîîl‘ic(g´Ûô£¸­´À‚ü8ôñ±}úß,Ú*éôÖ××'“¢®ª"?ÿøc­hn»å–ç½àù²V«8’0˜ŒÆŒû¢K/-f¹R6 £S§N¹úê0ò9'aHÕ0JF„Î=„p]×cîqæqѶÃÉÌý€yžŽ0œtîùi>Ë›J[Cæa €ËʲU{< üF*æÌ œ3ÖYc±N+SWMDØ€j^@ˆ)áM^cBcœQÝt8qÐXc …ÖÚ<ËE­0&ñ„¢i§z’/Цª€ð0ŒÂˆ ,d;™N˲ô}îâœçY^–Z›•Áê×_·±¶:Ÿ/„ªÕY9b/+³áŒŒFãát2¢À­Ú:[X­Äl15Æjm®½öÚõõ àÇ?þ‰,Ë„”‚²n0Á]¿³±¹qíu×m;a¥Þ¹pébõÅݽé¿möò—¿üŸþ韞ùÌg~ä#™ÍfúЇn¸á†']ï¿ÿþù|¾··w×]w]™²øtê>…n¸áÃ_b}}ýÊW_}õŸüÉŸ ‡Ãétúñ§OŸ~bõÓ§Oßÿý·ß~ûë_ÿúK—.F£?þã?¾ri~Š6?…4M?ð¼øÅ/~báÛÞö¶7¿ùÍG¯O:u×]w=òÈ#‹Åb{{û®»îZYYyšñ¾ô¥/ý»¿û»+›gÏž}ÿûßýõ×?ÍxŸýìgÿÃ?üÃáááp8üð‡?üÝßýÝO:Çßùßù‚¼à+¾.ƒïüÎï|÷»ß}eôìÍ7ßüÀ\é½ü›¿ù› žÿüç/,------}õ³Ê&a' âNÜ x,hë¶Î«&+Û¢1Be°uÑÄc?€‹ì`wowo>›WE•„ÉúêúêÊZ§“ræYëÚVey1OG“IQÕ˜Lˆm]ÕZ*`¬¬…U:àZ;ŸM‡ûûÓɘ´uêäÖÖÉ(­5¾ïÇa>v1›îmo7E¾ÒKWz½Õ•Á ßçŒ-²l{gçü¥ »‡ûeS[dgó‰Ñ-gdssýæ[nú¦ozî žÿMÏzæÿô{,£$‰ü8òÄB°¤ßYßX9¾±zfëä3®¾êšÓ§Äöé IDATOnn®õ'76®9uúº3W:v¼ßIÄmÙèZ„Ü?±qüº«®;¾y<ôñ^/ÝØX¬ô;N·Û%„E1Ïê¦Qw’n/]Û\;sÍ™k¯»fãØz…GÃ5)ÁÐYg %8ŽÂ´›t’8 |çlý^êû\4Õèðp1›Šº*‹<Ïs)•6veeíÔ©ÓÇVV×¶¶NßtÓÍgoºùš«¯ Ã¸(н½Ý½½ÝÉhŒô{ÝN"[1 aQ¯¬¬ž8qbcsS*upx°·»—e¹çûgΜ¹é–[¶N〈¶•m«¤µàÜo¥Þ?>úèãŸ}èsçÎ=º·¿Ÿe#[i´²v^fó2«d=žOvvFûó|¾{¸ß(i14¤³¥l ÑHcÂ!•±ÎAØ*S”M–UJŒd|0<÷ÙÏûÌC}üÜg>÷‘|ðãú׋_8ß,*‘Õ{—vwÏoFu^[åŒ0MÞä³r>ÉòY.ʦ­…–J 9ŸÏ··wüñË—/ϳVÊFˆé|¾³·wyggº˜+£FÆY©£äºë®zö³n»ù¦ë7ÖWvy±ÈòÅt19î_Ú¾pñòy©Å™«OÝzëM×\s&í&ÀÙ4£N'Y[_ÛØXë÷SŸ3ÙŠº*Fi·Óëv(!¢i꺚N'ΟÿìCŸ¹pþBÓ4ƒ´ÿïýœ'Ož¼ãŽ;ÞñŽwüÁüâo|ã½÷Þ{Ûm·í½ñÆßÿþ÷ò“Ÿüáþáµµµ7¾ñ×_ý ^ð‚£´ä©ë>µñxüŽw¼ãÊæ+_ùÊÛn»íÊ8Ï­­­}ìc—.]zík_«µþéŸþé÷½ï}7Üpƒ”òè€0 _ð‚¼éMoJÓô÷ÿ÷¥”wÞy'¥ÔóÔm~ óùœsþªW½ê¯þꯎJVWW_õªWýèþèÑæ-·ÜrõÕW¿ímo»páÂæææë_ÿú[o½õöÛo:ñž:uê…/|á•Ín·û-ßò-NçéÄÛívÿáþá("çܳžõ¬³gÏþÙŸýÙÏ¿µµuß}÷=øàƒÏzÖ³¾²ëò+^ñ BÈÝwß}¥„RzeÜ,àhÔÍ3žñŒ+³=¿ýÛ¿= vvvî¾ûîüã˯·¥¥¥¥¥¥¥¯“á”1ަ„ZeV@LæE”r¦•†Æš¶­u£Z œöº©…àØÉãÚ¹¬Èóy.r%U]ׇeU £†ˆÎãÜ÷üÀ=6ŸÌ§˜bJpkähtè…^o¥ÛéuÒ^7I⦬!cˆ`Q³ét:[­Ó­’ÎYŸ³~·+U3Œ…jƒ0(м×í”Ó)EPIÁ‰Ã ŽÂ ðT«pÆÆXšvVVV”RÆ:¡sÎXãfª6ö{²UÙ"k[µ²º2è­8ç&“ÉþÞ~–-â0ÚØX“$|îñáááîÁ> ý°ÛŠºÁ…aPåb® Bœsçó}ß·Ö¹ ½À3Öjkª²æms4˜—R‚1ò=Ž1¶Ö !êºrÖ Ñ ‡‡m+”R“áè±Ç«ëZë"˜RÌ|Ïǘ"ˆ‚ ì÷â‹.^¾¼çyÓ4Zí,D8ívmìt»ÚØ2/üñ´Óé÷ºSà.çù'þí“»Û»RȤÓé&½õÍ«®ºzss3 ,Æa8ŸOµj³ Ve)M«Á”†qÔM^—Zɶmê¹$œÎ)Z)YèSß[”y%…‚Î`èœ]”(!”3v¬j[­5ã\+YUM+c”øD[íŒuʈ¼’¥¬+1-zý·jL«çó©( ôÃNØ ‚ :ËË"«ÊªÐÅIö»бr2ž!f½~štºÝ®ïû:g-,¡sF)Í™‡dœE¿¾¶2FFæ­&ó±V9µÈ»X¥e§›¬o¬¥Ýn‘/vww”Ržça(„¸|ùr]ÕZ)J°Òš&1á×uÓ4;;Ûãƒá|<ÙßÛõà'~â'´Ößþíß~4œ2Ïó»ï¾ûùÏþ<ðeë~ÙœóÝï~÷Ñë½èE·ß~û÷ÿ÷O&“£’7¼á Rʾð…yžxàK—.½â¯xbš  Ïzֳ޳·¾õ­G…_¶ÍOáÞ{ï}Ë[ÞÒï÷§Ó)à%/y‰µö=ïyÏÑÞ¿ú«¿zï{ß{åàétzß}÷={öóŸÿüóšøÔñÞrË-½^ïñ?ùÉOþæoþæãºüC?ôCÿüÏÿ¼½½}¥ä±Ç{æ3ŸyeóyÏ{à‰k]¼x±Óéc¾÷{¿÷U¯zÕ+_ùÊw¾óËo¸¥¥¥¥¥¥¥¯`ÓjLÂä &qÂ(Æ„AL)€@bé¬Å©V"ë<Æ=w{½tÐk•êzóüÈÃYUMm³Î6²MžÅÐB T«2ßk«ªð}Ÿ{Sê”2Ö•eͤÖ)¡d«8õ/¤wÃPuš‹íÅñx^åv¨Ä!•P“áÄy·“ll¬wÓÔ»›,¦Y™×;‚\ø~ĸáÏçsä@+DU”ªmsÆ* ÆÈYØIºŒÑ(2MU#ˆeÛ*¥¤TuÓH3JV¢ît’8ŠÂ8fŒ'qÌ)­Šr2·BTe‰ URÕUgyÛ ÆY[•B4ÌçÁ8 ‹¢:88€ÆéF2ÆÛ8~b3I;OžÏye ßc=ØØØ8ÊŸóœç<ðÀWæïýõ_ÿõ•Â/[!¼²†µµöJ/å]sÍ5÷Þ{ïïýÞïÝsÏ=W ¿íÛ¾íƒüàæææ•åÈ._¾|ë­·>©î;ÞñŽ/=çÓióæOÿôOçw~çÎ;ïüÃ?üCÀË^ö²üǼ’ ;ç’$yñ‹_¼µµÇñÑÀÚµµµÿ~ÎùÔñnoo[ká~áÍo~ó§>õ©ÿp–ÿ¹sçÒ4}â‚@ÿ%Ï}îs¯¿þú7¼á O,|ÛÛÞöîw¿û·~ë·þìÏþììÙ³¯~õ«›¦¹²žÁ{Þóž+w z½Þý÷ßÿÖ·¾õÏÿüÏ—Ó;—––––––¾œ8¶eµÎQB¥heÛb!bŠÑÑú7,eŒRh\6›sL»Ýn†Q’I4žM›²Žò<pæmÄÆjc¼N/•¢mÊšaŠi¥ªªºÌ L‰Qˆ VU>±G¨çõ×Vúƒ5£Ìh42eDB¸mšl±ØÙÞÃpmmµÛë"‚u#N®oöVy™Gú,œ¶eVB¢i¡+,&Ã1‚Èç>ÅTµªªj¡!L­qÎ"„-ãù\µÊj'dk¨­>\LÖJj A ܼ®ÄÁ^YÚè(޵R™¨%tÊ(çœT’1Ò4µRJ¶ÒYkŒ©›Fj%ÛV´-Bȯ ‚©”-c à¬ÁRJz½ÔZ»X,Ú¶ÕR:cŒ1óùl<:k1ÆœsBq˜P)­u!,¥l•e‹üüùó£ýƒs?\,²È TZ¶ªEX£!tŒ`ë5fog¯.JFÉúê çÞñãÇõ6V׃EV9à¸Ç{½^ÒIQ/2™ç¹µ&Œã^¿÷<Îy†Óùl4ŸÒÇCŒpÆ0%€"ÌH€"@±v:+3‘c€5Æ8 Ã0Šθ”Ò—/2-5#Ä1ïÆã›'Bßë†a1Ÿ wóÙ¥¢,ã¨ëaª™É…lÚ~¯ÛOkƒuîyÃñø`o8 b¡†¡×éiœt“N/M)aUYM&“E–åyŽlꦮ«FÔÖ¹ âNljç1 Àt<>ÿńβ¬iZ„0e\Ó´­*r€0F)mÛ6/J ‘Ç|Nx6ÏE%µM»)Æø(á|OiYW¥¶Ú Â Šœ5uYc€CÏOÕ {û¿Ÿ•Ò¶­âèõQÒB)½’K|ìc»räb±PJõûý§Spûí·ô£=z}þüù«¯¾úIׂ(Šî»ï¾Ï|æ3?õS?õï7¥0 /~ñ‹_ô¢=ñà/úè>úÏü·á‡ø‡³,»ï¾ûžXx÷ÝwŸm[!dùž BjÑÙk®¿êªÓ»;>øo‹y6Í[!’¸“vzM#6Ö7!ÄR¶Jj«,÷¹Ñf:™)- !´»?<<þ¼lUŸ“¦xãñtx0TRyžïCF£^!䇄ðäU§ÌQŠÙ¶Jµ„cŒµ–q¦”2Îöý¦iœó8Šâ$±ÖΦs­M¶XÈFkckkkZë¢(ÑH)1ÁÆ!BÈ:G žïsÆÆãIUÌ‹¢( ãH[£ÙÙÙ9w®˜OÇáN·ÛM†I]•GïëŒ^̦m+f³|ootxp°»³-ÛÞ|ÓñcÇÏÞ|óúê:§|çòîb^H%fóù£>J¢.ŠE]”âõc›q·E‘hÛÝÃý,Ëf³ÙÎÞ.¤ÄCѶ¢® Å„R]+¥Öº“¦˜’,/²,³Ö¦izjk+Ž"Ñ´ÃÃáðà€b2ŸÍÓ¤{üرNÒ!¯®¬œñ¡O| ÖÓ‰÷ž{î¹çž{Μ9ómßöm¿üË¿üž÷¼ç¦›núŸº"'Iò=ßó=wß}÷•ÛWbyÃÞð†7¼Á÷ý¦i®»î:Îù#<òžä¨7ø(_ZZZZZZú/ùÈG>ò¿ú¬”ÍÍÍ3gÎ|é ­µG©øZ|VÊÔ³ñŒb¹gŒ>¶¾®¤²FwâxÐïCà:Žç{Bˆª(­Ôi7Æ¢•yQdE6ÐmßÚ8~"í¦JÊñpÔ ¡¤1Õ¢½´³ÝU«4…!H8CŒ'ž5Äcƒª­PC›V\¼|{Q¿zÐ[AŒ·ÆƒÁúúgÌc¼® ä€jڪ̥”—»0Ú=ô‚ Y[!Bäâ°Ó {+›EQªVGaL ×Ú´B´²-òf±(“N'ˆ|ˆ "h-àœ¯n¬Ïg m$xeu5Ž¢Ãḑ-t€ûþÆÆFš¦ÁF4¢©•Ö˜`â1FIàs%Ûªª!G¿r뺑R1ÊüÀ/‹ÒXíy< Bs熨m[ aÍjŒ±vv{wGÔMžçc/𡀌²£5çÆ8ŒcÏóê²´Öv:I7] ¢À:[•ù,[4B‚ `„®úýnÚÖMS•çÝ$‚OÇ£v_ÏæÅx´µÀÎgóË—/3JŸñŒëÖÖÖ´2R«y6kyiûRÓÔiÚÀ0†kÎyÒí”uµx0ŸÏ'³Y–gBˆé|6ϳEU8çu±2èK­%˜-DQU~ŠVÅa¼±º!R­ÄUEÝÔ506 㺨VÒ£zþÚÚÚu×^{âäÖÞöö#=´½½+D뜋âdeu­ÓI=Ïó|Nišz¶˜@!BZ›~@(ç<èõ'Ž­m¬öœU²‘eVÎgÓºªƽN2pÎhc¥¨”•¢™‰y+„3Æ'8‰cB)ó}!%Ì÷ÃÞ`pÛmÏŠ¢h4îíî§ aŠñ:kµ'NœÚZ¤T†Û0ˆÈêt:I·ÄÑîþ~V”F©µ•U£,Á!ìy>Dxµ7>ÝœósŸûܳŸýl„ÐÑâ¥ÏyÎsŽ Ÿfõ<Ïï¿ÿþÿlïÏÿüÏ¿èE/zÞóž7Ÿ´ë£ýè _øBá—]øç¼Íï}ï{›¦yÉK^ò²—½ì¾ûî«ëúÊ®«¯¾ú]ïz×QÂy”s~iõ£XVVVžÔd2aŒu»Ý£~›o¾ù+ˆ÷Â… ¿ÿû¿ÇñßøFŒñ•–Ò4½óÎ;Çãñgœ>Mß÷}ßÁ»Þõ®ÿ쀣û?ò#?R×õ>ðÿð˜oú¦oÿßøê¥¥¥¥¥¥¥ÿ’ÿÕg¥´m{îܹ .|鈳 .”eyûí·_™ õµâ)‚º" "Ji„J¶Zn€³¾Ç!‚mÛ.òÜå„CŒ“ZsÏ ƒ@J}ԡ׉º˜QL©‘ªÈr£µVFKm”Fj©ó<3ʦI' ‚¶nÊ,tÒdH…1Hg˜Õ"LÈh4i¥íõVbQ’l?ÞVµq ´¾¹A0>ØÝ)óBŠF i.fY•£Åhr¸½ RZ§iÖåƒþJ+$pp±È¦³iU•RIÑmŒÒJ´Â9ç…žqº¨J!Å´,Ê .„~ÍœPBˆUz6™”yA(†J­ªª*« ´ÁÐ))›¦aŒaŒ9÷œcß÷˲ ‚ BJ‰ÑzVU³é¬ªJ‚‰1¶i„R*Ïsß÷!„£¬Õ:g¬±ÖRJÃ0L’$Žãº®•Ö~ D¤r!…”BI\ø˜PNYȽ8ŽW}ŠIEÓé¤mEVΔÑc‘ïù³8 ;H)µ³»Óë§qO&“ƒƒý,Ïe«G£ª*©$‰öʪ<ŒÆÓÙb¾he«´Îòl‘çeUUaŒáž·ÚKÏ\uª,Ë,Ï!”RŒ1`¯×£Ø;Ÿ-FÃ!!Ä÷}ä€3Ö£lã̺ïyÙbA0öMí £(é$žø~ìy¾RŽ D)Îæ‹¦*(&c­$´Îzþµ×\]ÕÍl6-ÊJk%˜*£¶ ÈVÉEYsÊ…ÒÔJѶ˜1kÁ|šµBG³íí}+UÚIÏ÷Å` BIÒRdYaµíu»i··2Dq¬µšL¦‡õx¶X ú. BÆcc'”PÖM:O7ç|ç;ßùÞ÷¾÷×ý×í×~muuõ·û·÷÷÷ŸøÌ¯Øóž÷¼_ýÕ_ýÍßüͶmÏž={Tø…/|áh¡Ô7½éMï{ßûîºë®7½éMÃáðÚk¯}ÉK^ò¡}èéŒÛüo¶¹ªª¿üË¿|Ýë^·µµõs?÷sOÊf¿ç{¾çþè¶··¿ã;¾ãÕ¯~õ—Vÿà?ضíoüÆo¼óïÔZò“Ÿ<êÂ}ðÁ¿ôK¿ôk¿ökgÏž}Ík^óÄZOïóŸÿüç>÷¹þç~ñâÅ“'OÞyçŸþô§Ÿ˜pŽ;öö·¿ýÁü rÎú¡:wîÜ'>ñ‰'•onn~×w}×<`ŒyÙË^öÚ×¾ö—ù—˲<ÚûŽw¼ãýïÿÃ? øöoÿöŸüÉŸü—ù—Ï~ö³Ëß KKKKKK_U8ç×_ý'>ñ‰/MÏö÷÷¿á¾ák.á|ê ®¸é†)ÅÀÁª*ÖYk „ MÛ6°PJ•”J´È‚8N¢8è¹~ÚïSνÀ—Ú´R•Y¡ZYW9çSÏyÈG)vK[e¬ÓÚº½~ÕTÊjˆ@„­Q€@ŸFšéhÖÖZ|üØæ™3WUy^åyÝ NðêÚFp:‹%ØY‹´Æj¥ÊY¶˜Î+)¸ïÍg9´!œv{N!kl%ŒòNÜ£aŒ ªD5›MZÑZg1A”ŽHw“( ¼ ÈʬVHŸûŒr-UQVÎYT²ª«VJÆ)°A`­UÚ¨¡6Æ ¡„Pp¿ÓébŒ•lÛV4e=Oó|†!&Ti£AJc¬g˜2¡qÎ8¬ <ß÷}îy„R¡TJj pN+m&Öj„!ÇÔAh­…$ÝäÔÖÖÆÊªneSU»»õl6«š aì…‘ïyB­í —v»‰”b2=rîa” b&®ÅQ÷¯BÍÄlf¹Ï´QRªñd’…TJ´íx2–ZEQw:qGQ¤‘ÚLgó²,=Ï[¬ „”Ò²@FéÅl>1&ƒ~?ít»#tÐﯮ¬îííåY¦´*ëòü…óÀ:Ïó6OG ñÒŤŸ&IGµc½~¿M~¸ãù<;'N?¹urmm=í $óy^d¹µmë8òµÔBJ0B@ö<6›nïì G㲪•RŒãœ5@I¥”†ÔIm÷‡ el>ÿØ»ó`Ë®ºpôk^{Î9wìN§;d0„éE„ðCü*,‰ ˆU‚TY ‚à@a•…@ñ£¬¢à•TbJŠƒüB™0¿ŸˆAÈ`HºÓý}‡3îqÍëýq}m Âäë|þÚkíµw×í{÷9ß½×^«9þÀ ˆà|6ŸOæQV‹¶ž·ƒ2–%¥´j+L(vÖhÕ¶E˜j#„”EQæÅé3[M݆¼Â8àašfÃá(æ!%”á#Í9?úѾá oøýßÿýƒ÷-?þüç?ÿß%ûýºêª«B¯ýë_ÿúן«r0¸ôôéÓ¿ýÛ¿ýÓ´ž9sæ—~é—Þò–·üò/ÿ2„peeå`Ðé׿þõ?û³?{ík_ûÚ×¾vkkëmo{Û;ßùÎsG=|s¯|å+ßò–·ïºë®¿øÅ?ªKöcûØÇ=îq¯{Ýë¾s¥ôÍo~óÁ@e!ÄÿøÿãüI†Ž;öWõWÛÞûÛn»í\ðKKKKKKKÿ©Að•RAð_¬Sçüôÿ7F¨6jQ-ööw›¦iE×Ë^Í£0Œ"ЉÕVö}×u“€Ö{ÊØF–å@( ¬›¶ªk-”è¤êDš$i”d vEšZí´1²ÞzF9BØyŸ¤)À¨“½G€Öt­ÔŠ@BBÏ÷g ò4ˆVWWÒ$UBLöÁõ••U¼Næ”uAèŒõÆ¥¥BH«$Ø_Í¢—À®î«i£”ÉóŒR†0âa˜åçÌ8Ë¢ˆPZ–Yže¢ï "iœ0L·Õ¶Š1Äe„A¬±NHcÞ8­(ãB€×Ú ¬¼÷Ö:m,B{ ‚Ð;ßtu×´Vig-Å„Æ0ÅŒ ¬s!ˆ÷Bˆ¡Œa蜋“„1ª´Ó)ç\Ñõ½1†`Ìg )`㜠BÅQQ”„ùt:NÆã±‚3ÆÎCÎCÞCg€µ#][ïloçEQ–ìÈD¢a1F‚U3ïû†<Šƒù¼žÎ§m×I¥Ú®«ê*Lâ$Ïò<¢ˆs>[Ì'“iUÕ”<ͳ4«ëf6ž)¥’$ xàŒ…(!û¶Ë’”1žÄq†ÃÑP*)¥h»æÌÖ™¶ë¢0¼ô’K…Uµè gé Hó²È˸ÌQÀŒêh”Ã2I“ÁÚhusýÐÅÀÏãh0,½VÐHä|×´ZkÎhÀÙÁèNJH–g˜Ò0Чóùb^)cœóÖ­ F$KcJc,B©T"o­«çUÛ¶]Û!9 D×uM ƒ8&ÔXsX\ IDATŽâÄ[ œÕÚT‹j2™RFB”Œ1ÁÈ#¥´ÖQÂâ(ƒH+Y-j8™Lá´:€4Mõ¨Gõ}ï½÷ XýzÔ£EÑéÓ§÷öö¾¯cL1B.½ôRJéÝwßýmO‰C‡­®®Þ}÷Ýÿßß /¼puuuww÷üåL~Ü(¥—]vçüþûï?÷„󜕕•ÍÍMÎùƒ>x°ºÌÒÒÒÒÒÒàž{îy$ÍÖÖÖo{ÛÛ^øÂþøÆÖøÌg>óÌg>ó‘Tþy˜øßö¶·½ä×^ÆìMvÿñëwíìíÌ«ªS½…nu}­ &{ãz^©®mc–yž'ÙêêêÆ¡Í®—ãñx2›wm×µ]5¯œ2k«+Qµª•^QN«ª'ÎJ)ÄØC€0΋Ây/µ2ÞZoöö÷ª¶ qwœLª0 ³,Û8´^–…ÝîîîÑ—]¯óùx<ÛŸê¾Çjiú¦•B:HôZJ©º¶sÆR‡MÓ3ÊxB8çŰHóD[-dç‹¢(ÏӵъQÚjC0AŽwö¬q@θ’j2+£•’#r¨‡À{O9µÎJ%»¾oÚ^Je­Es΢0Šâ8b¡}Û4F)Fhx­$€qVZ÷]§”"„&i…!„P ©µÎòÌh=ŸÍû¶¥”ZëÆQXä hÝõø0Ž1eZèá¡õÍ2ͽ6ÓñøìÖÖîÎNòrP2Î<€Î¡¾1ZYˆüêú¨(3eÔl>_ÝX[]Û ˜im¢^ô#!![„ Æp<žÎæsm,ÄBhͲoÚ†QV–e9(‹¼X_]ÛØXŸL&[ÛgêºrÎ !‡ÃÁ%—\RwÍöÙ³R(Jx¥Yv°®&´Î2Fx@ ôi’¬®®®¬­…Ad „ižq['•ôÖq΂€c„¤R)gm]7ÓÙlooÿŽïîïkmz!»¶‡À_|Ñ‘ ¼ó³Ùüôé3ÛgϦiÎy(„œÏçRÆyY–mÛÔ‹Š2Z–E–§”q 䫤“¤Ñ`0@g““g¶&³D„ó`}eóâ£=r”!Ú5µ–‚|_Ïu]¬ ùÌ9÷Ýf¬ùÿ+fcÌ`kkkkkëëïÉ“'Ož<ùü_ µ>=ûïÚßßÿÎwq—–––––––þ3èûÖYÓËþþûîûû¿ÿû¦oóQ™”¹C Qrç[÷k¥#dÃ2ËóÅxZMaÆÎ-ªºiØÞÙ;s挒:˲4Jò8ËV¢Q9hꆰH2™N¶N<4™Ïe4 !"Ór8 £Xie¬6!:F™÷ÀC¦k1ë$2j&áp0$FCDĨÐYPÍæYœX©cÜA‚Ç®wÐyƒ‰ÔÖEI¤<`”²¢,˜·}#°ÖJÕ/ng—QŽ!â„ÆAD0‰NxÐu]SWQy`Æañ8Àc¬wgwvÚ®³ÎGQ†‘óÐZ °ÖwM#\×-E¸(‡q0BÆÎšYµÞ[œÊXã|ÈyÅAzï@E9pεmïŠÓ!´X,¢$Ý\_[[śͦÓÅ´“"ŒƒÁ ‡O÷';{gï¿÷^ m@)‚h0(ƒ Ȳ”0ê¼×Ò‰Z1‚…ìú¶ òÍÍõÃb_4Mk»8Jó<ë…˜œCàâ8 ͦÇ?Ø÷ÂP–ƒÕá(-r!e×u“ùt±¨!‡Z[YõîíìT‹fgkgww¯^ÔyQpÎ)&ÖXFÙp8J³ "F!ãÜ#ЩîŸß/¤”NЬ¶$¢‹¾ù»/}Î#˜æyšJ¨Ö*×·ûõÜ9—eÉF±Ö«^Yõ‹q5·ObBCI𭔣aVÄ”9¥“4eG„ à£HáÚ‘ÃF›ííñ|þÀÉ“B(„£õµ²È®þ©+†eáœ;þà‰Eµxà´2E^zVGCÆ8„0Š"°²R·ÍþþÞÞxoQ/Ž]|±s`±¨E×:­°÷ZÉÉt<žL0!ø‡kkAÝtZ­U×u{»{ZZ`Mr²¼ ---------ýö¾ÿû½Ðê^F&Õœp®éDo Ç ÒhDœ0ìЖaR¦Å0/@mÓJ!ƒ 8¼±†Ñh8J¢„B\$i†[[[ÖJt±X´ am¯”’ð MSÑËýÝ}m „0M“•ÁÈ©”qÆ" •¢0 "ÄúºC–£AœÆ‹zn­ãœC‚FÊ3æºÞHYWMVäåz±¶ ¤PÖxÆk|]7]ßu}ÅAœ…Ü"ï,¥8NÂbP$q¼uú¬èÄÎÞnS×bNx™åIGah­ÕÖBŒ½óh$2`0@ÆYbPJ;ç•R@„g§ AÈ)“‚åQ²¶²’Æ!ôØwít6—Já0¢(ï}Œ1ï½”ÒÃ3Æ@ã$ŽãØ(­”Z[[»ô²ËZcŽ'{ê·vvú¾Oö!@³é\ …,ˆh@)£„À€QJ &«M×ö²ëvÚikb£•3vmcuóð‘3Û[»»c¥UÛ·Ór8˜Í&§¶N×Õ¼ï!Åp4*ÊA‘£y5ßÝÝÓÆDQ<Ò4=x@=Ù›ìžÝmê8€<eQ–Q#Œ !QEIìœuÞc‚1ÁØ­½ét ŒBišííí‘€'YfŒí´¦[âóC‹ÜÙñ.„Ž1 jd‡1ç³x;ð0fÁheXä9#!H0Æо/Ëáh4¢”O‹í½Ý§NYë6­¯n¹à²+}ÁÆaôÈÑ#¡éx²µu¶ïZÎxij£ÇŽ^ré¥QœÜwß½÷ë[Î[ël'Äd6’Ä:ËY—ÀÑí­Ó»g·6ÃÕQ–fˆm\ß)¡U×öãýI[õÐã2ϬÕËœsiiiiiiii鿲¿ÿêÿ‚@WÖW-òøNô  4âAÇILqʈ¶W]Ç .‡ƒ2/ÐÀ<Ï×VÖ e QFu¢k:Ó+'µ–=¦¢‹ÉÒt<ŸïŒ'­‘ Ó<-„T“ñ¤ïE ᎴFK-5Å4Â¥e‡;¨Ñv±?išÊ9k/Úšdˆ0Ï„Tcq”e"mDã¬È}/AÀ{c”s YJ©º­OŸy(ˆ ( &ÀA·yá]+Hª^0BU')¡E×yï1g’Bö,ä!OÃ,Å·]×w½¶"FQ„ÖXc„rÆ8ë¦çq Š" y0ŸMgÉÜöç sîŒQJ ¥{!µÞ{J袪Æ:Œ±u^H… M²Œ\*)¥‚Èe^uõlQÇ{`pGy˜äqÊ)ƒ„¼uÆ©e×¶³Éh¤•1N[c¬1Rжëpqi£·Ïî:ïGÕrPh+öÇVjÆáÑ‹ŽŽF«A !öÇûû“}mtœ&Y–GQB íº®oûÝíݳgwú¶‚°ÈòÍ$I0cÖyˆãŒÒK-•²Â:ï ‚yYŒVW’,a7Ö(­hÄ¥SYc¥i+¥¬^C¯do´ÁAƒ Dyà±½è{ç§œ1Žk›^÷*"Až¤ãj† ÄR‚ ÁÀ9­u‘—EžSÊ«º=µ½Õið1â1’Fíìž-ò$0lwwçÌÖéª^$I4,Œ²<ˇe±2`Ê­3RõŒ“’—@\š¥å`pé±c9ÂþÊ—¿ôµ¯Z!gœ ñÀ`L¼mÓ7¸ˆ‚˜3jXæœKKKKKKKKKÿ•aB8ea VGC}˜§IQ˜[Œ±Þúˆ,$UodÛd²ÎúEe^äi±21ʦ"«Íb:3R®”¹êg%&ÄPõí‰Ó§ÝÝß<µ½m¤ y¢”ˆ8ã8$´™Î¬±ÎX‡iDE˜Ä,ð(§ªéþ¸­ƒ8Ç ‚°,JÓ+Ñö 0JåÆJÆ"p2™¶mÛjºz¶àaP$I$‹ªÃ„H#¥MÛÄyÒI¹³;ž-»{ãªn<Þ8JèÆæÆÆÆá `BôûãñÎîBÈ8 ƒ8ŠÂ( z!ŒRU]#D¶m Ø<|(JX–!uï„Aa„âI†aÌ9/”0Ö@ŒµVm×¶]ã¼eœ†„Chz %Ä[ µÀ˜`‚½·Æh#]S/‚AÆ(% "D(“$ϨŒD5]LöÆû“1Bè!h›v6†ƒ};•BãÀ0Î1Õ|>·º«¦;[Û²ï'û“ÉdÊxP†Ã•µÍÍCÞÚû¿õ­oÜ}÷îþ^Qæi–e'&xÈXèÞ={Öô½1zQÕÕUkmÝ4Æ[‚I’fq”äI*:E‰‚8ŽbÊÈEYæœ?z×\sMQüËÅôŽ;îXþ@–––––––¹ÝݽյµŸ”h1Á§OŸ¹à‚ÃÅS§Oò¯³ìÖuý©ÏÜþSW^ùäŸùÀñ'>uûíϽþYiš48HM1UU}ëÁ?úñ¿}ÎõÏJ’äGäB9軜“"N1ÁJ*@^ä!œ’í~¥[å´5 Õ!˜€aª=Ðq¼Ø™sŽÃˆVGŽn¬Å,DÀ£„C€£Ltq Óv²º÷>á@NƦI§ Å, Ó3§·¶OŸâ$H¢E×´¢ƒ ôØ9æ½SšH8È dP‚™ÇeT4mÓwÂ9 ²][_-Ë‘‡ØhÍÇ”´mD,Œ0Œ¡”€Ài)‹&̵˜/ÚymZQ'Œ–ûÛgË¢X]]‰ÓŸÆQ”ðySw²Ã`c}mo{‡{Ì qÆYkD€Ö Ì8w˜ ‘]Õ{¥Æû»ÀÀ× Dç\I…áAZÕ¶M×I„a1( FÖYBpFãñþÖî¶VšcPæ¼÷Î+Œ„ÞLiÂÓ,ɳ¨ €z @¢•ÕlÑÕ…8*y2̃¨•F×}=›O'Ó ÄØzöìnÛuuÛy“4µÆ-æÕ zƒ¬†}ï”Þ3BI’$QÈ1òFiŠPE²ë¬u“8Ž!Àë››išv}?›ÏOïe³˜¢„sN)¢$M2©Ìx2­ûNkm=°V# £$AÈa„¢˜à‹JŠaN1ÑF9#½ !ÆÐkoDH³,IRŒ‰R&Š¢¢(â(–­DÌgó Š(¥ÅpG1"t2u¨«Fô"àÁ  qˆ±J)…ÑÒöÍ£®í¥ÎÃ(J!¢ÓYå<’Rnïî ¥g£ºZÄ1Ïׇyž‰^)åö··¼ï>©¤÷¾(ŠÃG. „ð8®›ZJšR‡a„SÆþ‚ë—]vñ2çüÑûßùŸþéŸÎ²¬,KáODÌï}ï{˲ü¶Ê¿ø‹¿øÛ¿ýÛƒí믿þ7ó7;¶»»{Ë-·¼÷½ïõÞÿëç Æ¿ök¿ö¾p}}}{{û/ÿò/¿sÁÒ¥¥¥¥¥¥¥Gbgoï²K/ýI‰ö§®¼ò÷Ü}.çüÆ7ïþ©+¯ºãsŸ;(ÞõOÿôèË.»òŠËŠW^~¹Rê®úÆÿþäŸ9ÿ$„Á`pí`À(ûǯÿÓ·íýáÍꚆǨí»NõB«²(£0Ä»NOª…­$ž ="«NW®¢˜„u+»ª¢Þ@äxHï¾' °\­ òÁ°\¹? @RÜé~º3M“x0 ú¾…Þ%AEa„u€ÄÎ  "©”Ö’h-’lA@ÕÔãɤﻦ©‡Î9¡wžS^d9Å´Éje†AÒÔõ|2ëëfçi‰¾¯æó¾u?Dà¢KŽaJ1ÃÀ9gÌxßhMŠH ¸CÈz¥©GØìîiç£8$”C ê®íúz‹wÄyÂhÀû¾ée[Õ=lÒ, †Y–õ£Q–¤ÓÙTôBJ§1cÔZ;Œ»®#[h0&I\̦ó®íŒ6N0€ 6ÈËA9à„()êÅ|oo¯—’rN8ï•´M• " œ4²ª›úäI)¥P* âápÈÃ0ŠckAÓ6÷Ý÷ÏãÉlum}0¬o¦,”Z@è0ÁQÈ0³ù¬ë:ç<ÐYwô‚£½TZš}1mú¶nª(V]°¶1¢•Jw]¿?Ÿlíí)i´±BˆPÓ÷eYÄI䜢õÖ8@”2H Øh£T¼åŒ"€sÂ( E/‹Å~¿×µ}9ÄqŠ1VZA¥è;Ù! ³<ÛØØ8|ø0BèìÙ³Réñï|çAñiO{Ú'>ñ‰Ûo¿ýÆo¼úê«ßýîw¯®®þáþá¹ö7ß|ó 7Üð|àÓŸþô\ð¬g=k™s.-----ý¼÷ãÉäGžtýø\xäÈ×þñ®½ýýÕ••Ý])å…G.8·wkûìs®¿úüö_tÑÿüä§¾ÛÙ.»ô’âþȃ<´¹!†ˆR†ÁJ1ȳÌh3ߟԋª™71æÔ"-t߉®éáÎû4N‚Ú$O-°Bc´hdoúNõq9ïÇjV/­U‡ù}9 è¼YàËÑ(É2­5DŒ)eQÈãRì1˜`F‚ –ƒõµ€óÅbÆ]G+#!D׉Éx:O£(ÁsÆ^Ï#˜P’9Ö;§´êU/¤è•tÒˆ¶—R!Œ¥ÎyÙ à}Æ”‡,Œœ’áÛ›À{g­Ñ&â,Ë%e×¶]×k´¶³Eí¼hg´Õ3'È〇qkãj!xyÞ ÑII)xï¬1B Ʋ€àcZæAÛ®ë¥T¦NêvQccàbpb~¢šÎœÖŒq­õl:eœ¯ ÖX-´ƒ½wÞkµ­÷Mµh²Lˆ€ôÞyN‚<5F{N,AžbLh#ºÉb±?›‹¾£ˆ'QÓ$MWVViÔu3OæíÂYg¡â°<äa ¼ÕC‡¼6ºjêy][íŠl°¶¶‰ÛÝ;]5mGY‘­­¯eY’óy=ï&Þ9 …½„‡aE cÌK)î„ìEo¦C´QBÎ8ç C ½ £PŠ~65Më<ÊË@x6-æµs ޳¢(£}ÛJ©â4é{1™Ldz±4Ò;ß¶m’&2JË^j©n(Ⱦg„j©(ÅQÕ]Í(µÚ:œõÖöRi£õÁÄN#JP^d_rtccuw>ŸÞsß½@hÙ|^c¼÷³Ùìhû./‹Ápèºn±XD<ˆ¢(# Qß÷§Nž"œ)³œ·v À+^ñŠó‹øÀƒÁç?ÿùƒâßøÆ|ðúë¯wΤ”¿û»¿ûŽw¼£®kÀÏþìϾèE/zÉK^rË-·,’KKKKKK?ŒÉd’¥)cì'%`á•W^ñoÞýŒ§ýßøæÝW]yÅùƒ¼¤”qŸß>Ž"©Ôw;[†³÷Æ(£GA…aå²n÷öö¶No9c’ ÀöÊ©^‰^@âÚ+å°À*;©¦]ßy`Ã"ím#ļ­&ó¹Ó^ €ç!?³{1 )’Z6½œV§µœ1©]+ôÞxš%gï»ç¾3§·ò¼ÌË‚s>†ƒ5¦Å$.ŠK/½ìØÑ ç‹ùööYuâ¡ùbáŒÓz „`„JÂFi!”½RÒmuÊ:í´Ô„xÄ€!ÂÄZ bAʼnµn>Ÿ31&ÎXÑ÷ÆhÑË0 в$[g5õV*©­!ž4³¦Wµ˜wI’çz­ƒ4‰£pc}­j;e4"DJ¡µ”Ú`Be‘€Y–y§Óiå*dýb:“Bzà£0✯FÆè¡‘ÊjM æÅ‘CPBÏžÙ:ùàÉ0ˆ’2TRUuÓuQz¾XFyXk†E‘m;²qôðt:™Í§½R}×LêÚ8»hk 8Ã8Žyåe9 q³Å\Å!@u²ÛŸîµ²)†ED8†Þ9Óuít6ëzA(ãŒhëÏlï,˜9#Œ"€µÒÓéô“Zäœó8NXÀ&³(ŒãÎ{-„ÎYDˆ(m'Ó‰R‚R a§!)¡S±¾í$ð8ŠÒ0HuâE/ÄB€Ñ¦—½ŸÎ0ÅèÜ_ã‹^ô¢OúÓüã¿øÅ/N§ÓÏþóW\qÅù®O~ò“ï¸ãŽÙl¶µµuÓM7{eñ‘û0®¸âŠ/|‡õõõs .¹ä’|à»»»“ÉäÃþð±cÇÎ?üرcwÜqǵ×^ûÆ7¾ñ¡‡ÚÛÛûë¿þkŒñ÷Œùa”eùw÷wÏ{Þóί|×»Þõö·¿ý`ûèÑ£7ÝtÓ½÷Þ;ŸÏO:uÓM7­¬¬<ÂþÞpà ŸøÄ'ίºêªÛo¿ýòË/„ý}âŸøÉO~rgggww÷ _øÂÏýÜÏ}ÛùÓ4}þóŸÿÔ§>õ¾.F£ç?ÿùïÿûÏž½úê«ï¼ó΃„ðñ<Š¢ë®»î ø‹¿ø‹÷Ýwß2á\ZZZZZúáíîﯮ®üdÅ|ÉE'“ã'šÎf_tÑù»8gmÛž_Óvÿîuß÷œóGÎQFå¶WÓÝñÖCg¶ŽŸÚ?s¶ž.L/€µ„¡0 ŠA^Œ Ì`ÕU³zÖéÎ"×êN¥•ÞÖªŸÔ‹iSíN''··¶w÷ö¦³½é|^·TM'ª¦›VõÎxrâô™ºï5ÂÚYUÚÞzàÄñ3{gÙk`Á< ]Ó¶Mã´­•Ô!‡åh}mc4\ y z1_,œsqE‘§iDx¢Qæq€y¦YD,,â¼H‹4ÎBÌ‚ ‚ˆF “´(Ë4I²kµ” BH׋NH`œfkëÃÁðð¡ Ž9zxýðJ¹ZÆE9Ô`1­:qúŸÿùÁ‡NœšŒ'õ¢Âåi’„Üj%ÚZ a”À!ˆ@ÞÑ˶nU'­P¢éúºíꦙ/šÅàµŠÛ IDAT¢¯-r~¥ ³’¬š®[ÔV(Õö}ÕX¡€±Îè$ ‡E1,‹2Ïâ0„Ð7m3[Ì„–Æ[ O¢•CëÃCë(dsÑî.¦ãj¾5Þ›.Öû(M²²“QjëU¿³·szëÔt1óÈQÀª›-¦»{Û}_KÕ;è½èwööë¶E˜"ÂÄQˆH%a”8Ú®kÛVc‰£8Ïò$N³$”åÊh4–IBèû®©«Ål:™Œ'óÙ¢®ÚjÑNÆ‹é´é{Ó´bQUM×6]7¯ªÙ¢êzé˜H«ªWÊ…a2­†+¢Éd2žì+%Á˜Ó0‹£< ’”ÅAZdù¨ ‹²(Γ i@=†‹¼ƒÞC€9É‹œP$µìd§Œ²Þ9à°: ¬‡a$”˜Îg»û»[;Û{ûû]ßF7m®­¯F£ƒ{%A!Ú¶±Ö2Æ‚ƒß箟L&{ûû³Ù¬BSUÕx<ù×çœGŽyÚÓžö¾÷½ïÝï~·âÍo~ó­·ÞúØÇ>ö`ï•W^yûí·õ«_}ÙË^¶¶¶öæ7¿ùòË/êSŸz–<ü±oÿ}ï{ß¹âË_þòÇ>ö±çÆy^xá…_ùÊWzè¡W¿úÕÆ˜×½îuŸùÌg®¸â õÿÝ‹ãø©O}ê[ßúÖ²,ÿôOÿT)õ‚¼€Rj­}ø˜Æl6㜿â¯øèG?zP³ººúŠW¼â•¯|åAñ1yÌ%—\ò®w½ëøñã›››o|㯹æšk¯½ö‘ô÷èÑ£OúÓÏ‹¢xÆ3ž‘çù#éoQŸüä'zä½ÂžpÕUW}èC:ÿü^xám·ÝöÿðOxÂ~°ëòK^òBÈÍ7ß|®†Rªµ>ÿž%àÑ~ôÁÛž{Üã¾ð…/<å)OyùË_Çñ¿øÅ?ÿó?ïû~ù½aiiiiiéûµ··÷¸Gö ê?Œñå~Ô¾ô¥Ç>æ1çîûØÜØ8~üÄ5ù×áµ?¾¹¹ñÝNuÿ·Ø<ïÁà §4äœ d”ÚßÙkëÚ*í­KÃ8àzˆ0â!?XfÐ9?Ïê¾1½Æ Hè €Yk…–‹z¾¨få ðÖL(ÂÎ:)•Ã(DÄP9U·Õ¬ª{)KBã€嬔Rj£½ÅœB‚Œ·ÎÚ¾í´%eßõZªÅt1 ÂŒñ(Œ®›ù¼nº¢(òÁ à<æÁ0J sÍ1@ÆYD‰P œ§^(%µÒÖt­ ”Q 1¦ÞAï„(ORÙ¶²ë0!å`@Ϧ½ÓÙÜ!&„3Jm`9æ5ªµ”aÊ©¡³É¬©ZÂiB‰’JKE8…À[£Œ±Þ9çBÈy¨¬sÆ)§ÆÀäA=Ÿ­-B„ˆ‡„`NXÀX'Þ;ìê{i0v1™c“86ÚäirJ0‚ŒFQØ‹¾i›^ö¥–añ$$!ï´\T‹3û;;Ó±5&‰D0€O!„y„VV˜NôX’%J)!D€PÌ!Oƺ‹*N’¹U¡BI  8¢SÒI!¤ü7ck !¯ýë?ó™Ï8ç7ÝtÓæææöö6à5¯y1æ9ÏyÎÁpʪªn¾ùæë®»îÎ;ïüžÇ~ÏœóýïÿÁösŸûÜk¯½ö¥/}éx<>¨yÓ›Þ¤”zúÓŸ^UàÎ;ï|衇^ò’—œŸ¦F£Ñžð„ƒÄìïxÇAå÷ŒùaÜzë­7Þxãp8œL&€ŸÿùŸwÎ}ðƒ<ØûÑ~ô#ùȹƓÉä¶Ûn»êª«¾ùÍoþ×ćïïcó˜Á`ð†7¼á«_ý*àãÿøã“ãWõW?ûÙÏž:uê_?î¿ÿñü¹âSžòÀ¹9‡ÖÖÖ.»ì²}ìcüàso}ë[Ÿýìg?ó™Ï\~oXZZZZZú~Õu3 ~â¾úª«®¾êªï¬¿æê«?ñ©OSF/:v püĉ¾ÿ[ÏyÖ³¾­™µv¾X<øàñ‡Nž|ÎõÏú‘‡G1ÁZed'¶¶¶fûã8Œml®­¬Æa$µÔN!iÈ’(±Î+£•ÓR*å•r*à!vXUµm¤e”²0bˆK$RU×5FB,°B ã<áÀÄx/ŒÞkàéIOºóÎ;’7ÀÇ>ö±s•ßóX„ðÜH‰ƒ9‘¾órp饗Þzë­ò'rþ(Íg?ûÙŸûÜç677777jNžô¡]uÕU¿þë¿Þ÷=Bÿ20›RzÝu×]wÝu¿·ß~û-·Ürýõ×ò“Ÿ\~uXZZZZZú¾ŒFÃsŸ°ÿdYö³ÿíÿðµüÇ»¾X[]ýÙÿöŒ,KÏ58X¢“’¥é¡ÍÍçý÷ÿ?ú±µ"g¬óA ÒÊ*¨¬óQ’^|ñÅÅ ?uæ¡ñtBˆ‡ÎÖÊb¥X,ª¶é„WƒbŒƒ0 B¾Z¯mŸ=%±’"òˆÄk#;ÑèÃ2ì‡1f<ÐÖRJYH€€aä ¾í[Ókc ‰cJ©ÕÎ(ë‰e˜É^fIFóŠr0¨ê^ôUÛìïïç‰vÄCD0g!¥Në L±À9âÂ8¢‘˜‡Œ 30ƒ„yäŒ ‚PSÏ«®—Öù4ÍÆRÊÉxj¤YŽÊ ¤˜`æˆs.Œ°† ãMÛHÓ+¡!ê!Œà,Žö÷'„’ˆs`k|ßIà¡ÆÉÏó4‰ãÁ`0­1œ1B(‚¸Ì!„§œÓ€î) Bà•ÖRiå5tPY ²ÈN;ëvºéÛVvÚjë\’ÆÃá°( kŒw^í€:ç„RIÆØÊÊh}}m}c#Ë3Àööv×ÖÕbÞ (e7ŸÍ!gwö¼FYèÑê* ÃDkÐÔÒ`Dç)ÏÂ0dy™ðh×#äXŠ»~Ñw½è»¾mŒ1„猳=£.(£Ã‡V£()òagÞ)µF)ÛËNªÊ¸ÎAG *iG2è‘rem½mšº^t²3FZ§¢ˆSÆ<Ö9L å4ŒCÆX†Q…AHÂíïŽ'ûcÕ # 1„ÈC ½Nƒ8K)cÞyÑ«ù|ጣ IÇiœçi’†Îêýé‚8`×ö÷Üw_ž–Æ9€`Çyž_|ñÅÂ3gÎ̧Ó0 cÞû  ‚mß9àƒ‚yµø79§”Rq°}´PJŠƒÁà+_ùʹ–óù\k=ɱ€k¯½öË_þòÁöƒ>xÉ%—|Ûµ I’Ûn»í®»îú­ßú­s•ãÑhô¼ç=ï¹Ï}îù¿óåɇzè;¯/ß3懱¿¿ÿéOú†nxÏ{ÞsäÈ‘'=éI/zÑ‹ÎïΧ>õ©Ùlöå/¹ªªƒU¤Îïïæ{ö÷ĉ/}éKÿàþàK_ú’ÖúŽ;îxÕ«^uß}÷ߨ97ŸÏà^ö²—-‹Ûn»íüÊ›o¾ùÈ‘#¿ñ¿ñš×¼æÄ‰¿ò+¿ò±}ìܿҶíx<>wÇáÃþð-·ÜrðÞéò«ÃÒÒÒÒÒÒ÷euuõ'(ÚƒÕ5¾~P–Ï|ÆÓ¿¯Ãä0DÀyÎi>ZáŒíŒV¦ãÉt>»ûÞ{0%× óS×\=Ovvw¦³ùÎîNk«ëëé†V†Pš¹š$‘'(“"ƒ7h w€A„ !†Àyˆ(„؃ &"„¤Ñ½R3‚ e< Áö©9B(KSBI†Î£õÙ­³‘¢(&4¦< ó¢Jž8urçìŽh:æ‘Ó&M’8I¬³MÓ:€8gFÙEá(ŽXŒâP)%ªFÀ£ …ŒÅAˆG#¡@QÇq˜$΃¦© ª¬µ Cö­°RGŒórQ·¢“”ðÑ`c¼u¶je§µ’ªwÈ)£!ð <Æ ±%„:ìÎ9ç"6fwwW‘eYÀQ^qc‹Åb±hÛÖ{ŸÆ)£tQWUW +†+CBä|è’L Ä‚ƒµOtÚhBIšÅœ2ée/•’Š#Öw}ßöÆÎXžeiž•y–¦ÙÁ#e©U×u”Ò4û^TUÕ¶]’¤ER<„ý¿ìÝy¬mIY0ü§æZÓÏp‡ž¡n[„ ÀÛøj4ýG”DQ0E1$Ð@ã@$¨t€€tH$ŠQ$võ%Qìnᣧ{ûçœ=¯©æçûã|ïµ?жEPyÝ¿œÜìZkÕNÕ:wï}ž]UOµ›þb8ŽFÖ:ç½²¨yQ…Î'»£Á0g#Hº£ùÓõSŠ1RÇ3:TƒA™EžeUæY±ZÕ1ÊTJ”vD22Ê2Dë‚U"'ÈëM×÷.ð.Úà{ë«uÛÖRR­ó¦µëõ:¥P†BñDÙÎîîtgBðÞ+¥Êª¢äò+/gœž?ûP[7-b¦4T-5§"H)(¡ò"ÏucšÏõª¶Îö¶;œö¶[¯‹¦Þ â|>OU5PB¤4ÏËd¬¹ÿþûçó¹RJQÅÉ“'«ªªëÚ9§µ!ÿÛ¶mÛ¶”R$@9{´yk»®»´æ²,B|Í¢ðGp÷ÝwßxãÇÿÅ•~øÀƒÁ7Þøðºc×uïz×»^ûÚ×>òóÿ‹§ÿÁ6èCºí¶ÛNžö±¾ï_øÂ¾èE/úèG?ÚuÝ¥S}ìcßÿþ÷œÇ1ç×W?îËîîî×tj6›I)G£Ññ8áŸøÄo ¿÷ÝwßoÿöoWUuóÍ73Æ.µÆãñóŸÿü£££‡¯8}”^üâçyþþ÷¿ÿ_»àøû‚ŸýÙŸíºîSŸúÔñÁ¿þë¿>ÎtÏ_{íµœó{ï½wû ·µµµµµõïUUÕö&|ÓeyÓ¶mÀ˜å¥Î²éþ^6¨Œ³ˆx´ZýÓ½_ª½ .Rèƒë66„à|°Öõ}oz I  •I1ÂJU`æ)&HRÉÎôm×úè‹"' (¥!DD œʬ·yY"Å%a”0®Ë"œ!pÊ@P­çr¹\ΖËõx:ŒGBk$ ‚q¦”IqÕ6TȲ( ²(+o]p^qI‚£„"cLi™gš ®³Œ1Þ´­ Á @‹²ÌuÆm›e­…•ƒLeÐuVg“ŠPšR”BíLw€bo»Mc£ R ‘3d„Q  #4Dˆ½éctŒ¡„"¯JC„R<Ž(a!F¥T9*¥º¶oÛ6„”Ê,`×]3¯×”¦k,Ï9—Æï½³N)9 Mà{kÛÞµÆ÷–IRŒJ)¤RŠ1fBpÆ8kcJv>7Ö†(cƒÁ /Ê¢,9眉®µÇQ™’š  ¬7.`Àã’QÉt!#uëÞ,ö,ð0=±?Lò…„Œ –" 1 ¦8wÜÛà¼OŒKŒ!Ädº>$ÔEî¬%” !¤””RÀD) >xc…Y¦÷wöçÁyLÉt}×µ 0xŸB >ÎsM×XkëuÍHÑ[bd\0Ê|ðÞ†<%À„1¥”"rÎʲÐZµmsþ|{< hŒñ18ïSJ±ï0¦øhcÎ÷½ï}ûØÇn¹å–·½ím{{{¿ù›¿yþüù‡ïùñ {æ3Ÿùæ7¿ù×ý×­µ7üŸÕç_þò—¥¾õ­o½ýöÛo½õÖ·¾õ­{Üã^øÂ~æ3Ÿù³?û³ou›Û¶ýã?þãW¾ò•W^yåë^÷º¯‰f_ð‚üÞïýÞ™3g~è‡~èç~îç¾¾ú_þå_Zkßþö·¿ï}ï !|þóŸ?Âý¾¿ò+¿ò¶·½í†nøùŸÿù‡×zäþ>ëYÏzÆ3žñ‘|äþûï¿âŠ+žÿüçÿÝßýÝÃN8}úô{Þóž/|á ß@ÌùÓ?ýÓwß}÷ç>÷¹¯9~êÔ©ù‘ùô§?c|Ñ‹^ôŠW¼âo|cÓ4—îó/þâ/¾ûÝï~ík_+¥|ç;ß¹Ùl>ò‘l?á¶¶¶¶¶¶¶þ;ðÎzïµ\ÊÉÉÊrP–ƒIDlÛ.Rröü…£ù!cÔ˜ÎzÏ?^U1ú®EŒÉ»SdLè, ‡e^î ÆÈt:6ΤÅjy8;Z.—óùœrRUUg:Йö!ö}_UUU BDt1 %‰`”$ŠÎy TQdE×ô}g„lŠª’R¥)¡UU ‡CB ÞÔÖûÅzÕY£„ÖBsæ—’IT)SšSÖÔkï]ŒJ%—H1ÆÈ;^ÕC$ 1DJ9§,zcôà›¶…e^ GCÊ9 (˜´– ó1y• ãzYL>2Ê9¥(%KhÁJœw]ßfFI%u¦Û^:k­óÖ9ã,&¥Ìò<ËsFYJÝfÓÓFP‚‡œµ¶>x(g\@Ð:‹!:c!&,“à¬mZ×™è¼æJBH%¹œÃÿ™`XäELèmÚ&„ óLkÍ„ „PF¸X}¦xJI(®sEÍP3%ÆÞ·‚)M40a‚Á²RTƒ¼p!àäå'Ã!e,ŽÁõÑaŠŒ@"zà™°à úD(ãDJÁcœ0F¨£4õR"œi&bŠ4xàŠygD$Çá¡HŒRÆ%¥ÄZ_·Ý“8gNJJ‰1ÆZËåŒK!´Ö\ %%^¢ùñ7ÝtÓ;ÞñŽ—¾ô¥Ç§þñÿñQFSÿñ6èCzñ‹_|xxxÇw<üø/üÂ/|ìc;ž\zöìÙ×¾öµï{ßû¾¦îC=ô’—¼ä-oyËOýÔOBvwwSýýßÿýïüÎï¼êU¯zÕ«^uîܹ[n¹åï|ç¥ZÜß”ÒË_þò·¼å-ÇÅ/~ñ‹/~ñ‹¿YoÇO~ò“Ÿò”§¼úÕ¯þúSBˆ›o¾ùxº¬1æíoûÓ ÝsÏ=/yÉK~÷w÷'~â'`6›½ä%/9<<Ü~ÂmmmmmmmýwçEJ!!„1.¥*2¡4“Bê¶i7]·©ëuˆÎŸù¸Ì˪ÒZÇ»¶sÞ›Þ´mß5]Œ)ÄÐu]ˆq4M§ÓA–?æ1W#@ÝlŽf³ñÅ Ž—ëeðaµY9祒y–JSHœs)$rD‚„@"LÓÉǾ·)¢’Ùd<ílϯ7MB,UY–!E„D9#Œ9ãÚº©gäj<§r•Y¡2XpÆ£M³©7ëÞš|^æÎG‚Œ*…(‹’R.¹´.¸ÎÙÎ)ä ¨A"µO'E–÷Ʀ”s.8bìú:„PUU–ÎÛÅjÑl×Y\•å™â\@”sè‚kúV(%(CÄ£óÎ:ç¼g$1ƺ®7Æ…êu=;:êJ°‚£&J+ÆxãœuuŒ°²¨”TˆéL½®%g›ÍFp¦”¬²’ kQ*%¥dœgyn¬C@Êx‘åeUI¥€k­  Í2]ŽÇU1êº^¦K-3¦r)2¹iÖ­Ù0àD ©G!™Ê²re—ŠêLFÕ²^uÆB%1†®m!¥<ÓEQ ca½Šˆ (åh´hâq!oe¢šp&¨BŽ„ ÁÎ&kW4QI„(Cô AÊ9åŒ@0µ®o;ÔZJ%§@¬uu]›¾\dYF) 16]kl)ï;Ûùà1""˜Rð¾nêÍfé „xçÿ¿D¡1õ}ϧ„ .8—Œ%ëZï¼Èç<ÆØØÆZk­Ýl6ǵ²,㜷mkœ)e5!V«5™Ïç2­TUõøÇ?¾ïû{î¹çxÂêJéãÿø<ÏÏž=ûï f¾Emæœ_{íµBˆ»îºëkFÓ§OïííÝu×]ÿâJÔGîï•W^¹··wppððíL¾Õ„{Üã”R_ùÊW.p>œRêºë®€»îºëá›ynmmmmmýOv÷Ýw?šËö÷÷à–[nù±û1)¥”’s.„àœsοfÓËÿ Ûo¿ýë·4û~y„ößrË-w_<;™ì ‡#Bg™±Ö¥(¥Œ»®™Ï³ÃºY#Æ“—ºêª«öOîM§.x×¶G‹Å¢k{F8Öµýüh¡uqõåW\yêôÕW\ñ¸k;Nš®q>cç‹Åƒg¼ÿ¾òÿ|y6Ÿu}O9ÎêÙ[ƒˆ'OœØÛÝL@LͦÎ*+T.C—$ÁÂRȸ IDATyF)aÔ8wáè€2vòÔ‰r8ÑoT‘1ÆùÑ|q¸H.VåPr5Ge%¹@ŒÖï­1ÝÑÑÁlvè¬L'N,‡ÕÞ‰=)eÓ´˜­ëæÌƒgæ‹pƪ² >„ò<ßÝÙ­Š!ÄûÀ¹PJÀåjµÞ,•’eUB–«ÅÝ÷Ü}4Ÿ1ÎöNìOvv(cëzÓômŒÑZã¼eŒVå°Èò¶iŒ1JÈ<+Lo”Tœ klÓ´Î9Á£áZÒŒE‘ )âb¾X¯ÖÁGF9Aª¥,òÂ/²\Ic¤€)E@½wÓh4ÒZ‡”zkº®‹˜†£QV”s 4¥¤´¦Œ"¡„s#VÕ˜R:t.z[ÛÐ#ÃÃÙAÓµEUN§SrÅ—Ÿ<µÏ9ñÁ¥`½íϜ۴5ã¦cH © \çº €¦ig‡‡Î:BÈh4,ËR‘i)…€¦ïº¶ Ôg$##4ú)ïg9zÞ÷}ŸBðÞ×u-™¬Š²È D¨7Mô1F9c‚!Áˆ qAu& )” %g”PR‰,W±‹}ßÎçRÜÔ¾}ÚÚÚÚÚÚÚÚúÂsiËô‡SJcžˆþÿ‚Ný3Bg‹ù…‹G³™s!¯ ë|×™ƒ3Ö[·³»³³·£´ŒÑù`ˆ÷¡76Ä‚Ïu&ç”*!Èu¦• Ö-æ³hÛåüp<Ovvvwö´ÖˆH(Ëóüê+¯jêÆ眱Éxœ)½\¯.\¼Øõf8òÁ¨Ê’0„”|PZcL!FÆùd< Ú®kºÆ9Ë-Tá1ï)aE–£güÚoóy×¶UY–e¡¤´Þ¢O’ªòÌUõ¬[lÖ.†j8Ìò¼( @¤„pʪz­Ït>È˾ìRJ˜–šE© „®ëœµƒR @©Ê2¡D )QpÞ'D!e¡ÕhwÚ4M‘#ËË"+Š€H•Zçy^TUU ¨ Æ÷œ£ÎºÖ ;ÓÓ£”"Æ”B skú çZåJ'VËåz¹$• 1§ƒ% ˆÈ(#Œ„èxJÊYÝp%˜d\±¬Êã¨6UÉ3¥ŠœÂ…\2%#”{L ´À@eÒpL’$Jm›>ÆCŠ>¦”(!R³Þt}?[.º¦¯ªrog7×Y Ñ{ï½wÎ)ÉsuÓ˜®§H &¥§ÜYë}8žt™gùp8´]ˆŒ2Ée RJ!Dï!±w}Œ„¤„PÎcÇyO‘Rz<á6˜SRÊêº>œÍ6m×wfsnmmmmmmmýO 8ï¾ûîS§N}ý©S§NÝsÏ=×]wÝ·]Øùº¤nïüfSÏfsçü`4R:Ó:«ÊØ#Ö»½éÎþ.ed½^Ìæ‡Hba³Ù}ßÙ¾€\åÉ¥ÅlÕÕýzUÇ5¦1›E¼Èy®õdggïÄh4ÔY^å`4ÒJNÇÁ…óaÓÔ}ßy>Ž´ÖHáuÄäcH!Eë=IT0&(×Rç³!FÉe™•Œs\oû¾ír­9!‘RB c2av4뺎qÆ$cŠ»zÛDò|2ж™Õm£³LJ9(+Fˆó!z¯„Ì”2ÆbŒ}×Öm]wÍqØ ÖÍ:—J I‘Ä­uÞûpjÛ{Îy éz×ùà„\J A"™`@LomoŽ#|FƘ•‘¤*«<ËSL}×§0 BÄ£q¦nû®ÂÀ0¯JU`çBJB4Æ`Ó¶ÖYƹ(B0Áz×QF!• $ôÞõÞ!!*ÓùhXVU@d‚e©óBJÅ÷à»`™LR‘œåC‘M'ƒ<—ÍzÓno|pÑ;sñÜ9߇Q1ʸêë®ßô£²d}TÈ(ðã̽0BŽÛ:4ž"7‰c$¨U¯ŽP12Èôt4Ø™dy6Œ²¼@ 1$J O@§Rq H‘¥D”Ò‰&ˆ`ûδ-! ¢±C̤*‹²ÈsθóÎ9Û÷ý S*¥Ø4é J(£Œ’0ÏóGDk-!$ À3JEžsΕR”Qc­ó8çŒódM lcέ­­­­­­­ÿ.>ûÙÏ^ZÃyÉqÕÿ8¥ÔÉ“'¯¹æš¯?uÍ5×Ü{⦅ûÜ笵ß^wì:uÉl1g”F£! ™Œ'e5¨ªj8bï”q“·ÞGB éÚºk@L¡Ù¬´ÊáIßšzݤƒAµ\/êuíe@š¾3}¿©'Õ`8ŒBŠY–EN(m»®í»"Ï˪TJ¦‘’ÑÎÎÑÑ JHL)j)4”P„0SDDFY‘!Ñ J¡­$@•ä”Ð!l<aÂãÁ½Õzãb`‚ÚØq¥užK¥Ö«ÕÑìHkmG¦Pše”*¥µVÖZç Ò;ÛÙÞ§0 ¸àÆôÎÀ §Œe‘geÛtMÝv­å‚JE‘W\ LDO)å\PJRÉ$AÒn:kl †lovˆwž´Ð¹âr³ÞXc=õ1…` I ‰Æ¡¹Î„P1`Ó÷Y–[ç\p}o| Àz”pÁ‘‰–W%œ2vœ •†H9§\¨<—Y‚cŒ\kžg(¨Å¨"ŒPUp•)ˆÖLiÞ´ëÕfÑ­[׸~mÖ³¦]Õ¾ ¬#¨ ¡ YI2tF"HÊH"€KÇ{êx*•& „„‘ÆÔº@zDZ™ÎÅ|®”OÆÃñDgš ©”Ö*KRj©9&$‰#’ª*0N¨·Æ÷³Þ;„ æ’SÆ)÷Ö .J©¡k[g-g,¦È8ÓB!aˆuÎ{ï|H„2!e@‘J)ˆØ HpΘT/°ÙÔM]{ç !ȰäE®•R2Î{kµÇÿo•T Êrncέ­­­­­­­ÿ.žñŒg|«sý‹(¥×^{íµ×^ûå]]׫Édgo¯¬…Î&“‰ÒššbZoÖ&„Õ¦‰LÛ¾³Þ"D]žsVÅxwO •É Cb‚çU>(“Ñ”QòÐýÀýά<‰›uïÜ ï­÷&ºý½½±w}ÝÕ Ãîîîtglz³®WJ‰¬´MŸ\RK1©P‰d¥–šç€Ð›€JÁ&ÃÑx8"/\¼àœ$‚*.¦àcT£Ë.+7u3[Ì׫ŦÞT׌2š""gr2Ý >ë»®ãÁ¨ªª‚³¢ ~]oãY¡Äè½%„bgš¾CÅeUOìîª<<œYBè(!TKE9QI[ßûd‘&")&@’D“Eç|Ûõ+ć(…#!”Jô]ŸRL1pJGE5TmÛwÆrà’Š¤(e|ÿäɶïçË…‹‘) 1F>E<¦„Õd\ +0ÖX¦ ^I‰ ‘ mò1ôè(z ”޲ÑÉËO¸”œk¢ï¬1}mŽ.\ìÖu꣩ýfÖ¸µc†²¨ KÑ9Í¥YÎT€Hbˆ.%)°\ë£5Ö‡@—”B ¤˜PN)ó\Ó5}³®PbƵÝí«É VjGh-:â¨@ž B#áL¬ „¤” 1Ÿõ­Á”(# MCìë–R"sÅ• $aà’ J«¬*U¾Yn–‹EÓ´Îú¢`œïà C¢ˆ±È²èƒé{"ÏŠjPJ(çŒéûÎX‚¨¤,Ê’+™å¹!°Á:g9cJ©AVŒ†cÆÔ6æüæ{Ò“ž4ŽßyçÛ²µµµµµµµõ_hwwïÄþtgzâÄÉ‚à!.Vó çÏ;g•Ö½1}p*ÏG;££#·Xm.»â2)!¤ªªà\UUí¦^Ìf‰ÆÑÞx4JÆó"Ÿ¤½MêõÎèòS§Geõ_úÒÁfÅï;÷àôp'!zï0%ιG{ù'­1ÖµõƒõrÙL# $Ër™)ÆEô©‹^dš2‰Çƒ“B²VÓSÂò<Ï3ùÕW]{öìÙóçÏ7É2Z!¬·>Ë2.äd<Æ.\0-hRL\òánMW°“ÖëÕ|¾œÍæóª<}úô>#eYVÓÍ„¿V«äœ[›œ7@ aŒÞ#¦a£ÉX‘UÅh:‘ʤ”óÝIßw‡GçƒKyQêL®7‹Í¦Á 8ÍdQåÃÞô> Rª»v4É\#§‰B^æÃñhq4cœb Ñ{J€úÐ… Ganœ©ƒj¹^_88¬Û¶n›€)¯ „pÎ"ˆ”‹õ&Ï $ŒqIëM;ÙÉ…`IPEÖ‚ë\[fƒjX2FŠBŸ<½3_:ë|L‘"a@æËÍêÂQ¿êÚYoÖ •A¤L> Ârƒß¿|Ç–¦iêzU×]'@Pž{»Ö‚ F*Ρ!’ %§LÚϧ ËÙ&Qˆ>6ëÆ…©•BNwÇ’Bï6 J8 . åní´æt8ÐRgº,s}g»®ï[ˆQÌ´-2¬4K ÛÐ\Hɽ±BJIïJpÕ®\uÕ•y¦CLY^„­µ1Æ#DDL@qn¬i7ë¦éû»v<ÜÙ;q¢­ÛùÑâààÀƒœ‚«BƒAYdùd8ÌGË”pïš§.;uxxäÎëec\­×Õ`0šLNŸ>5FÕ njLÉ[ë1M{öÌ…βË.?\,—›MÝõ 0V–¥,²x·±‹¸Z,×õf±š«Q.2-”f„ïÚRc½Ç˜ Qô ‘%@¢½é'"—‹f=«—¢TH +4ãT Ƙ¶õ½;ÑÅ„¤SBH¤œqÆIÀ˜R×6Œ±ñt<šž)¬ëM]×Î{Ó÷Š t8$Áù”0ß™ÞßvMĹä@Àô­' ufú~s~óÝtÓMðŠW¼âïxÇ·K›cŒ!„KÅk®¹æiO{Ú;ßùÎãâ7Þø‰O|âŽ;îxÇ;ÞñÄ'>ñÝï~÷ÞÞÞ›ßüæGSwkkkkkkkë¿Ö¦îC 1¥º®5‚ó"/Šj<N9cEYUEB¸à¬$’I-t´kû¦k7›uðN ‘e¥l±š­× cú££™Ôùtw?Ïòz]×õZR®„d’gMv&uÛPÎŒ5ÖôÞûÞØÃÃ#oL×oä"FÐR !:Ù™Þ,æ³s=4(ËÝéÎp¯R\2 ÑÙ®i]ß PLR »{ÓË®¸ì²ËN_¸paµÚ„`¦e^äY–SBâëÚÕjÑõ1!*ÏtYè½G„”0a²ÖÎãUUÆ ¡”L£œsÆ™ÖÒ¸Þ‡ &CËÕ’Yf…Ñdˆ˜œµÞ{Æ!„H9•¤$ˆJæóåz½Éмï{FYžç„Qëlðç:ˣѩӗ™¾_-—ëåB+5×õ†Š.¨]·-R(‹!0JgÁû(£Ö{$„PJ)#£sÖGï£'@´Ê4Í#]¤D’(ÊÍJ™J*ªÓZ F¼mbìl×,«ƒE=_ׇß…šº˜1’UIŒ ë’s}âHxïE„Õn1,§¢ReaaÕ$1‚÷£å=I–Æž¥’í¢£!(Æ€Áõ€Á†moLgÌzÝ ÷Ç£½éhG0%RŒ>xJ‰,„θíâzÕ'š˜dDð¬q.zÖ t¨%“¢m„˜L) µÊ¤nëVæ2!µÖ›ÞD ’,ËvGìýòðh>Ÿoó¢(²B %€b<ÂLgqÁyDÐZ£@HÛµaCJRI©‹”’·&Od*ÛßÛ§BncÎ-€—½ìe/~øÃžL&ŸùÌgŽ‹oxÃî½÷Þç>÷¹)%°Ö¾þõ¯ÿ­ßú­º®ÿͺ[[[[[[[[ÿµÚÎ "ÐéÎ~5(ƒaY”œ±¾ï)%1¡ëmoúåj‚·Îgú¾Û¬—),sJS߇¶mBض 8oÛÖ4Mˆ>rÆ8¡Àz„äyŽÓi ~µXv]·\.£õ¶·Áa¦µäJ2^f¹>¥7›zµZ}þîÊ+®0m×MÆãj¸·³{õ×Ä/\X.½íZS/׋Q;¹ì²Ë¦;£¢Ì›¦]-W‡L> ÇãÉp8pÞo6ëår~ö왋/,—s!DQVYV”Å€¢Ô:ï½[,Võ¦ÑZFC¥ò1ˆ)–$4& 2¤)àjµ >‡V ] rº©×>@‚\hºnÆEYqƲqÕ™îààK1‹í#&!¥q¹^eG‡@ ¬ªÂj³Ù4-MI’…Ò›^h5œŒ‘1ÂIJ^kÁ™„3ÊŒRF=?Þ¹ƒxg£œ!N¦H¢Cˤ.G…ª2®9ái`\HI¥Š‘’¬k—›ÅùÙìܼ›·±N2* ùÉO^¼xñààà¯þê¯~ôGôkž¿ªªç=ïyÏ~ö³¿á÷åç=ïyøÀ.Íž}âŸøéOú8à€?ù“?ÉóüYÏzÖ£©»µµµµµµµõ_‹ š•º–§¯8}Ý ×_û„k÷OíÂg"Òd‚[Õ›õj½^­—‹åz±ªWëÍr•|È¥äy™e™’’1½1&„)§å bœ5m³Z­bŠ”ÑºÙ\¸xáÜ…s.ž9{æàèp±œ{ï…œ‹¢sž!@RˆÉˆ ƒ§Už•b³Zžyà¯üÓ?ýÓÝwùËwõ«_>wî¬5]^fãé°””ѦÝô¡'?ùÉÇg¿ã;¾ãŽ;îøüç?ÿÒ—¾tÿæ›o¾îºëžýìg‡\÷‘½÷½ï½Tü™Ÿù™'?ùÉ—æj^yå•û·ûÀ¼â¯!¼úÕ¯¾ýöÛ¯¿þúãÝK (Šg?ûÙo}ë[Çãñoÿöo;çžÿüç !bŒÜæG°\.•R/{ÙË>þñÙÛÛ{ÙË^öò—¿ü¸ø]ßõ]}ìcßõ®wÝwß}§NzÃÞð¤'=ééOú£éïUW]õœç<çRq4}ß÷}ßp8|4ýFŸüä'{„ˆO}êSo¸á†?üÃ?|øó_yå•ýèG¿ð…/<õ©OýÆÞ—ò'’sþÁ~ðÒ!„÷þRñ8‹úžð„¯_±ùõu·¶¶¶¶¶¶½oõ^)§Nºæšk¾þ SJ÷Þ{ï… ¾÷Jù×:uI9ʳ,‡Õp°·¿Û3›Ïêº6¶oêPèRð!FÏ ‡BŠª,„àiƒÒ:Ó™ÎxSÔZ!%B0©³Ð: Šñ¶®»¶ñ!RB\°³Å,!–E%¹ Œ1ÂRD&$g1†¾ÝtˆÄF^›è< îM§‚²ÃƒÃÙÑëÛv³šÜû•{öv÷®¼âò'NììOG£j±Xœ{è̹‡Î‡£'N ª‘`RjëõJð“'vFÓgFG'öw¯¸ü²û¸ÿìCç’ùT‚„Î[LëÚÖqÕ©¹ÈtäŒqYNv£wÄu$ÄKb (  ·Ñm’íPNFI1QÆXF¤íbgêfÓÉ.ƃjZ1Á#)Æhb‚sB|@$R)ÊY3ŸÐö7!šH8rÉ$“‘ZŸ¬µ¶Æúèàˆ 5žL”Ò\ ˆH(ím_ÔtgB1ƾëRJ@c º®'Z¥Rè"O¶7dz©Z+Ÿ¢Î9gœå\”y•ëRr^7æìCzèÜÿon-çü5¯yÍí·ß~ü¾õÖ[O:uþüyø¥_ú¥ÂüÀO§Ül6üàŸõ¬g}úÓŸþ7ëþ›1ç>ðãÇÿ/{wlÛUŠþý˜Ýjwwú$/ È3z ÷YRRú¸Ä OÅJ«PéE-¬ÐEÑBÉÍŠÞ°y”¼Â£@QH IN»Ïî×Z³ýï}+/•¤½wýþšsÌ9öù¾uöž{sÌ1æÓŸþô'=éIÏ}îs÷öö[®¿þzkíSžò”º®àÖ[o=}úôÏþìÏÞ¿L€•••ïÿþï?,ÌÞúÖ·6þ»1 7ÝtÓ[Þò–étº¿¿×^{mŒñýïÿáÑ|à·ÜrË}'ïïïß|óÍW]uÕ¾ð…ÿàuókçû˜Çý×ý­¸v?ïyÏûèG?zöìÙûZî¼óÎÇ?þñ÷í^}õÕðàuƒ¾bߥ¥¥¥¥¥¥‡î[ú®cÌí·ß~Ï=÷\~ùå8tÏ=÷´mû¤'=Iñ½õ‰}¤îsôÄ ‚ÒÝ^Ì‹¹‹ 3DËÁyäŒK1rNW¦+Ež ÁÑ{{`‚1F Mmß)£­s”Ñ,„RÊD™•’²RfU^´uÓÔu×u„½Ý­­íºnʬœ'Êwww3& $c,ÄÈÇ)%´7ááp¸6fœÕuÝ6‹¾­§“ £ÃÓgOßùå/Veù°Ëÿ·ÿý‘Ü8²väÈúÖÖÖ=÷œ>sæÌùóç'“‰àÙau6›Íb ßÿ„ï9.pÉŽ?2§««£ñêl±hê¶íº¾ï¼ ƒA58ç]×íïï·m[/ c4Ëò²tû»2—\dù°‚„¼UQ(¥‹ÅÞî.ØØØ˜Œ§e™3N¤^©ƒùl¼˜ãRPêê:/Ëáh´½»£›º¨Ê²ªç;û;1%€ä!ù&ÄœbJyÛ¶³ƒóçÏ;kãÉx2AŒôF§ÅbzäH5,ºÎ¦„ 1zïhb„1&3 …¢³˜â“äÌc°Éc€3n¥–RؾïÛ6(ÝÍæî>WoÖõNt xbÄC 4`ΣJfŽH9\eƒUOs¨±4,éHdêíB7µªœÆYBX{¿;o E=M€%)ÃPªä{²Ds)(ÅœJ’ˆW1‡–Œ`F¼¶Ñ[£RŠ1ÏsIEYVDPÀ"Jžâ@°KíAízÇ y^–Õon*¥ûE¿v¨ ƒaUeEU2!€Óœ³u]cÜmP9bU5Zߨ(¸ÌE†êê&¤@YVUƒñhe~ šEmµNÁABÀ9‹ NDïmoúx8—Å ¸8ߟéNK.bôœÏyß4¼;.9rX7>ùÉO¾õÖ[‹7øà?x_ã¿ÛB÷]ÂbŒ÷RÞßÃö°›nºéþàn¼ñÆûŸö´§}üã?zôèÑ£G[Μ9óØÇ>ö}ÿäOþäÁ_ó¡ÄüÕüùŸÿùïÿþï?ó™Ï|ç;ß Ï~ö³?ô¡ÝW §”ƒÁ3žñŒS§NUUuø`íúúú¼æüÚùž={6Æøë¿þë¿ó;¿óÏÿüÏ_ñNäí·ß>│Ï×û«îÊ+¯¼þúëïßøö·¿ý½ï}ï›ßüæ¿ø‹¿¸êª«^ð‚(¥|7ñ+ö]ZZZZZZú.!„¸òÊ+?ýéO?¸<ÛÜÜ|âŸø=Wp~í¤î³_ŸóÞsN#NM×$€j\UÃ±Ì¤à’“,(L"Ÿ+¥”VÁ[Õó¶ë½OJ9‚{ç¬sÞ9G)™NÇy&B ÖÚ¦_„¼êbŠ!‚õ!Ĥ­ >&Ãá8ËËrPµ]R„”œsÁÇ^+¨̲#G×ÖׇÃJfùÁÁþÞöv×,tÜ|nBHiëXÓ¬l 2ÏmŒ.zRQ@”Bfy†0%»®WZ'ä1å˜óD N$†"Løè­EºïûÙ\ÍçÍÞl±5‡ZR Ód“·:&æ¶@9/Ä`ZMO$Ñbè Ç!BHÀ¸KÈ©À°,A! ”@P ÈF‡·7 Ç@h$ «“?~PCYÂ@¢ ')($’œV9A‰P !ßÍê}N\tÙ°`B)ó¢ˆ>‡œµ) EL(•2ŸL¦Æº¦k(ØŒŒ3R‘uÛ6m£´ .¢àÇtÑÖžë ç<¹RJ+ãCʲ2Ëʃ ”2ºW'Jép8¤Ž>zDÐxõ©ûΜÏçιétúPúÀ“žô¤O~ò“‡Ûwß}÷ƒ/ eYÞ|óÍŸûÜç^úÒ—Þ×HYYYyÆ3žñô§?ýþ'?xòäéÓ§|}ùwcþvwwÿþïÿþºë®{ç;ßyòäÉ'?ùÉ?ýÓ?}ÿt>ô¡Íf³O~ò“u]—eù€|¿1ÿn¾÷Þ{ïsŸûÜßþíßþ§ú'çÜÇ>ö±¾ð…_üâïrŒq>ŸÃ1<ÿùÏ_,7ß|óýß÷¾÷Ÿ)Õ)Õ Gê*­5‹ÅìN¥¶.looîdY>™L‡ÃáÊtUõV)e­ïº¾iÚ¾×·Þú‰sçÏ;väÄÉãñaB¬ƒª*Û¦ö΄àbŒE‘­­­L&cð>¬®N/»äÔæÅÍ3§Ïl^ÜôÞ¬¬¬”•E„!@½Ò(¥"/²L¦RÌÃ1Ƃ֦ikë¼µ0vÎííï÷ª_äÅx0œŒÇ”3„ñd<¡”Îó¶ï€ ±hšVõ!Æ,Ï»¾ïµO§ ¡¼*Š";züø|±ÐZ'„0Á]¯î>}ÚÇÀ„ð1„€D0åœKA)E­µqÚ:%$aì 0BHF±$CD(ËDð¡7ùä{3ÛÚß;¿ç^t9Ñ„aŠ0òÖG@"Ë€2e%mTk—$*Pm©G BL$Ñ€†4#{gQB(ÑVõó¦aU–¢*¹ÌB.FíÄH Ëøˆðé´ÕÁ1ì‚ ÑZQQ D+×5-pÁ) zeokWƳL2F ˜P¤LˆŒGÁ¢ä"Hdb”ÆÎzÎXL>€O.¥© 3Lb0FŒ”VY†å(ëÛngOµíÔ‘éj!²²ªRJÞû¤”ºxqkaËó¢*$£(+2bœ>X(g@JÉ9«K[彑¡¶×ÃC]·¶ïûûæ@–eŒ±®ëb÷Ûo¿ýšk®9ÜVJ=ø„÷¾÷½ƒÁàšk®¹ÿ]¡ïû·¿ýí¯xÅ+¾ö×ÿЧÿÁ˜oºé¦o¼ñÈ‘#×]w]×u÷Íí€7¿ùÍÿöoÿvÍ5ׄàG~äG®½öÚtÿj³FcŒ÷ig–e_W¾7Þxã7ÞxÙe—=íiO{Ík^óþ÷¿ÿQzÔ7ë’= žõ¬g½ï}ï»ïöÁ}¹\ýõ×_}–eJ©+®¸BqÇw<”¾KKKKKKKKßY¹$E%'ÓÊÇP ŠrX`ìµ1Öë„&gœŠòÑóÀœ1Ž™3N¶ŠP ÁE­ g9Ab1¯u3ÈÇ{ Ø‹DëDã´>èµ RBކã`@VÙÕµugœjúdTô¡njJ ðÎcmnû¶eáb<AJ1yï­Qš3VFзêì™óõ¼“BN¦+'ŽŸØØ8:N2a(æ‹Å¢ë{ïÝ—¾x×Ý_¾ûÒK/yâŸð°‡]^”E Ç0E„!íÔÅ‹§«ã®?9Ž„’l:®®M¦ÓñôÌøìÙ3³ƒÅ`8Ô.Î­Ö #ÈrŽ! ”¤`ÎY­UŒAJaŒo»ÞX(y﻾ƒ”PL!J1&$¥dŪ b³ÁEŽ „”Ö”q™gZB°Èr‚@ÎÎ c]Àªí•ñ–)Á”#„`X0`J0cáV&Y@Ø9o¢A…MŒÐ¼(ª"÷}Ÿ¬&êÆèZÇ>` H%á)F8@ˆE*áHÉÇr|¼X9ÕÓœKPÁú˜&„¶ªÉ)8`Rô€€f¨@‡E°Aá@xEgGɹ P«VGRVCŠ¡ *úЪ½‚Qp!YÍ#PÊEŽ §­.xGä[{°y {·zÔ­l¬ yg-$‘ Š˜é¼í\VT9JxL‰1Ò¶õ¢Y$ä ”™ŒÒ´M>ËsÆù`0´ZodLDˆM×Fç)`™ ¥•ÒZi]7]ßùèHQœÐ,˦ã ãH)’9¿°}áÜÅÍÞè¦ïó¢êµ³.H™¯Ž}§›º#8=ÔšóóŸÿüžðŒñáâ¥O~ò“b÷º®?ö±}µ£¯zÕ«žþô§_}õÕ»»»8ôÉO~ò)Oy BèXõ?ó-·Ü¢”ºöÚkŸýìgß|óÍ}ßßwèòË/Ï{ÞsXpÖœî~˜Ëêêê’ÚÛÛãœF£ÃqÂG?úÑß@¾÷ÜsÏþáVUõº×½Žr_$0ŸùÌgîîîÞÆéCôœç<'Ïó÷¼ç=_í„Ãû¿ø‹¿Ø÷ý?üÃ?|]}—–––––––¾#8¡ÉÛ«¦k(™*:=eTäY¢ž‰ Ë N!f¥ôÎ1B ™£„úVõMϰ°Úõ⬬$‰[C]Ô(&oC¢‰RZæYJq¾˜ÏsmÌ3áa”aÖkí´áR”ƒJ2!E¥„’ó&„SpÖìïí!€ªª&ã FÈX‚ï»®©k)y‘œH¯ ú¤‚¹Ðovêe™Ùd¼2ŒÚ¶],꺞o^¸8;X›ºÙ8r¤¨rQfÖ*@!¡¨M¿½sñüæÙ£ç׋"ŸNǜё 6Ž…ày&9£çù…Ñd‚ˆì•mÛ¦ï[­;H¾,²,ãÞ»¾ocŒ}¯›¶„Æ¥s1¥„BŒÑûû{ã²,cŠ2Ëò"çB´}oœ'¹5ê뺎d–‡Bu>¥À„ÈŠÒ‡JEŒ¡’ ž`Ä ‚Á.†hƒÀ8'˜1™'\f.DœÇÑňBÀ>e4+²"—Y×­\ÐÔ{kHЈ9æK)&pˆhOiVˆñZ¶v” §‹&Y’CÆaDBZkÁ…5.BÄ Cä$ÑL¤3½í}ç=xNbt&ÒD«ŒêB q$q‰ "n‚isŽ(J¬G.@ÄŠcŠmïXHPJØ›ØíÖí¼ÃsJcÈ1Ab.Kž‰àÁ(K8ƒˆ0¦ƒ”PŠÞÛù|ž@ˆˆ B 1´m“q!%)BI5¬&Õ¨â™@”#R,!ÖZï½1Ö¸ d‰“ÈóR"$Ï‹‚1$%O.ù½ùlÖÔÒ£ñjFQ,dUfÕü ÖZ¹|¨5ç»ßýî[n¹å†nxã߸¶¶ö{¿÷{›››÷çÇ7ìꫯ~ík_û»¿û»Æ˜«®ºê°ñK_úÒáB©oxÃ>üáÿñÿñÞð†ííí‡?üá×^{í'>ñ‰¿û»¿ûVÇÜuÝ_ýÕ_½øÅ/>uêÔ+_ùÊT³ÏzÖ³þôOÿôìÙ³?þã?þ‚¼àÁÝ?þñcÞô¦7½ûÝïöÞæ3Ÿ9Âýìg? ¿ñ¿ñÆ7¾ñª«®úå_þåû÷úÚùþðÿðþàþå_þå½÷Þ{òäÉg>ó™ÿò/ÿrÿ‚Ž;ö®w½ë³Ÿýì7Ps>ïyÏ»ýöÛ?ýéO? ýèÑ£?ù“?yë­·†žýìg¿èE/zÍk^Ó¶íCé»´´´´´´´ôupqæƒEb AQfPT”¥ y$‰ˆ„h" 3Ê)¦ªë!%šQÁ$¦,Fð6ŠLr*%·$1«¼é½5&D‡!¡„(f‚)8BàƒïúΣ¸¶¾žRŠ:ÕÕ]íµ¥‰0ÁGÕ€$ÔÖmÆ¥³ÖzG0å‚Ç·¶·|ð£Ñh<#mÛ8g!Æùbn´*‹jPıÜ(cêº~ÖÔÆd}}ãÒK/ÇœK„!x±¨/^¼8ŸÏî¾ûîS§N?yl²1‰(øàBpÞ›”ÂööÅ/}éŽL „RU–„àÆX±²25F{ç´±£ÑðÔ%Skíæ…s§ï½;ËËcG6Æã!ÂÉZã½;sæ\¸°é}Ìò2D4›-ê¦)">8c{BØ`PI‘SÆRŒP&E!³¢(º¾WJµu­•¡Œý0Ë$ ”R¬Êœq‰1î•FÖB1c$øˆrF9Ä B£€‹!8K)âE>˜Œ} .¹ˆl­LD(¦(xÔλÙÖþ|gî–[Ì#¡sÆPëƒñAcrÈGòéq\Ž{D¼@ÅHŒ"ˆT¢”œõÎE œ L9öÀ¨$اØ)ÛƒI\zîܹW¼âï~÷»Ð÷üùó?ó3?óú׿þç~îçB«««‡Kýë¿þëýѽä%/yÉK^ráÂ…n¸ámo{Û}½¾v¾1Æ_ù•_yýë_¸û¹Ï}î9ÏyÎ7ërü¸Ç=îû¾ïû^ö²—=øcìu¯{ÝáƒÊZë7½éMX(èkô]ZZZZZZZúÎ:ÇYH)¡˜處eÎ3™ :‘`ÔébèEn…¸(ˆÄÆ*ïÂØÇä¼G ë^1Ä%—y"Á&Œh)‹LŠ­½Íy»??˜÷u‹ DJ1ã´(ŠÉÚ”Iá}ˆ1Å™¤œR $oŒÁ€yÆe–aCû®PDZ«Å|(îíM××7†ƒ!$Øßßå„WEe­A 9mûÖ…WVV§ÓÕ¾ïç³z>_„³,;\/W±¶¶B1looíîîÝy×'N_;±¶vdEæ™Rºí[çì]wÝ9ŸÁ¤df4β,úÀËó"ËäÚêªéÕé³ç÷¶w âá`¸¾²æfœœ8qò²KOÇ£˜Âé{ïͲBfùÖÖnß«^Ûƒƒ™Rª*KÆÁ lH)v}S7 ï}Œ‘RVÕÑõum­7VR>*!Ž­­ÙþÞ`4œL§ãñP€pà¬WÚМ÷‰ „qð1„„á@pJ1”ÁŒO6ÖBéLT‘­ú`£ÌkkZ= yNsiêcìbìS°Éhžæ°"&²)®Ëñ:)Ö Ê­ ˜ ‡,fˆ'”Lç%ÉGVæÀqŠ(tÞ· ‚””çùˆ ë“nºÞ{6d‘‰ƒK&áhú9¡7ÚY/ú:7ÀÉ%œÂÖ%¹¤Œq‚3”¸ˆmHVwÚÎ/ìè®)Vò\JÂbt(å8ð9)d" !šAâ`Ôê¶M(†BH)!B(Ôo‰)Xo´V(¦ýðA·=‰°X,Œµ}§Y–s.”Rœå”“ád8(‹ÙÁþÖææÅnŒžÕóºkåE5ì;=›- E,ú”KqÅå—U‰ö÷÷â²:PUÕW\¡”ºãŽ;XýöÀ_qÅyžŸ;wnggçëêû-Š™Rú°‡=Œ1vÛm·=`¤ñ¡8vìØÚÚÚm·Ýög¢~í|O:µ¶¶¶½½ýí|% cìá¸âÎ;ï|ÀçÒÒÒÒÒÒÒWsûí·?”ÓÖ××à†nø©Ÿú©oÝ»R}øÃþÑýÑ‡Òø=äkÄà 7Üvϧó<Ï é‚ãY& É3)«\–áL{'ª’eRfY5eQ÷¸ª”2£-§¢o‰„OlkuguÛÏæ³E»Ø_ìíì^L!@ŠJ·>X.x5ª&kSÂyˆQkµ˜×ͼÈb:šö‹f¾{Ð7]ô`ŠV½Fà`C×öë+«UQYßG!†zQsÆ(%ÎY­µVNõFk»±±1Ž‚‹E½¿¿ß÷ý`0œüchÛ6¦Ð4õÞÞî|1ç9kL;]O&“ªª2)ëEsúôiÕuW\ñˆÇ=öq'Oœ¬ªÊ#¸GY–¥˜Úº¹÷ÌÙ­í}ŒÙêêêêêÔ{·yáh×½ÚÛÙÛßßŸÏæM×a‚†“rº> g”µ>†”RŒ‘ŠÖE傲®·È¦õ•Ukœsa’€8çG£Éd:½êÊ+W§ÓÝíí/|îs³ÙÁ¼ž9ïE– F£ÑtzqkûÜÙóVN8#\>N׎¬Ó¯ëç¹išÃ7C~›Å°bÍwâÈÆÆW;ÿ+6~³œãœ€ÇžDB,K!©®ëpGO÷¬N©àyU£2T ˘åÒýÂ,0±M†œ ×tªIàR ¦7]­¬é¥!Ëy5¨ÊÁ@H™UyJ‰tØXã¬Ì²<+dtŽ Š4!ÔÍ‚š|b˜rÎ…)!çüÁþÌ*ÓŒêÉd2O9¥ÖYqİÀ˜8çêz²,O†£ñhßY[× ©ªª²Ê1Î ¥(Ë¥‰ÆãÐ+Ý_جÊrmm31ƒ ;;{wÜñ¥®é‡ÃaŒ1“²,ÊLfœqÆÔ5ÍþÁü`ÏèSkëkaÕö³½ùê¤VÃ<Ï„äÆ¸ƒÙ<Äb,ª2ËåÆúúcó¨õÕÕý½½sçÎíîì6mÓÖîµO‰Q|áìYB™ $¢S|ä˜"‚M¯öw÷´1‹ºö> G#™åŒñ,KŒóˆ!"À„DŒàp´3F”xŸ!„reVŠ2“.J¡(&(ˤêûºïQo‘ŠQyâ‘@‚!”LRÚ2&Líc$TÓa‚ “H ž1ËÃÞEâSJ}Æ}–b (Rˆ{ƒ·­1M´3oÞ€äuŒ.2&3&s‰‰EÞië­RÆYĻŒá’’pN(qˆDD1A‰Æ¢)L#4ý·ôÉÊ1‹¬SZ»ˆÊ^ÇË$“¨lŸ|ˆÞáó¢,8“hL¸WI)J1Á>ø^+JHtÞ 6D9£‘³€1.Ë2Ï+ÊšÙb^׋¦¯g³]ŠHô1X'… †Œ‰ÑîîÞ|±PJ­¯­e\xëú¦Á&Z÷Ëšsiiiiiiié»Åÿ§OÀÇ?ñ—\rÉ“ŸôÄïÝD¶¶·ê¿ü—ÃÑEBÈ%§N]rêÔw*·è1$Œ àŒŽŒ)J1D”bH&—BtÑ«hÛE+ÇEÛõm¯Šq%rQ …1Dï}ŒÆ+[ÛÐsŒ²Ñ`@ a׋¹Ñ½Vºï4 ß™Ž0Š0„D&pºQ.8©¤c‚)…£^;oc2"„QJPpÁ*댓Y†9,½¡e™U~þÂf×¶½êÚ¶«,ã1–ÖŽø®¯7/J!Ëežçƒáê½ây.\nŒŸ̺N-æMQœ²àCÓtÁsame €§¼s„жQ”Rï<‚Ôu]×¶Z©õÕµ“±³ííóçÎ_vÙeÇOœX]_†‹z1_ÌëÅ\©Ž1ÂeœJQ ‡ƒñx¼2™@Œ@÷zee¥,Ëj0PÆlïì ÖXF©”rApÝuÌ3J9FÈY!J€±† PÊ$•,¢a‚=DIN\HF8 Á”ò<—…¢sq>;èæµn:§-ñ „0æ(b¥Ì&Y±Z”.òÞ0ïp²ãqŸSLŽ„¸„zoÛz±]/vz=WýÌÛž¤@ ­bBfñb0Ý y‘¥Œ"̼ºV€ÈFßc¯2Œò0$‡¼D°Vž‰ˆ¦'&¥C$¡ÀR@™FE@,Ïh‘ÉJÇDcŠ(¤˜B 1&,„ȲÜ:£ñÆê˜daÄB$C Ñ{Œ¥$/s)åẵYVh¶˜õº³ÖDï!$Šh™•™Ìc„¾×ÆYë\¯TUUëëë‚ÐÙþA=›­…”1ùe͹´´´´´´´ôÝ}o‡dcýŸ>õ©G>âÓéä›;õ°¿¹…R¢”0Nº^ÁD‘cA1£·^".°ÔÉ’J›¦ím3>2]=º–•¹s"'ð6¨€-•¥B ÁcLÓ,ö÷öv¶·š¦žŒÇcFi–‰“§N`HU^ì0ÆŽ=š—e§ú"ÏÒÞÞžs¶Ì3)y9(R„±ÖÖ(e½Oq)e‘…°#JˆRÊ8WN!„(gb°Þ'·6‚…-—E(zçl×·û[[v®÷’0)ñÈ›`bÃ.§"ŸH9–²âLfh "…@°e1šÀøà›ÅÎ|÷œ^ìú~†¢F<&â½iCJ}D½È`~b´~’çãj²šåR» Ehr)ÚÐ\Cê2B&($H€"Žb*U1<¢cDB(e3 .‚j0Sîm1e)ÅC "À"ÐUp­iæ==¬µ½n:w`B_KLIA>™Œ­²SOM2>„@¸Reë¦ñ!Å„B Þ,¥„ N#+cš¶wÎ3Æ«Á *ãñ8Ë„Õ:„€R Á'Öêe͹´´´´´´´ôÝâÿ'à¯ÿæ‡èê3gÏ~òÿýô÷î³µÿé‡~è ·Ýþ©Oz±XäEqêĉG?êQ‡ÃžðÞÿë·3˜½¦'bôÓÉ4`š"FÖ“”œ!JPˆ˜PŒŠ‘#Â|Ñv}O1–ƒŽÕ>†áh8œŽãÁX½Bº ‹ƒºíƒA“WFmQƒÑ@P–ËŒ ŽÀSN…C¶u]ˆ2žEÛt¢,3ÉE‹j§-Éúàcl´ëU+2qüØñ,/ÚV)mKusìÒSÇ.9E3¹»³³»»»³·!”UÉ 9ú(ÆØ—¿üåsçÎ+eêEwôØÑõ#v뢶Ž–eÅdœUåh6›um#¤˜:¥)íœw’˜*8£!FcÆ(įëúôéÓ£Ñh4%ˆMÓÞõ廿õâ`~—™uÖ;Ϙ˜Ì>÷ÏŸ[[Û(Ê2Å4[Êœ#6È+“k£1æèñc—_qùöŠ£_>ÞöÝÎîî‘#G0ÁÖÚ‡½ƒ½½Ý¦iœ„²|PŠLTEN¤0à#EˆÀØÇˆ!rŒ Æ>Pš ,rë•ÒfrœWœÓ¾éû¦?ØÚݺ÷üöésHÔb0‚€"„á¼,!Ï¢NûÞªLäÑ)‹P^ë”Pˆ#ÀóÈZê]‰c 1ƒ¶¡ ¡ÃŒPFHò¶3îÙY,vD±rôäÃVŽgŒ¹ˆbkƒEÞÑÈ1ʲҧ@’£S’€¦ªeÙÀ{èµµÖ„ä5˜D ‰„cÀ³¦ ä ¤‚Ç'eY2A)c8kmo;äiÆ‹²*}ð!êYc”é8g„Ó#!DŠL2Iªat¾¯»f¾7?2—TtM}akÛ9O8Œ†>¸LHÁ„Ó¾­û¦]ÄÇãÉp0’™ö±£ÑèpûcûØòYZZZZZZzˆB€1~Øå—3ƾwaŒ=î±yÜc“RZ,Ÿ¿íöOü÷üÏ×\sxô+®!ô­ &ާ„Q’¦¬ïU.…,¥d@£0Š2ÔÚäh”BT8kNª_ɇ$—ÜK½Õ¸,†v´žõˆ(ÊÈd:vÎ’Œ ‘ÒÒË |4+‹sgÎ^Ø¡0š FÓa×6u;¿ýŽ/dyV Y–¥Á¥{ï9÷Ñ~|kovü豕Áhm<%P ììy»¿½kUVŸÐ'óªôɧ.;þÈ+a­ÝÜÞ^´F~{ks¾Ï(LWrÎƈр¡È ԡ輫*˜È$¡¤ô¥QÝl{Ÿ3ÐQïÌw3‘ù>D$P¤“_˜< )ùHPJmDãD¼v˜`Á §ÎP€¾ogQŽ„Œ“‹Þíb둎Z©5àQ´)FJ"A!X@N0ÖuwÛz¶eµéæÕú‘áÆ)rkf¯£ƒ¼ àz›|ŠœÁåˆpFûŽŒ'Ž0—eJ.Xï$‰ÈÀú‘(B¢zÖÖœg“’¤1FGÏsÌÊqÑz³×;å0NUY¤4šÍ.b^ä$ËdE”ºEC‘RfY!¨¤”ˬkÒÖtmgc”[c0ERæRf‘I^ (ø(¥§+ÝaRð"›tMݶsÀ8/+Dزæüæ{å+_ù?ðƒÁ`<þæøî÷®w½k<? ñ=ïyÏßüÍßn?õ©O}ñ‹_|饗nooßxãïz×»98ô„'<áe/{Ù•W^Ù¶í­·Þzà 7Ìf³åwÂÒÒÒÒÒÒ7àYÏü¿þ'«¢G£Ñ“žðýïÿo7§bàGNœ %B)×VfY^ ‰±mF<% @YÎò"!RhgYcòÎ5¦³B2ýhº±&EžXç{ë”ÑÎX™¸,ĈËA9ŽŠ¼”2Û¼x¾×m=oFÓBjÛºN cª:l¢ ŒÆ„ÓÀ1N˜bYÈA(\Šç…'s›ç¼OƒbH)§‚µ½ž-š"ϸÕpS !4õ¹X75BH)uìȱcÇO¦H£G‹Ù¢©{ã/ˆBYvdc­m;gLàâØ‘£“¶ëvw÷RŠõbÞ÷ÝþÁ.e ¥˜Àb¶€”eŒRJÈt<¶V-êÙ¢žN£Éx<ÔM]7‹y=¯›¦ªª¦é&E^íÏæŸ¿ýŽÙ|±ZŽŽ®¬­Ç‚P£Tß¶J©ƒýýfÞ:5^öªŸ-æÎšSÇ­­­Zo›®ÁV&ã¾iœóRr.Z‡"‚RÎ"%.¸”’ÞëàƒÇ„`‚qŒ xh$mpÞÛéùî|¾µ¯A)‚#¬sI'êl’ÑŠâ2zæ\‚䉰„FDBB!¢˜OØEâ<ŽA@$Eœ ÂÂ$aBÂÄ{ð !–‰lˆ‹ åƒè…ó#@8a „F‚!E‡‚ ^…ÐûÐE°BD ¢)¥„"€Æ‚‚‘ ÉÚ¦^à Y¹±Î§ã¢¤”³¨âb1G®¯*©19m¼V(ÅLdˆ’”À‡è}H)!„ ؇‚ Î1* ¦¾×ž"9*$åÁyŠ0@rÞ[c±ÇàcD)M>1B××Ö#c´5.B£„cJ)‚µÎc„„!.Džå‘ÓþÁ¬kÕª>닼–£<Ë‹¢BpÎ!¥¶m½µ:—UY2J«ÁÀ;[×mðË5„–à—~é—î¿ûgög“ÉäŸøÄáîoþæoÞ}÷ÝO}êScŒ`ŒyÕ«^õÖ·¾µiø…_ø„ÐýØÍçs888xÇ;ÞñøÇ?þSŸúÔòƒ]ZZZZZú_ÁžŒýÿØ»ó`Û®ª`ôcÌv5»9ûœsÛ„{HÁH#`•¼ÐXþ”V$/@¬¥D±°b€€h° BS¥‚^”4"? Œ_’{/¹ÝéöÙÍZk¶c¼?ï¾kÀ‡µuþØk®5÷™sŸÚkŸ±çœc¾èÏìcsç7¿ù¥ü)¥ªªÎ:kÿÿ}É%ÿ»š×©i!²>ìcÖUy Y°À”}ÓÅÌ1ÆÌ(R¶Œ€’\ãg“IÞû®^éÃzyeI*”!ø9ÌkS‡bŽRiSX©dŽÙµÞ§V(–Zhm”±ZDh´²‘‹Ê¦} Á{¬…”Bç ”Èûä}¥´2Ú0µmÓ6-la4ŒÉuKMUY)ÖRÝK1x纮k©[ÛX[]]-ËÞÒÊ’)l½Y7~6ÞÚ ¡íõzJi¥D~íä Ú»wß®Õåº*¬ÑGiçÍÉ|Üj5-ÚôëÞöæt>Ÿï„ĺ.þ‹ËófÞ4ó­ÍœÓž½{z½Z)9OrNFk­•oÛDY$å}hˆ9D7)ÀCÛµÛÓÉÉS§Š¶j’oƒ‡Î…âlÖL§sç<ÍçsAˆBh­±EY !Œ±¬£@f‰(´VV‹X”BdÊBZ¨´´Æ)ƒó ´ Fb«t¿îÙ”Eb)€HŒ TQ ªþ Ë 5EcJQÖ‚d¤Œà@9gbܦÔDž%n;†ÄÌ ,ˆ31&¢HX£„È)Ʀo·7z;²îk­HÉÀ9:ï"9I¶T@ 月8§œRbf)¥Â)² 5 ð1yïshûÉJ%¥Ôh¹ Î;'³ÒʪÊF£Äº§]pÛ“íÎw)f©’P‰´fd¡•‘Z(¡ '"d©´UÆÚ¢*KJ‰ (Ól:ss¿¼¼Ü¯ûZkff"Ê9wÎ))e¯.«*†þödš™Åéwãóž÷¼OúÓOxÂþþïÿ~kkë _øÂ£ýè3ß®—\rÉm·Ý6;výõן^²ø`ê>€G?úÑ_ü{ÏØ¾é¼óÎû«¿ú«S§Nmnnþíßþí¹çž{fõsÏ=÷¶Ûn»øâ‹ßô¦7>|xmmí/ÿò/O§G{€6?€Ñhô¹Ï}îYÏzÖ™…×]wÝ;ÞñŽÇçœsÎõ×_çwnoo=zôúë¯ßµëÁ~uwå•WþÝßýÝéË.ºè3ŸùÌ…^ø ûû¤'=铟üäÉ“'O:õÅ/~ññï÷üý~ÿÙÏ~öSžò”‡|_^]]}ö³Ÿ}à 7œž=û˜Ç<æöÛoß 8àãÿxUU—]vÙÎáp8œL&;'>|äK½°°°°°°ðº½àù÷û€}{÷<ý©OyîÿsÅ ®zÞå¿ðìÿë§ÚZ{úúïú$?¼:ì1Lz%©e.v%³âä°ýËiRó(LÙ³¦(¬Tµ±¥P=S¬†»KK¶ª¥6º­éú±›'×ÚÉ,Ì]tÁjÃ.t bÑ+‡+KÃÑ ?è—e•‰·6Æ® ® œ…‘Öj; Wv­ö½þR¿T€¢s¾s¾kÚv>kšyÛuÁ9" iµ.˜„ £åQÙ+Çét{¼µ¹¹¶1ÞØ˜mOcçCUƒ^¿ª*c¬ÖZHlÛæ¾ã÷;qÌ'¿¼kù‘¾à'û“½~ÕuóÉx3º®´¦0f2Ÿ8vßÆÚ©èݰ×;ø°³<ì¬B뵓'¿yçw}óßgÓéÒ`8è÷BÛ6Ûã­ñx«s­Vª*Kom:qÂ{׫ëÕÕ•¥á@+™RôÞÍ›Y×6!øCN¹ónÞ6“ùlc<>~òı'ºàÛÎmnŽ>z×üÇt:ÓÊÌçÍ}÷ÛØØD!0RN)æœsÎÞûéö8…@9§c 9%!„5¦´Ea¬ÕFIs(„”R DÙE1;šŽB2B)”@ÄÄ>æÄB=e ëDÊùìºbÜ™C›Úæ1;怘$ RlCšEšgèA&¢”(Š]mŠmN.SHÑ»q`ˆÀ‘R×¶³}aMUÚ²0½ª(­ŽÁÏç³èƒVª.+­5‡]ç½)¦ kë²(­Ô½Bk ¨9¦n2›nmSHœI i-¬U;_x[ز®zýþ°ªúƒÞ ´%‚H!ù.¸ÖùΧ˜A e´ÕJI©‰™2§˜÷]çz½ÞÞ={8°wï>k‹ét:g³YÓ4mÛæœ­µU]K©œóMÓ„1k¥þÿqÎ<íiO{ÿûßÿ§ú§Î¹k®¹ææ›o~üã¿sö'~â'>ó™Ï|ùË_~ÉK^²gÏžk®¹æÂ /|ÊSž²–ö¼óλîºëî¹çžýû÷¿éMozÜãwñÅ?˜þžsÎ9OúÓO.--ýÌÏüÌp8|0ý]ZZúä'?¹Ó#f~âŸxÑE}øÃ>óùs¢¬÷õ¨Gí¬öüð‡?ü¼ç=ïgögo½õV!Ä•W^yâĉ/~ñ‹‹Ïà…………………Òì D ´5=#+á%Ͱ5yÊÚ˜C‡”ëªß/ëyã@ ÔÆSž4sUÔ½ªšeŸªÄ"¤éæ8BííÝ»[ErG¬™——ž{®âäñcãñæÖƦžÍëA¯ìÕ»v—ƒÑh6ïv†¥âñÆÆÖÆ–ï:XÙ².j-MÝ B=Ð9ävÚfŸª^U˜"§\÷Ê® óyœO!•¶X-Wu‘spΣRŠ>xn]sô¾£D<­<üÜGœsι|Ô#Úvs}-·M;ŽSuÙëÕ•܉9÷îÝ»gïÞ^ù¨Òš¶oml¹÷ðîÕÕó/:¿_o9|d~j2™lÏærÞ͋–E±¼4šL¡iÚS'Ž+Z£T˼½½½µµÙ…ÀJ©‚wY*%UQWý²N!(£3rØ;0ç¦ëxƒpiÐ_[Û'R+i•Ö†’K)¥SÌq>ŸÌ°J§å1'$´Ú"q¢LLºP(2eœ’kâds¼yb­[÷P)‰…N c’ e…²§õPˆB2jfLZƒe"ZÔJi‰DCŒ!Í»8îâØç ˆ Ì9SŒ)ø”! "J@ R¡Èœ2G Ì›¦§Ôõ{e:ß(SW‘ã<¶Ùw¾µÖh«´RBÌ™%€H)yßá’IL¢írQ÷Hô¬õ‚›ñ¤K~õ¬Ý9çNËcòY¨ºÎǶ“ Q9¢$Æà£Á¢”ŒC,‹Æ¶gS ÄÌ…)0ÆL™«~=¨{½^¿ë\tqóÔF×¶Zi"Š!ÔU%„°Ö¤$º¶iÇÍx"…H”ÿÓÜZ¥Ôë_ÿú[o½¬µ×_ýþýû?¯~õ«SJ?÷s?·3r:Þxã—]vÙí·ßþ=ë~Ϙó†nØyüÌg>óâ‹/~Ñ‹^´±±±SrõÕW‡žþô§O§S¸ýöÛ>ü¾ðÌ0VWWŸøÄ'îfïyÏ{v ¿g›ÀÍ7ßü®w½keeess®¸â "úЇ>´sö£ýè-·ÜrúâÍÍÍC‡]tÑE_ÿú×À{â÷÷±}ìòòòßøÆ/ùËðñü‡q_~ñ‹_üÙÏ~öèÑ£§Kîºë®'<á §/½ôR8sèСCW]uÕÍ7ß¼¶¶6î¹çž§>õ©óù|ñ ·T„¿X IDAT°°°°°°ð£ -ZQ‰˜3 «Y•Žý \ÊY1 D£u¡ ¡MQcæŽ2Áw Kƒg-µÖ*qî‚WBU© ]µ’:º¸vâfŸ![Ê:wΩ¢)’ ªôëÕíÍuº”’UV%¥2ª0ÊZYXe|ãB!ƒ2JiKÝöqkc»kd(öûU]ºÐZkGb8-Mf³íÉölÚ°ÀsãÚ“›§l]Œý=»w§Nž\_ßX__3ÚŽ–Wý!ÜØØœÏæ °¼¼¼wß¾s'“#G7]s÷=w[k±Œ@R Dh›&Fo¬®ê’šfÞÌæ›ÖÚ” ªº4s=ïZ¡„DŒ>LÒ4û–c}v=\Y6eQzæä‰I3 )†”|p”X+Í4) «¬ÆN‘÷>gFB Dj›ùÆúz‚¨Š(WQ„’€‚¡( ©”d @`”UÕÎÚÔ9 QJHŒ¨€%0 ¥mÙÓeí""0ÆÈÞjæ IŠŒ •Æ,˜BŠÓ®ÛœwkMwªukÎ…D!$€ ­.°L R LÈTÖ縳 *Jbˆ±Îf[]7«u€!§Ò(5视(Ŷ™s²²ª•2Zi!T&Ž)%r)†.¤ÈÎç à¢Ä!º|Ð úZªÉu]h›¨’f¨0¤”JXH¡J[õû½˜óÎp¨‚3¹Æ‘`Da”G9“I9ï½'ÊÆ¥TŒ±¡&xß6MŒ±,‹~¿o «³tÎ{`6Ÿß=çé%|wÝuìÛ·o'n|ò“Ÿ|ûí·ïoð±}ìtá÷¬ ˆxzB¥<ÓùçŸóÍ7ÿñÿñM7ÝtºðÏxÆç?ÿùýû÷ïß¿§äÈ‘#{ÜãîW÷ýïÿw>çƒióå¯ÿú¯ßýîw_~ùåï{ßûà¹Ï}î§>õ©Ó‘03ƒg=ëYì÷û;k÷ìÙóƒÇœÜߣGÑoÿöo¿ãïøçþçñÆû¹ãŽ;F£Ñ™ ¾/—\rÉ…^xõÕWŸYxÝu×Ýpà ï|ç;?üá_tÑE/{Ù˺®âÛ³8ðÚ×¾öÔ©S‡Z^^~Á ^ðk¿ök¯zÕ«¾çxòƒèØkl (Iƒ¨,[=ih…F—u¶š3QvmK)SæØEBÀ…’mˆä Ê.øykꕌˆ€È(‰3eHˆBJ©6Æev¯î6J%J¦4Æšèãxk Z±äÎw$DLÞÓ+zVUÌœ|—B>kï¨Wõ¶¾ Á8¥¥¶ª®+kLÛ˜BÊ1Í&ÓqQÄP++ŒµJK[Zm5 ð1f@ Á¯m¬%N»FKÏÚ·4ê×u¥Œ>zô¾ñæxÞuËKÍÒh¥ª*mÔt>³eÑÔç<âxâÄñ£Çîk]÷°³fµ©z5p¾‹)eB@`ˆ1Hbbf4ÖôúuçÚíéD¢¨«ri8ÔRnœZ›5³y7ïûƒ•Qo4íZ]ߨXÛÜo½ M3K)©U=\ÕƒZ™)RfÎ'"`Fæ­>SC° PqÎD$A)¡€ ˆ™ŒÑ #¥D€ ‘| £Jd D(9cŽIdJè ¢(úljÊZƬL†ÑJa¤„S7¦DÁÏÚn³i·îD7]lBöAJÔRX)´ŠXäœ(r¦Áe&âÄ(3HbL)ùºÄ]ö]ö­Uh+›¸dßå˜|&IصÞ«t(H£Œ¬S¢LYCUÊ¢êu”;N™$3dBëµ1„°vjÝ -Ue Ô¨’Jƒµe]÷Ër¶¬«^ÊÙÍD)%!¥. ­PƒwÁs¬l„1$‡ž–KV9ç¶mcŒAI™RœÍ¢Âè%cKá|HDEñŸóÖzïs;w‚–ÓC-//Ÿ™f{{;Ƹ²²ò`êÀÅ_ü¥/}içñÝwß}ÞyçÝï^Ðëõ:ôÕ¯~õµ¯}íéB)åêê곞õ¬g>ó™g^ü‹'wÖÞÏ÷lóX__ÿô§?}å•W¾ï}ï;pàÀ“Ÿüäç=ïygvçSŸúÔx<þÒ—¾4N{½ÞýúûÐ|ÏþÞ{ï½/zÑ‹~ï÷~ïþábŒ·ÝvÛ+^ñŠo~ó›g^LD§—V>/yÉK&“É¡Cÿ)›ù7ÞxàÀßøßxõ«_}ï½÷þò/ÿòÇ>ö±Ó¿åÝï~÷®]».¸à‚¶màŸøÄÇ?þñÛn»í#ùÈâCnaaaaaaá;« k¬D•…DeH ,$‚ ‚×™e7Z –†‰SJeQ$».€eY6ÑçàƒAßZ[”ŠaßÍÛb`±ÆÈ"§,8k­Êº\Ùµ|ðœsºy[˜b}s-Ç$@æÌâÊêÈ–VQŒR«º®Œ²H"ʉ ZkmUõûÃ¥ª¨•T³é$¹Nj1ZÖu=ßnÖŽ­ €ýÆÆFçºÁ ¿ºg¹×‡¦¦0¶,Vv­DæyÛvmçRp±›6ÓªCUÚÝûö€™Ù‡8oÚÉ|ÊR$Î̧Nºà÷ï߯¬é/ ÆÓñx2Þœl¡»WWÑ"ˆv»ÙI‚J”sL)¥ÂZÎB°h•ÖJ+©•6Ú=o›f:ݳk÷òh4›N›¶]oè‡K½º·d—¥Ö¨”ÒF)BòÞÅ:çªA½²ºBœ!ƒjcmÍwƒA—CŒA… DN”C(„Ì”sr+úºªu¢äÛ6«³ñ¸›Í8$‘2#ƒQ:K@$0,¥‹T(M¨ˆ °Ö 0:ŒÉQns˜¥Ðví¸í6:¿óÑi#…*cò)攈D R0Cb$D™HHdf怀ÏÙ%ßDj²o)8”Z ÔF3ǘSlç­TF«B+MŒ‘3eLÁ‡„¨¥…À‚()ÆZPIÈ1#’ÚÚBÚÔÍÆ&…*½^ݳ¶(ýÁt:ÍD@À„ߎi•df,ʪ¨€Ùµ.†TUU­‹à}!ç,„‡Î¹£Rªßë/ 1ÆÙlcÜžLŠ¢"&bmôþœmÛž^seYj­›¦yÕï¸ãާý»w]÷Üpà ƒÁàiO{Ú™t;¡óu×]÷†7¼áŸÿ»œþ€m¾ùæ›oºé¦}ûö]yå•MÓœ^Û ï|ç;ÿõ_ÿõiO{ÚNF©§>õ©W\qÅýªÿW£|Dtæ¦eY~_ý½é¦›nºé¦‡?üáÏxÆ3Þüæ7èCúÉŸüÉÿUwäÁ`ðœç<çÆo<ýõÁé¾\}õÕW_}uY–]×]pÁÖÚ;ï¼sç쥗^úÙÏ~v'à€OúÓÌ|Ùe—-bÎ…………………Ã~…B2KRÔ[Š¢éLPRU¹ŠóC–ZYc(f%UU”Q¨”2€(­ÍÈ]ôF*©%CšÏ[V¥jg™…F(!… àDI¢¶,KC×8£‹ÂT.¶”™%j£‹ª´•œeÖ{÷훎§)Pè"Q&m­‘6çœ3U©¤H1L\ ‚…U])” cPJ„Ò$µ®eÁó¶i\S–ÅÒò¨¨Êº®[סD@H9‡è×=vßÊÒP‘˺^ZY”3°Aº.t)„#dcLH¡è•Õ°¯¤˜Ì'ˆT…w>Æ •BD‰b'm§RªmÛà"¢°3ëÒh“¬σsLd‹Â97™Í¤^ÏÌ\eQ«+«Ji%e×¶ã­qL©mÛÊÕ)“Öª×땦àœ}çæmSÖ=# °š˜)&[Ñ·]×u¦(´ÕEJ‘R–B3£O){;žŽ·»y½Ó‘”D! 3gF€³²J ƒÈR1ÈÏÉÇ0É~šÒć-6}Gš2x¡³6“R †(gJ9‘bÀRHd™Q D@(˜9G-IKRH8s¨…Ö¢ËSÊ]畲Ri!„”RI) @%€B©RbÅ\JYTš¬b”¤J®¨h¶ÕvÜÆ”wÊ Œ¥ÑÖš ¥­tYÖË+#­Ôd{{>m””¶°À ¥ÒBŸ½¿Ì°µ±¹¹±Ñuêºf朳1f0èïÚµ ?¾¾¾¾“RHJ€ÆX½3ý`üÛ¿ýÛ“žô$!ÄNòÒ'?ùÉ;…²út:½í¶Ûþ«³¿õ[¿õÌg>óÒK/]__¿ß©/}éKOúÓñ!LÔüÛ|Ë-·t]wÅW<÷¹Ï=tèÐé˜ Î;ï¼~ðƒßNa ðÔ§>õ;«ïôe×®]÷ëÔÆÆ†1fiiigœð1yÌCèï=÷ÜóÞ÷¾·ßï_sÍ5RÊÓ-€Ñhtùå—¯¯¯Ÿ¹âôAºêª«ªªúà?ø_]°ó}Á¯þ꯶mû¹Ï}îô÷Ì<ûwïFÄÅæœ ?"ŒN!Dmj6BÕšK˜Ç™g ­ìîåtª¨M!…‘*c*¬ ´ÕÆibÖZöMå)FO¤541`fÌ7ߞˤ¤•uÑGP)Ç”R˜Ç­­Í§Nm®­i¡ý%m›Z¡•nÛ$×¥­ŠbP÷×ôÚdÆõÍÍÓêhTh8'J]ð[ã±Öº_ôLacNÚ–ÆÚ˜ât6MœQ‚Î3‡KCmíl6ËÌD9Æ0o(?ÞX›¬,sÛº¢°Z†I€’ ˜bHÀ*t³ãßRJÕumër°2 ®ëæóµÍ5(@ô{=&vÞÆj©vþe !€1¥”SYWƒá°ÚÚBZ)‰b>› @)eYW!„é|¦fäs¯W‡}à»vi0ιàM²sÇOœ¨ëʵ{ÏîÊZ×v›[[eUÕUOU帛»®-}…¢kšYÛöƒ•ÕÕ¢.=z–BH©)š˜)sH!ä(F&ÔJKÀà½ê‚èˆQ†B©D¹.5»Œžµàà:æ@Ô„´Òºk‘Ç€sÀ–!#hM¥ÔE!²¤,™C  ̌̀ Y0 ¥b%¤Ä^¥ëR×B§B‡N¢­P¬V™9‡¤¬™Îڭͱw±?˜ÂXk3¥àƒ@a¬a–Ú”*Y@mkÙpB(©Œ6e]—Ub6¢Lõu ­DðÑ» ”î÷J !d]×+ËËûöîÕZ—¶Œ>N&“œ)¥lÝ¿gߣù¨ãGïk¦s)eJ)cRJ1F!ÄNNݨD!¥’Rí,®ÔZ)‰6æüÀ>pË-·\{íµo{ÛÛvïÞý‡ø‡Ç?sχìÒK/ýýßÿý?øƒ?ðÞ_tÑE;…ÿþïÿ¾´¼õ­o½õÖ[¯¿þú·¾õ­§Nzä#yÅW|á _øÄ'>ñÃnsÓ4ùÈG^õªWç9Ïùó?ÿó£GþüÏÿüË^ö²ï¬þùÏÞ{ÿö·¿ýø@JéË_þòÎîW¾òøßù·½ím]tѯÿú¯ŸYëû{Ùe—]rÉ%ó7sï½÷8pàòË/ÿ—ù—3N8묳þìÏþì+_ùÊCˆ9_üâßqÇÿôOÿt¿òýû÷ÿÂ/üÂí·ßžs~îsŸûÊW¾òÍo~óé,A‡zík_ûŠW¼â/þâ/–––Þóž÷0óýfç.,,,,,,ü(pÎN±q&k­sng:ÜM§N»ûßþ…Œö˜•åPALÒ£ˆm˜mÅ*vKVCÎmÛ¹¶‹¾(Maµ±¥%fšNf¡06 p1b"ŒÌ8d7m Û¯x­A(cÚÜÞø»ïºãkwŒÊa¿ê1sÎlu¡J=iæ]½amŒ™MfZ*a¬a’Rš bÌ@y+×UEÙ´í¼i&ÓñúÆúñLJõ0R^Ùµš(5®sÞ¥œÚàØ–&ÏŸøÖñcEU6–˜…Ì0Lr ëÊbL™˜MYEBl|‡ ”Ñ$(3i­ ™§„Ù%Ï1+!$ŠHIK­P@ë:ß¹¢,3pÛ¶ rŒF(PjcÁK!gÛ“ècoÐ7Æ ’D4™M;ïRNea¤2R`¯.—G£ÇOÆ[Ä$L›iYK½Á ª¬-öíÝ›|Hȉ ›5Î5QŠn>)"gß9%u[¶Âˆ¥å\Ú¢¬*gÔ„6Œ¥µJ +Y¢6ÒŠL~gCM!„R)•rÁw)SÑeåˆÚF%‡"¥<Ûž|‹iKªÖ–Aš¤”½Ç®óÚ¢œ‘91¥D "@F´™ÉçƒFaE½ÔJd/È— µÕšI;šI)bi0˜Lç|¤±-ŠÁ o ©” !¦Ì­O±…Êé(wóÎaª #Q2sL‘Qزˆ IB¡Œ>looˆª¨™sHÞµ®WUUY7MëK))¥¤”]çBˆ%1»¶¶Ç1ç~¿[[[ÓéTk]×5"nnn:q²ª*)åh4RJåL9g£ 0ÕUñ`cÎ~ô£o|ã÷wwg½å=÷Üóìg?û»Î’ý~]tÑEBˆ×¿þõ¯ýëOž{î¹;K4?ûÙÏ^yå•ïz×»^ò’—ìœúú׿þ £©¼Í7ß|óUW]µ¶¶ö™Ï|æÌòW¼â·ÜrËÎäÒo}ë[oxÃ>ðܯî}÷Ý÷‚¼à-oyË/ýÒ/!â®]»vR}ík_û“?ù“×¼æ5¯yÍkŽ;víµ×þÑýÑéZÜ_"zùË_þ–·¼eçð«_ýêUW]õ¿ê~ýøÇ?þ§~ê§^÷º×}ç)­õ5×\³3QÙ9÷ö·¿ýÌ$CozÓ›–––Þõ®wíd >yòäóŸÿü3WÒ.,,,,,,üˆÄfwÜqÇé<…gÚ¿ÿwÞyá…þv>@§N[ûŸÿV”}èæ#E¢E=DS˜‚E‘xT—%e b`f@ÈL‰ræc¢à¼ït]ZÔÀÙ ¬M%„Ö¸²Ôº¶ TèB×8kK-MݯvíÛuÎô@œy‰‚ ™‘˜@k-´L!vM—3-‡£%­‹9´”º€Ñ{§…Ê9Næ³v>öú%R$OF¡Î>ëœ=+»777Ž?QÄPõ*˜7 )­:×Ͷ·bfmu&”Rk­µJŠè=J£•’ÊäÎM··a[”Ri™Ø…RQ‚dÂcL!€Ò §LM×ji¢QF Ú„”«ªÇÌιfÞ>r´éºƒÒªW× UòaÛ{ê ‡,‘€#%ArssˆJS­ý>÷z•óT£w‘CŒ•):ç*m«¢ k›ëÛÍL—%BÎ]Ód¶®Œ6‘bL>r¢nÖvsmM ÌÑ»f>ó®ó]Ç)‚PB2%!¥¶Z몬ª¤ JeY—¶”0] )4]3oÚ)±#šSž‡”sÊ*S¬ªàCÎsfæ ™ ¤ ™˜(cfÈ€ZåÞÝ»÷îZ.5Äùœ|cK­%“ATŒ!2¦”mY(\hC“bÌZ+­{R*%ÉGjB›*å@HV2KŒ“ÈÑÇõõõiìªaßÖ•5e¯´u$(Ѓ}L±ëò¬i76×§³I×Ì¥¶°Äd1Æ fÌy:oç÷¾wkcSF•ƒáP[³vê䯯Æ|>BXc•mÛ.-- ‡Ã” «ºç]|‡›››2­ôûý .¸ ëº;ï¼sgÂê!Ä\PUÕ·¾õ­µµµï«î©ÍJ©óÏ?_kýo|ã~#ÆYgµ{÷îo|ãßu%ê÷÷àÁƒ»wï>uêÔ™Û™ü°i­ùÈGZkïºë®ïºJ¿ßøÃÞ4ÍáÇrÖÜ………………3wÜqǃ¹lÏž=píµ×ž}öÙJ©A†ÓNçŠÿYk÷íÛ÷ˆG<â;Ÿˆî¾ûî'N|׬ø?Ê S;®½öÚëþôh[÷G{–Ï}DñðÅY«õþ~Õ'·ÌÖ‘þ|¼ÔuUÛɤUQR& b'‡gÌ9›ªŒÀ( 'Ä, #¨žÅ±+½Á®eUèȹ¬«¢¨²Ï“õñÖ‰­­ã›kÇÖæ“91 …A&;,«Q… RŒH\—e¯î»Ö·³Î·Á5Ýd<5Ú$çÓ)$ôzuYuÍœr2FÖ¦ VÏ{ÄùÇî;v×]wùàWWW˪캮ëZfˆ)6]cmQ–%"æœwFóœkµ–”²R)ˆ6·6sæÑhÔë÷0ÄÌÙ‚«ª¬{5¥0³)f&æÌœ¹´e¯ª SÄw65é|çcH”…BÉèû¬Q*¥f¾ÓEQ/ ¤5BŠÂ½ª.ŒÖ(*cWWV––FGùÊ¿ü‹YJi´”òì½ûV—F…ÒÉùñx|ä¾#›“íbÐ÷ÈM YY»÷î%¥ÖÆhÛ+W÷®n–w×Ë»jà°µ¾¶~äÄúݧ¶î]£-W±èRn}ò`‚¨Ø.™¥³†»°ÜwAK&y4 *4<‹ÝövžM›­ûfãî9ã1à1‚‹)¥,!WHK1s禙Z€ Ä@™‰‰ˆ)g¦€ d¢0½=»ûÓOø‰Ç=¶1­Ýƒã5‡R)ÁYj”¨ëBˆYéÒÅäB 1eÎeezu)s" YÄLbF­t]B¡ˆ\)5ªŠ•¾®K4ÊꢅLBxÀHB µ½5žÏ§“éöæÖúÆæïÛ·w÷žÝEa„EYöz="ÚÚÚ^[[ÛÞÞöÞK–{Wv•ºB:×mmmŽ·6cŒ!„£’²0z½Þòò²5–‰µÖƒÁR a²½¥¾¯wõl6ÛÙò¿ÎXóýú!µ9¥ô›ÇŽ;vìØCëï‘#GŽ9òßü'ˆ1~ãßxà×ùk_ûÚâ‹………………Ä%—\bŒÙIÁ¢µ>þ°¯âüóÏ?ÿüó,_Õ8;‘[›Û‰Ýãj ÃeUVÚ£‹íúf C DBÛÅ”•TBÌY B&`ÞÙ7¥n£ïBH™Ø”•ʲP…d­µ…aÍ@C«Lm«­­¦m±êW@,@H>ø¶i!Qò ²ˆ1±RÒZ#%"²T¨”Œ9ûè¥!G…ÂØÂ–%¢tÉ7ÑJYp ÔøN—¶7˜¢!Ä”´-ˆ²R+ÍŠBˆÞ;&ÐÂÌý´ ±¶(Ê~ÕŸ5­ë|YVÆZE’˜SÊR !rN;óN;×HIJ¨ª~O }lgmÛvD€}©„”J H!¢n];oÜYÏGD Œ"úÐzßå`ª²¨JüöÖ"uð>;WZc”ÜÜXkfSZ”Ò§àSDÄù¼•1F(£µ–J ‘S%$ŠL”C(´±(%‚àD“1ŠSÎ!…öû3»±3œµÄ,øÛ›Ü0S" RJ‡=p2ZBЕP=!z =¢¡EARÎ@ÀÀ™3 FÁ”˜#Q¤31gÀ 2ƒ4€””EY÷‡KÃae%·S ℜSH"‚ÐJèÂXDŠ™Œ±Ú”>†Îw¾ó9­‚² +Á9‚@À"gò«†¥ÒZ[M (s"¤”“K 3k­µÖÖË£ÑÒÒpÿYûêºQ€-Lo0`æãx[)­ÁJ›2¡™¨uÎyWVÕÈÚÂl6M1£ëº.l©•BøöN§”Y¢ì×µ¸¹/,,,,,,,,ü+¸ƒ”˜xvyP×{–ø¬¡!5Ð…4EC ‰9æœ2£"‘˜™3ç…@ÄÄœSšµ9FJi ŽS¢Vl Û˜I Ð”¦êWƒÑ`²5áDeY²)‚ó.v®s Yx…J°á¢*”œ6XÞ¯PêQHbŒî;y¬i4JC‘€]¦(lQhcˆÈû°±±Ñu¾WÕUU*©•TR…Z)åHl ²uŒÙ{?ŸÎ«š‘™Éh-•)­5" @bH”“`)¥B!:f,l) YØBÛÂG®KÀ–™‘ÁI& ˜Èç(–LRËÌÖ¹V䜜›†ØÌ&›ýþÆÚZ N!•@äà#14ó9äŒe­ëž-ŠªªŠ®™9GZJk¬TY (…R¡°›·ý‘>„NTEÕ«kk-3eÎ ÌH „HB b¦L)RN9§”EJ9'¡5* Т¨Q —'€^ Ò#åÄ"眕e‘‰˜}æ8g@•Aj@ ,ASöƒQ]ÕrçJ^!)ŽY2#3! Vš(û”–(!&Ê9zï]Š@À¤’°‚Xi¥Ö(DLÙÍü$6\+hÛ"ö%[ ‚Œ  âì]ç )ÑδDkŒVr´4êÕµÖš823眘9SŠ)†è)“‘f6ŸSbdˆ1Õ½þÒ oŒíº¹”8›N¹, «R ‰€œ§”¥‹˜saaaaaaaaáÇ™’„°íçÓÍSÕæžÕfÃ~Ý+—–«Ñªžn³óP¡ˆÚèœ RÎ)&Ì ´QÈœBŠ9ûÙ(¥\X7i‚îæºo ®*ÈJëoª÷ìÛcÑ4³&æš=Ç™kš®í:Çꪇ ¥@À™¤–K£aaìÆ©µà"䔈˜˜]Š¢é¼O™¸¨âö|*¥²EQôj$Ž9ÏšV"Vee › s¢’—±®êº®Ô@ û½f:Ë> Ä,ˆBÙÐùf6§œËª@ÈlÖZÆ]×qÎ DYUD”bšL§œ¸ÔEi»Ä• IDAT&ˆB)„ÔÖ )sKCQ–E]¹àD&k„ÊbÐJˆBc çÔ6óäÝtk¯Š¢(ŠÂ*)@J4Ò$™€ˆˆ¤’¥µý~Ú6›Ó ‘¨ÊB¥b$ÐRI£r;Ÿ—fNÎrî[[k­2åȉTÎ ˆ…„`ÈD$9³RJÁ‰RN‚ƒ`4R m(F mLž dY)Ê™!#13§LØ3¡" „J™^o°º¶èõ{#©\çCJJiJ$@Z-TO‚³±c"¦o/Z3ÊH@ VBH«-(]êÉÚl:›looo¬oÞû­Ãå ZÝ¿{©7Zê/ïÌÝon uYÆ CèB;kœóR"ÁF)•÷9†È@ÌÐy§©z5Jhºyp1…Øts ¨ëÞ ßßµ²º{uU Þñõ;6Ö6,ªƒûÏþ©Ç=Þu-§¼÷Þ+­PÀ`0ð>llnÌæ³¢Ô U£;Ù1%;›-…ŠBlæ­Ñ¶²•.¬Íȇ.«ru×®þp€Rh£…Î9¥It)d zЕ]JÁ¹è¼`hæ3ßv(„-ʶm=²gÿ¾Õ]«Ú˜b×¶¶,C–)rtÞu]]VR cŒÕÆQrM›;7u@)•.ÊŠRe¡rÈD1CˆI¥-«ºàÂ!U …b@9SÈÙ¥Ô­mœ½]Y!…ÐYåÈ)“Fmt5”v Ô2S$ €8¥”20K`C ˆ9£&,,ˆBGÃå]g|ØYÛµ´T$?‹ÍݬB.µV9ú®ó™X&&@TJ˪*1dFähg¬–Ñ¢Ôõ¬ñÝÜM¦ÛI(ÅFp×´v>/»ÚØr8¨——WKU´ãyš?qó¦éº¶ÿÿ²wçÁ–]eÁðŸçYÓÎ9w¾=dh2‘AÀHAÁ² ¤¤° ð‰XJ‚ 2‰XX&Å‹0H*U"h 2 ˆP| ($H†NºÓ·»ï=÷ {XÓó|Ü÷í7mZÑ÷;¿?ºö^k¯s×sn÷îzö^C=CŒ cŠ³Ù´óí`8X][eæ˜RÓw"Òvˆ,--9[ÕU•bFRkkk++Ëw½ëð‘#ú¾ãÎ;·NgÂ¥••>øÁgŸuö·žN¦MÓÔ8¨«EÎùƒ÷ =hyyyïøÆo\|! ?B‘2 HHa¼“ÝʧAM½UfX ØY0Ö¢ÒEYi@ò>)ùD@ÆšÄlË¢õ^•Æ!¡Õ %3§L,I6ÞC♲(¤ëû26©ŸÅÒ µ%I±,,–RLÀ˜­¥HÖJ£‚œ0 @YUmÎl­!­FËË"¼»;Ž!¦|ׇ¾W@µ±¡ªCQºM…¸>öÛ“0žíÜuwþEûÏ9p¿û]2of‡ï<c_Ùr8(77VëÚ?q¢i:ADA߆ª¬÷mì7Z=v´mú’´)H)@a{k­.Œøv<¢(ÙïVP“R¹Í 2|ßûœÅ(STƒ¢Ðó¦éÚ8Þ™ž;Ò^pÁáݘÄ šv]꺹™wÐúIßÏC,ªŠ…€E$e•òÐ9"M©ï³ïE«²(sö½o[$tÎUÖÆØYkJ[)Ð9ƪ²ûö¯_õÇÇ“-GÜr š¬V9§¦éNöÅs¢‘X²…‰’)M¬ÌÒYgAÉ»'•ß% ¥–L9s˜§4N" ¸p Ñ ² («—Wë«ûuÖ}¬­Ž;HVx%ù¦Ý™H9ûõåMmt¹4ºamꩇ®ÀÂÒ¶­^²„>4ÐR3Ÿ÷Þ“"W¸ºª†õ …¸³3–fÞ?v¼* ßwMÓŒÇã»…OnoG–6†»Ž»íè} Çîº{g4ÍÌÇ1Å$s¾ãÈ]ôå/¯¯¬Jȼß¾AQ3§z©\äœ?xW\q¼à/¸êª«þ§ô9ç|ÏM5Ï?ÿü‡=ìao}ë[÷N/¿üò~ô£ŸúÔ§®ºêª<àoûÛ777_ûÚמIí™û¡î•⽿ùæ›o½õÖ /¼ð^U·Þzë|>¿ì²Ëœsÿ³¾±Óu ²Q€È€rÚœ Ÿw}‘9¦#眄9€Ò,œsVŠ´RJkS8bHÁ3gfN9…D‘ìå_šP"‚° ¢Â 9 ²Òh­6Z%`N1ÅPºÂ)£•@T‰E}|­uDBš4¡X¥E ¶èL×vm;kºi3¬²ûˆh­cŠóv,…³wÝugÜØT@Úš <ÞÙþÇo|-[úÐ t)ºJƒUÞ#9…†bN ’+mY~Ü·}kØA‘œcŽ}‹Ù$e €¦¤²F¶" “Ò„•Ŭ+½j+m5³ÃùöɈ¢µ ™3rB[¸Ñ¨XÖ«ƒåËK+ÅÆ¾Ñ`€èûv¹ÛFHV’&"%@ÚºB@iÃ)gAh»†E@÷¾g­­Õ:eß7­°@"£4ш¦iž‘ËÁû8뢉`)§è»6æØÇ½‚ŽÁÇ#)J)zß·më}_V%)%H  •ÖFYkØ÷½ˆ¤”cŒóY[WC¥TÎyw<>qb+¦dœcŠi6›¾ãŽéÎîÚhùÀú¾CÎY­ä&L9çÀsžóœ{ž¾ÿýï_]]ýÜç>·wúªW½ê;ßùÎcûXfÞ»¹¿â¯xË[Þ2›Í¾gíÂÂÂÂÂÂÂιK.¹äK_úÒw§gGýÉŸüÉÿq çéƒ:…¸2 ªŒ•KK†K+H*øÈ!aÈ$’}L‘´%%Ì‚È ×ÖÖꪚ·sF†„$ †¤ãR`È É€H&R€$™I£­,F"Cƨ¢°Eebb£Ik$ Øs$P‰öVMEŽÜõݼ™«y[¥5fe0’˜RŠ”µºT¦@ÝNÚ0ï“.œ35dˆ))@D"¥2ðd>ÿçùöît²¾¶•¨ÚoÇÍäŽ#w.m¬6}ß;ç˜yP×ìã¼81 (¥sæbÓ¶€Š´.Ë‚9qJ((X¸B£Ž>Ž'»Gï>ºÿÀÄl¬µÖ:k­ïzNQ@„ ÷Á«á¨ @ Qb Þ+"­4rΙs"Ê!D@°Ž‰c¬†®Må  ŒuèS¶.Ð`³;/,), Â9%Îm«»Ö’+Œ.,$…¢³¤b M¡ Wâ£ÖªvE]UQº¢h§Âèy-HsJÌZ€™º¨V—†kÃz¹(8¨©° R—Ûév #e Ж•)+ô1ÆØ àöönQöU5PÚh¢ä!‘¢Ì{“r»ØE§*ŽÈ¬”¢²,ûu%±Ìº”¢(T¡ ëPBæÐ‡0÷Ø÷="qÎ!F"Ü{pcTZ9g6Öh­tJ!Ä”™sf¥”Öº*˲,Qßw}Û¥”8%)¦§œ¼G€ª¬VV–6V×]iýŸAO{ÚÓ>ñ‰O<ä!ùüç?¿³³ó¹Ï}î~÷»ß½¼ÝxããñøÈ‘#×\sÍ©)‹gÒö4îw¿ûýíwÙ¿ÿ© .¼ðÂ÷¿ÿý[[[ÛÛÛù—yÞyçݳùyçwã7^vÙe¯zÕ«n¿ýöãÇÿÙŸý٩ǧéói¬¬¬|æ3ŸyžpÏ«¯¾ú÷ÿ÷÷ŽïsŸû\sÍ5ßüæ7www>|Í5×lllœa¼W\qÅG?úÑS§—^zé§>õ©K.¹ä ã}ØÃö±}ìØ±c[[[û·û‹¿ø‹÷úüápøÄ'>ñÑ~ô÷}ï^__âŸøÞ÷¾÷ÔøØ<à7ÝtÓ^J ùÈGªªzÔ£u&µ ÿ}EñoŽžõÞEñYP§0¸ .ƒC4Õòê}.ºàСsU‘º&7s ARb1g$…¤²`L9¥„ˆÞ÷Â윫ª²*‹¥Ñp}uuP•¥3VQŠa¼}òî»l;¶½³=kf1GS˜åÕå¢r1ùÉlw¼»=›M|h’³ 6¡4Ói?Ÿwóη!…,9Æ9jCΘʸAY)À~:ß=±“Ú°\ÏÙ›Íçóœ9GŽ1‘±Æg´­ªjeuußæ¾å¥å¾ïSŒ@¤Œ±ÆH{QD’sô¡ïzß{IœcšL&wÝu×dù¸4ZQ 'ãùÉã;³i‚Ú˜j08pÎÁçì,× ´è‚ŒU…Ó•ÓNq¬V†„%¶±·;³ØFP[¬­8•H¼$ÖT-/mœsöÙ÷½ïY—ÜwßE¸ðþû/xÀÆù÷_¹ÏÅËç]°ïÇ.>ëÇ/9ëþl\p`iÿ°à|¶s×É;ÿe÷èma÷¸êgÔÍ¡o 'h}8±=ÞÞ4]ßzßyR¥GK˶(…(åÜ{ßû”"¥pPVÖö-ƒ«5*Ž)§$¤©”e]Uu5 ‡Ã¡U¬2–”ÄÔ5MHÁ‡ÐumLÉnm}}ÿ++ËUU*¥˜ˆ"€U(]×?~ìÈ]wžØ:–C(¸bX”Ž´ÄT(Sj«IqÊÍ|¾µuüÈÑ#ãñ¶sÅÿyÏyî¹ç^~ùåïz×»Þþö·÷}å•W^wÝu~ðƒ÷jïÿûêSŸúò—¿üìg?{ß¾}W^yå%—\òèG?z/-9}ÛÓ;qâÄ»Þõ®S§¿ök¿öà?øÔ8ÏC‡}ñ‹_¼ýöÛ_ð‚¤”^ò’—|ò“Ÿ¼ßýîBØ» ®ëG?úѯýëWVVÞö¶·…žô¤'crΧïóiŒÇcçÜsžóœ}èC{%›››ÏyÎsž÷¼çí>ð¼ð ¯¾úê[o½õàÁƒ¯zÕ«ô ]vÙegï}îsŸÇ<æ1§N———æg~fiiéLâ]^^þØÇ>¶‘ˆ<ô¡½ôÒK?øÁÞóó:týõ×å+_yèCúýݸŸñŒgh­ß÷¾÷*1ÆÄïùßüØýØÞlÏÓ×.,,,,,,,ü¨U,`hu}ýœgŸ{Öòr‰ÜÅÙ¶3“=b @MšHiØÛ2±ðîî":k­³)…¦™× ª¢LÍdÂ1(§ cuU- \UÈ´™Ib½¢úä»ÐùÔ &c"JŽM3ª6!DR)ö…JWº(ÊB“–$" Â¥-«••¶¾í•`î#Y*G8æä;¯4•EcOv•ÖÆY­ ²†&ûÝn^HÑf?OýN3ÑBGî¾Û:«5Ž'»Õp`)e›¶á €dŒ©ªâœsÎ9ï‚óÊÊ';1ûæèÝÓñ$Ä8ŸÌCKëbÌœ%'IY²@×õ è§œ•ÒEaÕ`X&“Ý®ë%sÄ„Y5F)µ¼¼JÚŒwǨ‘­õh4rVCâ”Rã»Þwd´ïû®m [Öu•ƒŸO§•ÕÖ*–BÎ9kEºïtã}TÚ­/­ èÐG²Q.—5nmXZ;–‡ÅÐ)‡©ï3[@1ŠÄ$ï'Çî.©’2õ*-BÀœ¹—l&–H’%ím—©´•b,F£rŸû–;*¡™¢"/iо? Óã0=iýÌrï0[–'ÈÆš½l|0Ä”'“I烟·kkk(Œ!ÆÃl6 >´}“Yé²(Ú¦7š».´]ˆÙb4 Y£"–(Yœ*ÃÁÐ – ·98ßÎ[R¤Œ€cJ)åø¿gŽ@pÖ”e!Â) 3ç˜bŠœDzïQÊrX«Ã¥²pˆctÊ”ÖíîîNÇãNkÅRjƒ)ÜÚ¶vÿjl­Öú¥/}é'?ùIpÎ]sÍ5ð½Ú}èC7Üpé‹···¯¿þúK/½ôë_ÿúòŽxúxøÀ®®®¾ò•¯üò—¿ ùÈG~wåg=ëYŸþô§>|ªä–[nyÈCrêô‘|$œZsèôµ ?Z¬J,¬]^>ëâ‹]tîÚÆ€¤ËómågI”ƒOdIGHJÇœ}ŒäŒV¤ÀæSÎ)F>xï],ANÑY32&h!­*k¬+ ]T„€!ecQFU¹¼ Dd¬%„œ#dôÑk6}ßs`0µÒšj;P@˜À‚*´E; yd&@Ú·<\5ÓÖ{e5M×tíòÊêhÙ )W—BØFOÖèÒV—g*s>qò„sF———S ]ÛsL™™ÁXFÄ¥¥¥Õµ•zX³äé|Ú´}×ÇÉt꽟OgŪuÖ¡ ç@HZ›étÖ÷Á˜–‘RÎ9aè{O¤Ê²R„ŠÉhM€Fi­´6èc¨ªJ欌-/!$Ʀiúíº^‹kçÍT[½bÊ¢Èu=ŸLSJÖ5¦tnoSJ«´â8“lÙ® tŠ¡™tã“»ƒÚ©\pßçœ\e]eÚyÛs«%#Xe€¤o±›ñlË0gíS$hD0‡ÜûäP !sŒ‘ kɈ1yEJ9•±@Ô¥K))é0Lxz|û"ûBaå\Úå¨%R¨¬ I‰}ð)sL™Yz5`ÞÞÙÕJ—ee´.Š¢ïCJ©ÙmƒZéÊÕ¾O®FAM®*ÈiŸÃîî$éŒ V—×(‡ä›.t=çÜuu…3Æ“™5}ß°Rjiy4ÔJ)çÌt:>"B­t©‘LNlPÎÖU5¬j ”SAm‹ÂØùîdÖvYQ_Ö]ÛjÀól6 ÷žÏyj ß-·ÜØËþð‡ßtÓM§fè}øÃ>Uø=Û"žš!À̧ÞRÞÓE]tÝu×ýñÿñµ×^{ªðq{Üg?ûÙƒ2ƒh¥(³ÄSÌZ#!)BÐ1†˜bäd´ÒZ¥”D@¡R¤6Æ8mi…ŠŒRU€˜’1¥T¥³Ö"¾ë«,pJ1x¯ $)Jk•¶ÖV¦¨L)SIÜLf}çE¨®ê¢¬œ…`gwÛ‡@DZë""jcŒµƒá sVJ¡FkqNkß5Leccuss£töèÝGÆã )m}ˆ]ÛÇ4ÙÜ·qÁ|¾ïÀæf½Á’¶Nly…Ñ;ŸÏRˆ„d­ã$E 1¦œYkí …¨ºÎ‡QJÇ…ªºP „9¦”E|EU¢R>t)%1bS€`Læl­UDœBlæó–ƒªÖZ§œvvÆqPj‘¢Ñ:õ} ȸ¢b›1Qš3ùÆOìÖ¥±°¬rvÖ¬­®Ä}íÑI1¢¥•)õóÔLw"éhÈqKËl]NâCê|+^tF¤I'ÎòÿšòK(È‚BÐŠÈ é ÔeèRî5xçÝtËhJh=0º"‚àSß‹ ŠA"!TD:gÈ™ uYè¾÷mÛ$ÊZ["eµ]¼ 3…Œ¾õ!äœ4Ö w¢r.µž†JD83B–$ᔄ30Ç”´TTÔUY¤(ƘS ĵµÕáp ÌD ˆ çAU2sŒ!D¶}è»{ï}?ÐY4°ì%{9F‰‰X˜s×4S³›Cà”›Ö$Iÿ*çôÞ÷}¿w¼—´cöNWWW¿øÅ/žºrww7Ƹ¶¶v&mà²Ë.û¾°wüï|ç»'yƒë¯¿þ«_ýêoýÖo*TJ­¯¯?á OxüãÏ‹¿{òäí·ßþÝ÷—ïÙçÓ8qâÄ'>ñ‰+®¸âïxǹçžûð‡?üiO‚Ý5 IDAT{Ú=ÃùøÇ?>¿ð…/L§ÓÁ`p¯x¿?ß3ÞÛn»í™Ï|æïýÞïýÝßý]ŒñÆo|þóŸÿÏÿüÏÿêIóîîî÷݇g?ûÙ“Éäú믿gáûÞ÷¾sÏ=÷7ó7_ô¢ÝvÛm¿ú«¿úáøÔO9}íÂÂÂÂÂÂÂÂÖÙ—\°´¶tàгÏÙˆýœ»6µcÕíªÜ*ñˆH`•æÄÀ1¥Ì˜™§œB]VœSï½;kA¸kBT„¨”R¨@HrÎBVRhŒSÚ"jÎc6:§˜ÑÊJPAeÊÐ3`Ž1u!€ÒŽŠÂ)"@ÈÌ…«ÊªN!ƒˆqΕeH±4Uý´uó™-Ì`8d‘õÕµUeô`0˜L§Óé´ï{"RdŠ¢À-HæŒDEYÖUi"2ÆäÌ}×Ïgó­­­cÇŽmì[ßÜ·¾¶¶¶²²<ïÖe™SJ!rΨ”F"D$c”µN)!$Rʧ•I){ß—…5Få@pXV„”R µ—£"ˆE˜9çœ2“’2ÖcBÎclÛÖhc´VJMçSÄ<¬KRŠ@rLj®ŠÁ°¨)ƒdFAî&ÝîññÐÙaaJW¨•ÞèwoåÌ Ø—šŒuM“’oãôdr*¨K2fhµJY€² © X‚(aV˜$msbŸ8‹³¨Éç0•0G E…ÊK E &fBEZs²1e$T¨Q´2Ffà Zçæ$)çœ8RRJ êÌ’3CFßFáR$E 8pŒ eCŽ ¥5)R¨ÚY›!Vº`Éœ”Ö€s )Xp…³®pÂYÕƒÚ9Ç9­GÃQaVŠ3O&“ñdÆÐ HH{sh8‡˜sb‘˜’d¶JÇœú¶"qΊHç(gºnmÛ¶§æ@Y–Ƙ¦iΰùÍ7ß|ùå—ïw]÷ݼ÷½ïF—_~ù=_ÐåœÛ¶½úê«_ö²—þóÿͧÿÉ>_wÝu×^{í®¸âЦiNÍí€7¿ùÍÿôOÿtùå—çœà§ú§Ÿò”§Ü«ù¿7k”™ï¹içÞ„ì3÷Úk¯½öÚkÏ?ÿüÇ=îq¯~õ«?ðüøÿøêŽ<žüä'¿ï}ï;õøàT,¯yÍk^óš×”eÙuÝÅ_ìœûæ7¿y&µ ?Z÷è¥ÃQYÕÆQí6çýœBƒ2/@¶ ¥Y ¦ J´Ñ@€)gŽ1…0ªÆÚÌ9r‘®ë{ï3iå*«M2Hʤ”ƒO˜ØˆÑÊ9[ùÐÑ®tuYÔas”H1æ„tila+mm¡ gAAbËs‰‚Y8¤§LCB­†+KÖ8mlÓvmjmLQeÕô*=ZZreqöÙg GC|Q–ͼéÛ6gÎ!UU¥Ê²¾$„”Òl6#EÊZ BÎ9c,g™Îº¶moßÚڪ견ÜÒÒ’&Eˆ…µ…s]Û¥`o!Ó½o¸ª*D¥H i]eA8‹@N9„ Bˆ¨Q”ÖÖBèCHÌY„bNmÛIÎN¥”³ÎRö!Ä”ŠÂ¹²lšYfF"ëlQ!ecLŒœRa¬Ó¶o{Ÿ{p¬s›f;³yUš¥ºVÊ*5(K§MÏ-IV’´dPHF¥›Ø…Ýã­J<®®C5(L¡‰²î¢ô>f 4 Œ…™D$ˆÙÏblÐg4ht"?…f’cKj[t}Ÿ›¾%¦D¥£ha± f/kÎÜ÷!gfW(¥LY*lš6‡Œ€ªTEQ0s×u1$e´Q•Hû4‘F º2F¡ c•!dou¢•Áª“Sʙ˲¢˜Òîd2ŸÏµJ“Qªp€û®åœêª¶Ö, ƒºŠ1*¢¾>³±ªÚÕ¶X*jIiw{¼}òdˆAi½÷÷¦œÛ¶E„á`V›3Í9¿öµ¯=ìa#¢½åIþð‡ïžaóétzã7þ{µ¯xÅ+ÿøÇ?ò‘óª]XXXXXXXø‘8ÿ¾g)ö“ãǶ޶9èÌŽœ-ëv>Wtb …¤­s››ëãñ¸kZDpÎANãñØ[Õµa<›êÂ}Ρ»¶Žïv€T¹ƒ›çŠÖE9XZZu£’”æÈÁK3ó“f>ëS¶ñ{Ëç Gu–r(À†Ý–H9Ô €³dm§»Ó£³»WF+û÷í_[Yß\_ïæÝ¤™#`…„œw›Y iköØ?ZYêcŸRZ^Y"¢£GŽìììTe9 íúØcâBk-•z6›¥BŒ]ß ª²ª+"šÏZ¥t]‰¨®+­õl6»ûîcEå67Öœ±û66`×û²(ï¼óÎùl:¨+cµ-œÊZ)¥´1‰@N)§\Ø…8å”r’úș۶³Cë\‰HÌ€HÚØùlê}ÈS ýÒhXÕµ&Å"M×Qfa‘.ôºm´Õ} ®,b m×:g‘€3’BÈÌ1Ív'Þ÷bX ')ÍNÌò¬™:ðaX•ýÉ©FCœ³ïb¦BEVÊ4>uã~gÊÏìú&•5‚6`La²¤È11gVÂ*+ "1äNS7¨ÙéÛ1b\¶¨°ãfGõÁTCå£K DÌ9™¢4•é½ïS…5¤(Ƥ”&‚¾íû6”e¥ÐäÄ!ÆZg f`æÁ`Bô>ÇÚìUé kPF'Êw?Fµ^nnîß§­î»nÚM¨o;–ˆ¤––F}b@¢®ivÆ;}×"¢&U•ÅúÚªs6z_¹bcsM–‘#»Òî»>˨¬7—W÷-¯VE5ÙÞùö·¿½u|+Ä%…FKƒ”ól6›Lv——FÎhMúLsÎw¿ûÝ7ÜpÃßøÆ7¼á ›››ø‡xôèÑ{îùñ}{ä#ùÚ×¾öþà¼÷—^zé^á·¾õ­½¥P_ÿú×ò“Ÿ¼æšk^ÿú×ommÝ÷¾÷}ÊSžò¹Ï}îoþæo~Ø}nšæ¯þê¯^øÂ:tèå/ù½²Ù'?ùÉú§zøðáŸÿùŸîsŸûÝÍ?ûÙÏzïßô¦7½ûÝïN)}ùË_Þ{…û•¯|~çw~ç oxÃ¥—^ú¿ñ÷luúxõ¨G=âø‹¿ø‹Ûn»íÜsÏ}Ò“žôÿð÷L8ଳÎzç;ßù•¯|åûÈ9Ÿõ¬gÝ|óÍ_úÒ—îU~ðàÁ_ø…_¸é¦›rÎO}êS_ð‚¼úÕ¯žÏçgR»°°°°°°°ð£uòîÛMê©kÖ4 …W´ÒPä ¨‹eJ¶iš8 )­,{ú¾o»V#•ÖYk™2§ì½g£53ô}ÐÖ–µ0ƒ6 bfiÛ®*åLAB¡¡u1ÐFçóY¯8g­hÁ¦( ˜ÏÛ©ä¬kºvëĉœd:’PÁw~Öõ›÷9ï¼ñxLŠ”Q,•õNw§ÓiÛv"9†0 VFKƒÁhX šÙ<åÄ1gHÚ™¥Ñˆ%;k0笔‡9IÎ|XZZÊBÇ·¶ˆ„9´ó™÷]ôª¢Öuß÷;;;}ßWÕÀ9Û÷=3‡Ã}ûöÃñx|×á;¡(œ÷}ÛµZáhiä;ŸS€½ÉÌRêÉöÉÉtÚv­ÖTêªp̲}r»ïº®ï|Ú`@"$BEÊ袮ZŽÓY“R ˆHˆ!FA&REQ”® g Y$-€Ä Üæn·Ç’LéÈ(ÕuScL,*“Cª ݉‰Œ¤ÛÅiH®dö¡ $š +J9J’¬Ê ɰ¨Ô[îŠ Eì-a© ç•¥R…VŒ¦gè$ù”ƒ„ai— g•bbÊcÞÛì4åŒÀ"rnÚN³ˆ‚ˆ” ·ÑBí4 'ÌQqR¢µvê ý±c[J+…d”º¡C“}Ž!æœlQNfóÞûf>ïš& D8å÷6G)œ·Àã¬5Fg€zÉ‘pffRjßþýA qÿÁߺ喻îºK;;o#礵Î9ê:øPºòLsÎ}èC¯|å+÷wwo¾å­·ÞúÄ'>ñß%ûu饗ÑK_úÒ—¾ô¥§ Ï;ï¼½)šŸþô§¯¸âŠ«®ºêÙÏ~ö^Õ׿þõ3̦þó}¾îºëžþô§?~üSŸúÔ=ËŸÿüçßpà {ÃGï¼óΗ½ìeï~÷»ïÕö®»îúå_þå×½îu¿ò+¿‚ˆ{Kýã?þãŸüÉŸ¼øÅ/~ñ‹_|äÈ‘7¾ño}ë[Oµ:}¼Ìü¼ç=ïu¯{ÝÞéW¿úÕ§?ýé?¨ÛñƒüàŸø‰ŸxÉK^òÝUƘ+¯¼ro rß÷ozÓ›î¹ÈÐék~´òì¤Á¦¸¬H5ÎR—±Š Zf]ê²ÊÌ)qR Ä9‡ Qß HˆRB­P™”ÒtÖD`ÔÚhMƒÂ•¥õ`HÖDNœ¹(J%Ôûf²3Ù>¾Ýλõµº®¬sÆ(…‚œ%§è#fÔ`H ÊzmeÃûÐu°t¾O)­,¯®–úÞç,¨Tæ,)gA!Eá˜Þûèk¥ ë [Xel©)C3o’9£gŸSj»fÎy0(×WW6÷­ånãÃ[ǶæÓùÁ³Î‡³ù,¥8ŸÍ·OœTÖê|×̱ªk£¨ïÛ¦qJëÒd2µÖóÏ>kÿþÇî¾{¼½c\ZZ±Öž8‘bø_3¶B¾ïÅJ1gVÖ‘5¦÷b¤®³Z3€ïû¦iúÐ3I5° (e("kú"gLmBL}ŒBšŒ3&Å)s¤P0eÎ1DßäDÁšÈdTA´²¼’Vû8DtFÕ®ö]ˆ>¨U&’à%Ænžæ“b´bliP;‹IqL‰ a€ì€ëÂÚ˜uð&'“jèç"S°œjÄ!ÇbbN¢LPsEa0sÓ·H‘Î,)ePÚhm‘tÊIY‡)u1ö“‰±†*¥”±ŒDUa cKk5ÍIqR¹ äê²O¡íÛ¾ïvå Vd@”"CD3ïîîN&»}× ³"2ÆÐÿþ“9çÌ9Ag³V@Ú¾×Û;ZÛBÛ`ß´±ë»¶][]«õyž¿º±>o›yÛ4MÃÌ",VëÇŽ[2¸½½}†ËêÀp8¼øâ‹»®ûæ7¿¹7`õ¿]|ñÅUUÝyçÇÿµý!õYk}ÑEc¾ñoÜëMã™8묳677¿ñoü›3QOï¡C‡677·¶¶î¹É›1æ¾÷½¯sî–[nùîw˜§¯]XXXXXøÿ­›o¾ùL.Û·o¼ñoü¥_ú%k­µVkmŒÑZk­•R?À.}ò“ŸüÙŸýÙ3)üä4ýã߸նeæ!ú³i¼[(íÊèÒ£ãjeÞÌ ì‡ æÞ÷Yx´´ )Ç%eÎ9„ˆ¨´1¢¨é}àÔ · ¡.«ÍÕ•ƒkn¹í[G>zÎ<,‡;G·wîÞþ—¯}ûÈmweŸ66÷)¥…¤,œ!âÞÇè9gR ÅÛ¾ËÌõ`¸·¾³tmû6.–@ÐûC0¤A‘BÒª(œ±j<Ç;»;ãB銵•ÕõÂØfÖlŸÜÞûGk+¨`6›v]SúÂóÎ;tèœàÓ·oùÎwþåVßù .¼H)7oæ)GWèá¨^]YëÂÉÇcŒUUïN§·>\Õõ`8 1íîNТܷoÿC~â¡çœsîÖ±­ÿ÷K_nšæÜsi­;rìØ‘v>}°¤õ°*+ !FÎMßeCLWW–¬6}Ó̦Ó̹TKËË]H!ŘX;¬RÇ·îžíœ ]£µÒ}:”)\YÕ`8\^[ß(ŠER™çso / «ÙR^ªŠå¥ñÖÉvg>ßžùy0`–£nÞu!5’[ÂV©F«^)ª*[/õ°¬†U=`–”3hbESà<( næÐµ†“F?‡®qÉ×’—4-Yc˜»¦²¬MZgm¤p„ÚfT‘!²RF€BH"¤ŒUÚe–”ƒ´]7kçÞ÷¤ ‘)hÓ SZUj,”XHÄmö um}t¦X,+V˜AƒR¤(æ|ëm·ž8q¼k["*‹¢,œ& jæC ĽՃöÒQ£537]×¥H”b †ÂûÖ7ömlG#ë,iMŠ(§4T«Ë+KƒAáÜö±ã“»ú?ôïy6›íí ù_Œ™¿ï5i~H}N)ýg–É9räÈ‘#G¾¿xï¸ãŽ;î¸ã¿øWcüÆ7¾ñýÕ.,,,,,,,ü)Ö@Q¥ˆê2ûÀÁ‹(Vºk½1ûX¬Ó9ë|×µÎY£t–cPH9g¥´Òˆ²i-‘}ŒÐ9]ŽJ]je‰!!£¤ÜNg³ñYÖ–W¬.VVV!䀈ZP˜$ƒ2ˆM×Ì›Æ{„!ŒµR«ëëeQæ˜SL¾÷ έ-rLÍ|^(½²¼äœc΂Ph3 m4b3›Oƻݬ±Ênnl:W Sèc×vÓy“SvÖc‚'fnÛ¶ëºÂ–ƒº®«*Ç}(U]–]/œ8†HÎdÖŠú>µm“RP„Þ÷ À,"œrjÚæèÝGEd6‡šf¼›››]7ŸÜî»]á½·Æi­SæÝɤñ½«‹½¡³Â,‚ DÚhT(($JŽÁCËà Zù9F­ ³$Î ao£¾˜cÈA‰AffF Y³¤©ëû.wâÊ`h¬+œú˜|ôm7ÇŒˆ…R€ ’S3‡Ú¾ì&WÂh‰´B¥Œ³¨s” ÕØ{ ž˜H!‰ë˜ ‹H”ÐJ‚BmäµvMàQ$#ìm<ÂÂ]Œ" ¡¢ œ8çŒÂœ9g… ÂA‘h-V\©LmÁ‚@&ŸBòV•Ö: ¦0¥Q6†”#gB£xï'("…"ÂŒ"ŠˆöÖ£ ¡k["D,­µFk­4"ÀÞoÝß÷3$žæÙööö­wÜ^UuYWEU–eYjM¸occ4VuµcsßêÆñ»OèÅmhaaaaaaaΈ¿ø«´RJ«ÿç©O]|?(µ@©•E4ZÖ†ídÖv‘“Q}kë)"‚("笶ŠE”RZ)²&g#IÀZCÊ„”CL¨ÒÈ!¨Â V£µ¡.5«Üû…2ÄLWì"9¥M= F›ûö ––úÐO&»}Ó1ÙÅÍ Øuˆªªjeìl6íƒïšÎj[Z×3ôm—B´ºãÌÉ30[®Èœ'ÌÌ}4¨ê¢Vƒ1íìîŽ-›¦·¦PÚŒ–WЧ,1¦cΙˆbŒ1Äa5ZŽ–†£nÞÏ&SgJR”cêCK$Z©Ñp8NQ@Bð}?éc`Îmۤ锔6Æfñîø[ßúç­­c4ŸO··OVE©«A1 H©”RÄÀ¶”8ø™•±DŠAö§ 1ŠHßûbȱO¾ñ}bÄÄ’2÷¡„>Æ$8gNZi­÷† 7~ÎŒ2„¨HjÉŒB1'‰>HŠ“Qc£¡SÚ(==9éšN£¶ÆcµÆ,`Ê»ÎÏç Lw]U”U©«Rk¥SV¡GM¨„)eËR+Ҙшˆpà¤-‘-A«„„sLV)C Y8eö)2$•‰Q$§.F$„ଖJ#$Ž)BŠQøÿcï΃m»ª‚Ñ1ÇlV³›ÓÜ&¹! ¼¨ ¨ˆIâ@yTES¡Sª,,l @B'bÙ…FÐÐÁ hLÙ^‚”@šÐë#ŠJ# 7íÍ͹瞳ÛÕÌnŒ÷ǶîË¢ò}ø}îß_k͹æª9÷>gÕgÎ9VQlu1®ì¨,†¥.ITFŽ•ô •RÚhgœ&+š”°ˆô!æ §ˆˆÂÂAD´&¥°m›¼RJi­ÁZ‹ˆ„˜TbJ9ä¶kgÍ'ûÚmŒµ¦, Nik¼q÷]w{ÖYÿ×Ù率cθŽ9×ÖÖÖÖÖÖÖþ«¸ìÿÏjmíú£ø²,È,†šÔVe):)*ÊM“+][eï'Wïû¶ÍZ;kª²ZΗ9³¦”»Î·ÞS DÕ¸£"@Ì’ƒï)“V¤2–íq3œ·Å¢Or.œ}ЃŽ$á“;;»÷î.Â\idrUËÁ ªKcí©ÝÝ|Œ±kÚÑ`hÈ Pá\ )Fº²Ò–Rˆ@rîÛv¾¿Oΰð¨ØÜj—Mß÷û{û1¤Ñh\UõÁCg0ª¦kZ¿Œ!8Á|6›Lö¨årbæe³Ž6 gcðËÙ"E?ŸÈùÐx4ôýf×6³Ùlo5½_,›”³ÖdUŠf³ia<WUED}×µíR0¥”ʲ역÷±®@Db ÷ƒÁÐÖU’ÜtMâŒ" (̨”6:䨴]Ï©ŽuštÊ’sÖ‘CÏ1Æ!*è|ñ1f¥4Aèr$V£ÚV F$’} lL¡lŽi9™Í6õæÖÈ ‡eQiÒ'îºG…)¥³8ªH'Ï9d¥¤oI"qPÑ[k5ÖæsÌ9rôè#i§E0e…ÈmJ)°­ ­)fnû|¨ ˆÈô©ë|ïcQÚ8¥ ­•(d@´†´c@¡Rhsè8 GàIãÒŒjUQ€èsŸ9gJ]AƬ²A`¨ªšPÇÛ¦õ½ŸO&ËÅ2ÆÈÌÀc !FE8 ¬Ñ)ÅBÎ@!‹Ä;ß÷>Eᜆ¦ï»®O)‘1å .ªRk“R œ'û{;÷Þ{û±¯ÿ³Ç[·ÖƒÍu̹¶¶¶¶¶¶¶¶ö²ÐO lR m§¤³, EBÂf¯*·Œ3]H«D>ö1¦”D“B"fVŠ åÌ H:g‰9uaëR4w©éRçêR`•:…¥oÚv1i3B&”¾oŽ¿kÞ."gfIAÑÁÃGŠ¢@«×€ö};M»®Ç}×ErJÖXSÙ‚GðȹDE)çœ"@αïEXº¶]íº4Æv!@Û‚Ò‰ûî9qOJž9!€÷þäÉ“Î肊²(6Çãf¾ä Î¥”Ö¶MsÏñ㛃C­™sŒA[7 ªáÀn¾Xö>ô}oŒé{Ÿ3“"C¶ëºÖÚÉt2›ãr¹ˆ!–EÕæ&¥$"Æšº®lY‚VÎÃÑ æä½'ºúý=ñ)%>§ÌÜ·MF¥9gÉ™aU $޾[.Wi˜’000‡ ÈZ qhÔ…#¦BΨ€r–ºªtaºŽûmcµ¶D9E´” Tá” Š˜1² @IV½èZ…Q1ç¦MZõx0H~.¹Ë}ŸZMel¡•­ªÚXׯxro׊ª¨0¶ÒÎrîrÇ]‚^Ú¥.$e¥”¶¨(2Ǭœ‰ )sI¤""­5 fU·=*7ÇÊaT© ¾-€Ø²ÐFªd#ýÂÇ.q[9RF@—mLˆШœ6)Åãt:Aº®9%"U–åxcT–eÌ)5KcL]•ãÍÑî©}i»¶Y,Û¶GA4¤ŒÖÎç”R X¢&b€¾ïwúßz õÚÚµµµµµµµµµÿ£9WFÌ @iê!•N#ƒDãÓ}?÷Y±Ph4iEBÂ97ËFŒ1…qJ›œ³±F¡jcô}nÊ­¡.­(@Âáh€„¤S—Ò"xï÷÷÷î¾ýøbº$²‡Î82_.ºà£ÑöÖñöÁ³Î8Kk >¤Úvyjow9_Ü:h´¶@‘¢²@ݲͭÔKÚuJÌ)'Á g$… {ïgóyÛuÚš”yw®ëýhŸ Èb1o›fs´ À™3(mŒj†âÇ6¶·”¦S{»Çn;vjooks“úÚ¾c$5$ "Fß7œA@Û¶÷m',ÆXkK"Ò†ŒÑ‚¨4*£”d‰1„ *$É 6¤ÐYt¾ ]ZwàŒa½·3Mž…W¯eÑ cdNZ@å䌵ˆ¢„˜³`ï—ñSÕ¨'jBV’9' QkCúŒ³ÎîR̨$10h†Ì0& Œh ˆdä,>rȬŒUÀ÷“ f”€ ÎXkŒQP·5râ¾ë»#i…€‘”R¤(AT 0§Ø÷­ï»œCˆ!ø>¥€Æè”c A‘"M"’s^Ìæ1%­T]×F!9ëVëŸÉZ›/—K†Nµ6ÖÙ§Ôµ­â¬´aæ:Li½¶ö‚G<â«ã›o¾yý¬­­­­­­­}YcrЉ%+ ¦,{ΊŒÆ%’^ômŽ¢´FVM3Î, ”ÖQ ŸÍº¦ ý2„–™€9'Π@”¡bÌI+•Bä”6Uîcà `$Ð Tйë:Î ˆíbƒá0…>ƈÌÀœ9+¥ÈÚ s^Çœßy¯|å+ðp4mnn"âÿ.Ý~Ìcó²—½ì¡}èr¹¼å–[Þð†7L&“Óµ‡ºêª«~è‡~h±X\wÝuï|ç;EäÖ®­­­­­­­} ³Ö@>aÊ:K‘rˆ)jÀ‘3„J+’……sj»¶Ð…äœbJ)ƒÂ¥M :Isö½¤ìhëІXÌÅ*W››Âì´uÚu©å°·\¶wÝu÷Þî^ŽlœqÆiCƒAµµµ}ÆÁ¶ÇÆÚ‚qX9ç Y…µqC[´ËnžU—ÛÈ!‚dNZ0±„®Ë"=ǥªª¬Ó¨V[þÈÙj4H |¨`´9v…+ªÊ¹´’r\eŒ‹fÖû–"q\½3Å *cßv]R9¤$DŠ•4¾ÿúm·©¬†ÕÐhK”Rˆ¡Î9ãLYÎÈ9Å 9£!Dɨ°÷}:WÙÑpT9æ¦ïØgŸCä4Ôõ°>|Æ¡±¾(ì`P•C­Êa] ÊáxäÛÞ‰]ïƒ'mŠÂ¡Rƒ1KbDA$T…µ•³(1˜®iÚ ¥2U=D$ÉȘ3£°eɉ(öÉi2v‘3R16} 1…œ´HÌ Hˆ4"3'ÖÚ *ÎYBEY°ñ±,ËàQD8mA˜B4õÌ1F£T; I‰ R„5ˆÎÌÑKì8¥¤¬¸BeÌ!çÀ…û™=Æ´ÒäªQÝö}v(NéJ£U ˜9±dP¬h•´äÌ€‚(âû6ô­ïûÅl¶œ/|×INZ#¢‰9å(€¢4‰HH!å¤UEÁ,XG¨Rˆ1ùä"#Š€BMJKæÐym´Ö:ÆÐÌ3BbeʘA)ã¬Ñ6³_ÇœßyW\q¼øÅ/¾úê«ÿwéó£õ¨OúÓ·Þzë[ßúÖ\yå•—^zé%—\cçÜ_üÅ_lll¼éMo:ï¼óÞö¶·mooÿê¯þêªíý×®­­­­­­­}wqfÒ¦²¡Ö„ ‹„J( `L)—ƒ:÷]Ÿ$‘¶¤uJB1I¹Ï ²ê õ’¼bÔ¤kçF8ˆ’GEQÖ•FmÉh¡ÜeR:ôa6ÏçsUWƒáÀÆ£Ñxä —r Ñ»ÚÖEŠûØÒh<ÜÚØ¬]y×wÅ2ø®!Æ`•ÍÅXÃ)ú>é.D4^YrÆjMJ±z ”«K;Îæ³R=Xk\Q*R}ßÏv&õ árPÅÛù"…HšP) ¥q…[t (cßÎZf.ŠDš®—£ñ¦³‘¦³ý¶ë]Y”Uå\IZ @ʉ´3ŠHeoq‚˜A\éFã!.šE×wMÛŒ¢/*·½½m9qï‰ýédçäNJ1sVš¶TõtrüÎã‹Ù¼ëzÆšH)ôÀ¢IÛU¦Tã ,ŠÒ••+RJ]²OìcR!ôÖšQeÉ9gAB ÈX‹šTʨû$RJ,‚ƒØïýjúÄ9‡…%ç `Uä Ì‘#°Ä¶U]jct1(‚daLŒâçóŃÉÔÆhmf]?ézDŠ>G#'O©…hRDÄbJ“‘Åa9ªãápkcwo·ó~0p"¥Ñ´}ß·½°”®ˆ:ƒ­º“÷¡ëú¾kç³ér¾È1j… q4™Rçû” Æ»®SJU®Ì™•"BA ½Gk™YZk‹¢ìš”JJ¾m W8g•±!ª|ÊIk]Xƒ>¬cÎ5€ŸüÉŸDħ>õ©Óéö÷÷ßõ®w=êQúüç?ÏyÎsö°‡]|ñÅŸýìgW¿~¯xÅ+ÞúÖ·®.¾ÿÚµµµµµµµµï.gJ"mŒ³¦PJYMŒKšÊÚ ‰ä„֚ʸJÐWʈ¦p`m7Ÿôœ#жÎVK­µá˜ù˜&Ó…#ëHsÌóS“S'wï¹û¸dFÀœRð>ÄE’pÈiѵÔhSÙÁ°îc e*klU¦HYôÉ]W{™A›ºCUUTX"£¥÷ÊwEYÔƒÁææÆææFYŠ0ÆÐù>¦¸XÌ'Óý”"“RX,æ, J¥”| zOU¥S!Æùrá—mQ•>†‚Y)M>ÅÊY$Z¶m×¶ÃÁ`c4Vš´ÕÕp0¨kFI*cÆÛ[m·}wj6IÀXXçÊ‚´&k‡›ÖÓé,åœrv… F>f >„Ú¶uÎý¿_øÂñãÇg‹9 §”¦ÓiQWƒÁ`¼1šL''Nžè–såæÖÆCʲìÚÆÇÞ{ÑZ+£…%*¥ô`0<|èN¦““'•R,Òù^ˆ”¶‚È1Fgµ2”Sj}ðQR”Z¡!ç4Ù4"§æQ˦é{Ÿ,+“…%øC³Ó®°N€€‘ˆú”{ï{E%i“‘²R,9䘓àèЪªú»¾ŸŒáVP—˜<ç;IŒ¢ˆ”ÖLàSÜCY±Ç`З”°Dk imÓ×õÀéÒQˆDfV’¥ë{`1¤œ+ërÐ6mq>[øXÓ°*666”R!§*Õ HŘöNí5ËeË`ÝmTÆ Çzú~:™ÔãqHIi¢º(:ksÎÖ& !tM}ˆ¥µÖ朽÷!„˜iƒ€êôo㳞õ¬o¼ñQzÔg>ó™ýýýO}êS\pÁ}]/¾øâ›o¾y2™?~üšk®9½eñ´½\pÁ§¿Ågœqú‚óÏ?ÿÿøwvvöööþôOÿôÁ~ð}›?øÁ¾ùæ›/ºè¢×¼æ5·ß~ûÉ“'ÿèþˆˆ¾mŸïÇæææ_þå_>ýéO¿oáÛßþö7¾ñ«ãóÎ;ïšk®ùêW¿:Nï¼óÎk®¹æàÁƒp¼W\qÅŸÿùŸŸ>½ð ?þñ?ô¡}€ã}ÌcóÑ~ôÞ{ïÝÙÙùô§?ý£?ú£ßtÿápøŒg<ãñü¿ëY<g³Ùé(ñöÛo€Ó×ÿðßyç«þðÿ°ªª'=éI¤vmmmmmmmí»+ÅÜw¡™·±K¾K¾Ï)@fJL]Çó…ߟ4‹…RƶÓùr±œvý2¦&ñ¤mç}ßs¦ÂmÜ>ëœsÎt'÷wNœ<1[.\U:ãðæöÖh<ª‡ã*Rìú>„RJ1!¢2Z@|ïsΤµ6V›C⬔r¶ ÊáPY×sžvÝ´ofýB,×Û寙ãÍ#ãÍ#£Í3‡ÃCU} ¨·]u ¬V4T4Ô4´80\)©·¸àtª]ž˜MŽONÝ;Ÿì6³‰ïf!Lúnw¹8Õ,ŽÝ{Ïn3OF³³-Õ•ÛƒóÜ,d\±֛ÖlZ»åÜVa7 [¶ÙŽÜøðx|hl‡%:UŽªáö¸Èè2{vÊ ËÑæpkc°5(dž\¡ËA5*L‘/¦ÍþÞd1_v1¥”cˆ!ĜهB`¥ˆÊ¢,ŠB‰0€”e9˲tÎ:gµÖ1ßõmÓtM“bTˆ†´ÖÊSEU”ÖšÞ·ûûû{{{óù¼mۮ뚦™Í¦}èþÿyÎsÎ9çÒK/½öÚkßõ®wõ}ÕUW]ýõ|ä#Wµ{ØÃ>þñá _xþóŸøðá«®ºê¡}èãÿøÕ¼óý·½»»»×^{íéÓŸú©Ÿzä#™RZž{ÿüço¿ýö¿øÅ)¥—½ìe7ÝtÓ\BX]P×õãÿø×½îu›››ïxÇ;B—]v™1&ç|ÿ}¾“ÉÄ9÷‚¼àCúЪäСC/xÁ ^øÂ®Nþð‡ŸþùoûÛ;väȑ׼æ5xÄ#.ºè¢2ÞóÎ;ï‰O|âéÓ'=éIãñøŒwccã£ýèjD"òèG?ú /|ÿûßßûŸ{î¹G½õÖ[ýèG?ðgñûßÿþg=ëYO~ò“oºé&¥ÔW\qâĉOúÓ§¿ý/ù˧/^_pÁøÀ¾míÚÚÚÚÚÚÚÚw—÷ÁZg‹Â€h­@‰ €FÔ: ²1Zk-€1gf‰ " ôÑï/æàh´1lÊñÀÖeŸƒs…Ù@VCb6àƒß;¹wïÝ'NØm­tÚØÒ*Õ4Mï{ã ãŒvÆ–Ö6G F£ÁØigÉŒCW•uEU¸ªˆ!žuÞÙ[÷Þ{ïÝwï|Rèû.3kRŠ™cŠÌiÑ.Y2*5êaÝu] "5ic´oŒXXDB×Ç”Rfé}¿?™„”Dá¼Y.še}ʹó=ÂEÛ(Q4YLír±˜çœÚè… HlÚf²˜ù˜ѧS@E:ÎöÛb 9DM*DO¨›¶MœµÚiÛvõRmHk DbØÛßÎMÛTƒÒZ]…¶†´FTÀà½ï£WJkëÁ „cÒJ·m{êÔ)a™Íf«p³Ù¢ÖFiÔÔû>¦ Š Ñ(#„¬}_%½¹ét­µAbc††´²Î±°ï}×´mÓ…>w¹I¼ÈÄJÀš3‹Çˆˆ¨…h È()¥ù|Çn“,rïƒ&Í*Fý¤ Ñ8]T”ZåÌU†P¡‰àF…v¶]U"‘q6 'QЬ6(2ºÄÂHJYgÊ¢Œ!Î&“¾Û[.›àû¾ó™!¡÷ÞûCŒ95ÎP%€`¡CâVoq)Š2¥ #§Hˆ¤I!(@$¥té¬3™S×u)%DdfN)ù¾Ï*ýkkµÖ/ùËoºé&pÎ]sÍ5G޹çž{àçþçSJO}êS‹ÌçóßÿýßÜãwË-·|Û¶ß6æ|ï{ß»:~ÚÓžvÑE=ïyÏ;uêÔªä×~í×BO|âçó9ÜrË-·ß~ûÿøß7L€<úÑ^foyË[V…ß¶Ï÷ãú믿úê«···÷ööàòË/gæ÷½ï}«Ú}èC7ÜpÃé‹÷ööŽ=zá…~éK_úO>ï¼øÃ·¶¶^ýêWá _€øÃß©gñÑ£GŸýìg_ýõ'OžÜÜÜZcÈÈÌ÷M“´õd‰QDA=¬HéŒccŒ2ºªìæhC–u5ÝŸ”Ãj¼½9[.”VHJk-"«ÙŸ;בÖ&§ìC˜ÏçÉH¬@YҚȹ‚%¢”S ³BaÎ)"jk­s–yDD)Åœ³+¥D$ÄÕ·ä­ýÔ§>µ:ø§ú'8óÌ3WqãcûØ[n¹e¼ÀŸýÙŸ.ü¶ms«cf>=Ky_ßó=ßsýõ׿ímo»îºëN>å)Oùä'?yäÈ‘#GެJî¸ãŽG<âßÔöÚk¯ýÖ{>>ÿ[þäOþäÍo~óe—]öîw¿žùÌg~ìc; ‹Èh4zúÓŸ~î¹ç‡ÃÕÂÚÇÿçcÎûïwÞÉÌ¿ð ¿ðÆ7¾ñoþæo¼÷ßz‡¯|å+›››§'Š sÎ9çÊ+¯ÜÙÙ9zôèÖÖÖsŸûÜŸù™ŸyÉK^²š&"fÞØØ¸ð O:%""rzóý×®­­­­­­ý×Ñ÷ýé?ÉþûhCOÎ „˜@!(΀h ‰!ç”ú|ŠZ;²ÄJgH¬T]ÕÃ[ÕöÈT4‚a£ !¢³N4y2ór±0sH!¥œ2ë̈ÊhMD‚¨ÖÚÆ@…5†È÷Þ7]Œ1+ED¤ŒRD‚sΜ³0£Äû¾÷ÁWuYÕUÛm»è|ˆ9jc”&W¶°ªSÆšª(±kºè½ ômÇ)ÒDZ„ªœRb}Þ«¶eTŠifü—‰^eÉ9qî£ìM½ÏR”F[e­beAiW£ÑÀ:c˜N&ƒíaÛvÑçœ gɉ™1zö}b–UŠªe³Œ1*£ui­µ%”‚Øu¾-‘ †ƒQÕ4]1´Õ¸2…VFY瘙Ú·ˆ¨5 ²EѵžE4™ªª•Ö‹yãsL>§6óRTF§R¨P Jæz‰óyÛµ1úà=&cÖª, £U»˜…‹­u*g¥ºSŒ©( Œ>pÎ’JÑH„ X˜D¢3ErΉ3 ç˜") j­©mÛ¾ïWSæœR–ÿ!æôÞ¯®€UÐbŒYnmm­ÒɬL§Óã}ç²î§-\tÑEŸûÜçVÇßøÆ7Î?ÿüoz ƒ£G~ñ‹_¼òÊ+OÑžþô§?íiO»ïÅߺyrµÿð›|Û>ßÝÝÝo¼ñŠ+®x÷»ß}Î9ç<ö±}Ö³žußá|ìc›L&ŸûÜçæóù`0ø¦ñþÇ|ÛñÞvÛmÏ{Þó~åW~峟ýlŒñæ›o~Ñ‹^ôÿø÷½˜™ÿÉ{Þüæ7Mö÷5Ñx8tΞ}öƒ677µí²?pèðÙçž9ííïBd4/sJi¶˜-Û†%·msX¶Kæ¼¹±©H÷Á[”UEÆ€R€˜rÊ9»ªRD«‰ª’q¶Ô’³±Y,§Ó™!­•æ“&B…DdQ Ðgtm­+œRŠAu½±±Ñ6-‚3ËŒM!AV¨´ÖÖ:mM™Â*þÌ•R¤”6I!dI9Å¥¨Ê1H]ª¢T˜r†,]×)Áº¬ 爔ˆ¤˜}ðØš†´- 2Z‘R …5‘*ªÚƒïÛ®¹÷)±dU ¬uN©’E²å`¸¹5Ö‡›£ƒG·mç}L1{ç³yΘ£,çmß{DT¤’öà“6ÊÕ¦ªÊ¢*Û®ƒ%뤬+†£Áím;›g«Ñ@†´6dtˆ¨”±N‘n›.g€¬€‘#@ ˆQ±‡Ø'‚¨ §Ä Ì’Sôm•¡OÑÇD²sF€P±B†eᦓS ˆ iS׃¦i§Ó)g"§ŒŒ•)Œ³˜çäˆVÊfÊ9ÎY!¬¦:Q©Â8M´úµÖ¨0DŸ–)¦ô@óÖ¶m{zÏ!”eiŒišæ6ÿÊW¾r饗®Ž»®ûÖ ÞûÞ÷ŽF£K/½ô¾t9ç¶mßþö·¿â¯¸ÿûÿ«§ÿÉ>_ýõ×]wÝ™gžyÅW4Mszo'üæoþæßÿýß_z饫¼ÉOxÂ.¿üòojþoíeæû¾´³,Ë×x¯»îºë®»î!yÈSžò”_þå_~ßûÞ÷ýßÿýÿùgñ%—\ò‰O|bpÀ7Þ("{ÜãV1ç±cÇV©ŒV×{ØÃVðêâû¯][[[[[[{à>ó™Ïh­µÖtJ©ïÈÍsgžyæCòÿv1g¿hRHŽ´±C«”vD€cB™7}š$9‰€ÑbA;qSm ê!XSJmˆ%“ÓnP(‡À€JIærh|îRheWã*ñaèJʨ‰ rdA@8ÆÞ7Ëe„\ý²1‚«´.À`H£›}ß ‹WUµ¹±±µµµ½¹UWÕþþ~ôQž}Þ¹ãñøØÇî9qb2Ýß:´Õ÷}ç»ÙbÚt­€¸ÂXWͦ3ÉÙh*Š"„0¶¶·KWä8¥eJœXk2Îu¾;yÛ©É|f Wº—ËåþÞ©”âÁíƒN™åtžbJ!¤œEØ Úh ÞwM«IƒÛŒ1!Åáp8û®?~×]ÓÉ~×õ)$­u]Ö«i–Õ_ËÖZmMÌi±œc|{{{¾o›fÞ÷ˆÄè{º¾ë½Õc­uâb!ôÁ÷}¯…|˜Å’©Š¢4.¦™Srfk¬ÖÚ–dµÖ¤“pˆ¡if–œ«ªZÅÅ̘ò<û¾ïºœЍ =žÌ'Ož:ó¬ƒgœy¨ó¡ªê² "¥tJùÔÐdo:™LRNÚèbè|èµ1®(ëº:xøðÉ“'‡Þç !„˜oQ‘«J$sV ”ÓD¨Á–l0e/{÷Nwî>•RN1¹¢ÔY+B]¡eö}×¶3‹@×µD¤µÒšbDp1«¶Mmßæì7ÆãsÏ;o1ŸEUYç”RÞ{ß÷’„§”‚÷)gÌD¬69³Ó¤‰"" (ZýÛ­6…+la1€hLçœ#"kmç»Rã›sþÃ?üÃcó¥3ÀcûØUál>ŸÏo¾ùæ«öU¯zÕÓžö´K.¹dww÷›ª>÷¹Ï=ñ‰ODÄo›øç;Þçn¸¡ëºË/¿ü™Ï|æÑ£GOÇcpþùçÿîïþ¨à Ox·6_åàÁƒß4¨S§NYk766V³‘?ð?ðï±cÇÞñŽw ‡Ã«®ºŠˆN÷677/»ì²ÝÝÝûî8} _Ð}s:tW/ç€O~ò“¯|å+>¼³³O~ò“àôåû¯][[[[[[{à.¾øbk­µVkmVim´^ïXùOjÄsðý6Uon «¾®(‡ƒáÆp£ï[Pïë6v]ôTºzcV¡Óf\é² ÞZIì˪¨‡C­©éÀ¢•–¤æþ·ê IDATB›ûi7?µÛ×¾Á}ØŒÆUX4ÄRW•å¸,šf>]N&³É~LÑ®,+dU¢¹X™N§m× ÅQ]eïsÀÀ*jBàÌ)"Dì»n>›òx4jš&ç|äÈYgu¤K]ŒqÙ.ÉPjȾ÷F›ºT®@ê®;îÜÙÙá”—óy³\ŠÈÖæi=™McN‚X×µ-\NI)¬ª*ÇŶ=°±Û@#Œ!¤” crξíôpP ämfi>™Ôu­ íÜsüXÓˆ!ÎùÞk­³…ssˆhLQ'Ož,Êb£ØpÚ­B aY.º¶M!ƧӉ±®® cÔZ#bï½ 8p`7æÔ§ÍäRë}ß÷Áç0qÐцSÖ„åÖ–#ƒ9Q=dÎ9&ßu…+¬v“ÉÅôì gÒ úédF6 †EŠ)ø4Ÿµõ°œˆ®(ªzPåöÁ#)¥¾õ¶ðU±®ËœsÌ º¶GPJ8k2F»¾í‘ˆ´*Y˜~ÞûB𣭺*¥„±™5ìAG  ƒv:ŸmÉ“Sò!´)ô)¦Ù|>›Îº®×F×UeÕF••aV)‡”’"P>t“)ÊÚºÒ9×õ]×÷"è\y䌳B)Ķéæó¹ï:ß”¶oÛóx<>|ðP]8%¼l–§S+ŸŒÓcÐÖÄ”P¡sn5Õ)"u=ÐÚ¨ÃêÆœïyÏ{n¸á†7¼á ¯ýë:ô[¿õ[÷ÜsÏ}ßùñvÉ%—üú¯ÿú›Þô&ïý…^¸*üÚ×¾¶ x^÷º×ÝtÓM×\sÍë^÷ºïýÞï½üòË?õ©O}ä#ùŸÝç¦i>øÁ¾ä%/9÷Üs_ùÊW~S4ûc?öc¿÷{¿wçwþÈüÈÏþìÏ~kóO~ò“ÞûßøßxÏ{Þ“Rú¾°šÂ½õÖ[àñ_ÿú×_xá…?÷s?wßV÷?ÞÇ=îq_|ñ>ðÛn»íœsιì²Ëþöoÿö¾'œuÖY¿ýÛ¿}ë­·þ»bΣG^yå•/zÑ‹þàþ`ccã-oy‹ˆ=ztU{íµ×^yå•ïz×»~ú§ú¼óÎ{Õ«^uã7®ví~ÛÚµµµµµµµÿžÞ{Ýü«åÏ{îsþ÷$ZÑÆäÜb¶ˆ–IE†Ðf1`EetQØ) :­–œ«Øb€$š£D"•$w}»®ëšÎ’“ –“nº; mÛ(>vÜ¢¶Zh{<‚,–´ˆ !ĺ(‡UÕv±Â6„¸ô.H)ôÑEã©“'‡ƒ!Îg³ù|‘}ˆ!ž¼÷^«Í½÷ÞûO_ûg@<ûÜs+Î<óŒ³ÍY®°Óål±XìMöh—fóiß÷9±ÕÖ(=Ý›L÷§!$µì;[uU)@­uÛ·D´µ¹© —AD$p‘¶i9%aÉÜ·-$ácïSJn`´±ZëÊÆZ…zÏ Yrìü Š”¢®ñÍB¬‹EQ•emµ­Š$™ ªJT*çœRŠ)¥œ€A¡S„¬c´±,À ÚEL).–ç,ì 1ƒ°p….-Yf!ÐÀ "pàÐõ Q$¥Ð‡Ø!*¾õ¾õ¾±ž0ÄN‘ÒZ‘VŠP)IÙ7í"ø`ŒCP„´ú$»®ËY‚)FcLUVÃz8¨ëÅl^ÕµÑ&ÅCêº~6›+”ÖZëX¤ëû#‹Ä˜Cl| P×µuN)²Ö†RN)ýË6×s~èCzõ«_ýK¿ôK«ý–ÇŽ{Æ3žñ¯®’ý÷ºð •R/ùË_þò—Ÿ.|ðƒ¼Ú¢ù‰O|âŠ+®¸ú꫟ÿü篪¾ô¥/=Àhê?ßç믿þÙÏ~öÉ“'?þñß·üE/zÑ 7ÜðÕ¯~îºë®W¼âïyÏ{¾©íÝwßýÜç>÷µ¯}íOüÄO âÁƒW)ˆþîïþîï|çK_úÒ—¾ô¥ÇÃÞðÖ·¾õt«û/3¿ð…/|ík_»:ýâ¿øìg?û;ò,~Ík^³±±qõÕW¯²þÞ{ï½ÏyÎsNãŽ;žùÌgþÎïüΉ'à¯þꯞ÷¼çn{ÿµkkkkkkkÿ=ý¯-ÿ-gžÿ AìS ™çÐ)iˆw±OË´©7LAÖTF•6‡(l+‹–„4r=¬]᪢–¼Z_Òtoj•¥l›ý~¹7G–ÚÖJµuµuµ±gØ}0J)…ÌœrjºF£:•OuÞ`!Ô4m—ÀÍ)€ì›n>›·£¡5vÙ4óù «¡o{ÙÛÛ_.ªëúСCƒÑ ¬ ­Õd9ßÙÙq¥›/f'Oúå|™btÎ)QÍrÙ43>rÆðИœqÆrJJŠ¢p®pesjºn>›{ïÛ¦É!qŒ9F[§d`µE2­–´mÈXdŒÒ†LLQ‰HôÁ‡.ÄT•…BÐJ9c«ªÒdsJ1'kI)RĜ۶”œ9*]QãPU}»DBÛ¨cï}ûÞH1’3¶*Jk]U–ݼíbôÞCf¨MY–võ’ÔµŽ9Í›eöa9ç´VÚ2†9çäÄlH pßû>gb.¬#M˜³RJú&ø†›¹Tƒ ­%ePõŠºÁ omkÎÁw˜ƒeá–AkÅ,!BŒ“4mãjU2+çLQ*Ê9 BJ" &­’I1çÄøÿ±÷îA—ÕÁ÷ê{ïË9ç¹Î37/ˆàgP–P±4’ŠJÔ5©¨QbURFb.”ÑøZF­$Æ –ViÄ„‰hT‚× ¯ŠH¾| ÌÀÜžë9gßú¶º¿?N¾ùø3Ì(ç÷ÇSçìîÞ{¯Ó½ûÙ«×êµH$è1a„dâèࢳÞ‚ .tŒ2BHk:LL>&ŠÉ¹Î:ïbDB‰R‚1jL‚gœe™fœÕU;®êb¤@½ R–QÉ©TJp @)S:‡D Pã\ÓDd”`Jƹ¦›˜Ie´`ŒPFO &^¾1&guž1–ÈÚÚÚñ§µèõz§žzj×u÷Þ{ïÄaõÇ¥ôÔSOÍóüÁ\^^>¡¶?¢{æœ?ñ‰OBÜsÏ=GY‡mÛ¶mÚ´éž{îù¾;Q-ïŽ;6mÚtøðá}ûö=¶¿s¯×Û¹sgÓ4<ðÀ##ßj­Ÿò”§Ôuý}m˜Ç.2eÊ”)S~6Ù½{÷ñT[ZZ€w½ë]—\rÉ‹oí—¾ô¥ÉRŽqÿïz×»º-Ô'lº®ó1j•Íôf2­F蕥ʔÎ5W!ï€A¢€"I\ð…ÅE-e¦²à¼íL0®ŽöÞ¿7¹$RšØ %$’q1ßïÏ”e¡ÔLQÄ€‚QÎ(xï7Ö×îßûÀCûÆ‘PÊĸ®U¦…>x ¤èR«•Õ¥”ÖÚ;ßufa~aÇŽS8ƘÑhl{ⓞ|æYO_X\,û¥RH5Õáåå‡Ü}ÏÝ÷ß5®HJ¹Î\g«QÕuçü¤Ç2»4ïëq5ëq Š¢R†„1ã¶©êšqF e Fd¦ìgB ླuU7mS’BÎÎÍÍÍÍJFãqUU³„¤ÑZÓ´uAk)”d\ Fç¼R0N€FŒˆ‘RÚëõ8çMÛÊ)Ær)N:iûÜìŒëÚÕC‡Ú¦Iã¦nMçú!Zi­²"/zy¡¸­­>px´¶ÑTu ¨…ZèÏ–½ÞÂÂbfFi• «ÑÁåÃÖÙ‰ ¡µJpÎ(¥Þyg-¤”å|Tê¦N)IÅ•BŠÉÃH!Œê¼ÔY&u&eƘ Œ) fú4!%‰À#DÁùdub’Ía8J'9Hã<Ë )å$ZÒ$£#“<8"øB „0ʼó0b¤„€Õµ5cl×´-‰J4®#„!Î:çÉt®´´Ö¶mk­ !èLfYF0Fó¼(‹>Dzðàòx4öÞsÆ•P“F+Õ+zý²/?|èÐx<Œ ˆHQ‚çJqNµR)ÅQU‡Cã\ð^HÑï÷3ƒ,˼÷Æt>xçlÛ´Ö¹<Ï‹¢ÇOèy®ªj’òÇLŒqbTüøÝsá¾%Ø¿ÿþýû0y÷îÝ»wïÞÅï\UÕ¿ýÛ¿ýW¥Æ˜;ï¼ó+2eÊ”)S¦ü¬ñ“ã[[,ô™sŒzDk]¡—õfú3ŠqSuŒR.Q4rB"@J1ï#"xÄäëÖû΢GÑÕÎŽÍx½J–Q XÆ5gLë|vv~ÓÜ\¦¤ IE PH$%ï=D¬Æs¶k9¡Ö…€$ª¼,J&¸q6BÌU–z9cTÒI2•‰¥®éŒAiyÛ5+kic¼Î8cœgê¦qΕE¹eó–…Ù…^QrÊFkÃ5¹jšN1È{¹ÊFm5\__>xÈ;¿¸°À ­ÆãáxT·­‹q¾0????/Ck£šK–@03TJñÑx4€<Ï{½žÇ@ëZ*™(¡Œb ˆÿ©hÅ­±„x’D‚„qF$H)MSBR.8eÔcè½]Û¶RÚº©7ÆuUÇ[k:çBŠ˜ Ĉå#ÄÉÉ'y)cŒss!fæ·ŸtR¿ßGˆll;Eï=¤ˆÁ;g•ây‘3ѯ#çŒözŠ‹hŒñÞµ­SAQ`’iFEŒÄµÑuÔP–Bg’pZ;Ó5>“¢WfRÊÑ bŒŒqÆ9+5JÅ›¦mêÖ™`1•£0%€DÀ{o[ë¼Ç€ŒJ©wÎ9g:3±|ŽÆã‚·h„1–Œ3CŒ=B"RJ.‚RJ)áœ9g¹`Zi­¥Ö:/ŠL¦õJ*B(Bè¤6@Œ1Óza~^ ÙÔÍúúºí £”3Î(  8¹Tš )¤Ôy©òh»Ž0J(ë:clÛÎZ“ ú¶ëºÖB¢Jç|:!N™2eÊ”)S¦LyÌùÉñ­u4•=å90žRlÛN–åZS‘0Bz3ýD© >%”wXB&Ñ;cŒà‘F>ZuUK#a„v-÷"uPmT äl–Q1tÆ®Æ)&%9Iq¦W¢÷Ñ;Fˆ ,¥8;;Ë( Ê^Uuucsí”Ö˜Ð[çœkª:Æh­1bLƺªnZë“·yR–ä½÷/¯-3Ι`J«¼È‹^Á8O˜ ]ðE^dÅ“Ÿø$’ÈÜûÝÝöžÃÍ!×ú•+«ãõµáÚêêŠi;)%M0ÓëÏÍÍ ƒÆt”3¡ÕÜÜ\žçí¸¶Æv6Q¯¸Š'HR°ÁG 1¥‰@€KÁ9s.aŒ! P’ù$hccŠ ®„VÎÚð¶É›,¥ÔK=&¡$ 9—é8TÆœ°‡ö=$€W£¢ Ñc©ó™ms an\Ç£Ñx4òÎUã1c,@ŽGëÃaUW+++ÖZo¬b†Õµ ô(µd„Ç“ä²(ó`û#bìŒ+ûƒHéÆxì*­8gÖv5„Q.9†€ÑwÆ´Þ[J ®êe´íìhÜ8Ÿ"çªßãÞEJ8¥Œs®”J(O´ÃεÆ6­E*Xž•>pkZïh­|°‚³€hL×1†`m”rHÄ3®êªSÚªªa#£Ô;K)Ævˆ®×ë!zZç»dç”RJUÊ2%2fEˆLpM9%T •e¡ÜZCàŒsÎ{½~Qôg1Fk:cMŒžÐ€1v]G! ('1FN "ŽÇU×)„é ¥(ñˆÆ9¸µ&ÆÈÑY¶mÛö§>õ©$Þ‘Ö‡ÃÖtÖy’i577ÇB€5f86m„NuÎ)S¦L™2eÊ”Ÿ ”R§vÚí·ßþ³¦s®^™Š(­fç©ÖΚ®më¦^[[ÛØ){„'P!'”L6u}øÁCö ‘šõnóüÒÜ`nfnÓI Û·-l}hßC±˜zÏ…ôÎbd£$”ƹ‚ªš¢µ±k[ ”%ʨY‘;:g8a*WLr‡¡qá¼1mÕÖ)‘€­óŒqBÖ„@ Þ;ÄÀOt‘3Ƶ«+ËÁùº®÷íÝ !I&çæfÛ¥%kÌÖ-[–v,E–¾÷½ÿ8øÐC«+«›—–ƒvÎxDã麦i’R²ÐšK>®F‡VJ›¦ë:c½oÚ&,Ê" È8§”8ï:c¨#”Ò±ëÚ¦i“`œ$0ÆLPR6‰ã}HŒQÊHÁÇ€ˆ)ÆÎt¦®KCJ)%ÎxY””³Öš²WRÆ(¡œ2Bi¦ôâÂb™—4%Ó™µS:QÒ:*† Îc Î9B¤D ABlï½§0`" ¤€¶m­qŒrÉU¯×s6 GÎc”Q ”b‰ˆ˜ˆmÚÖÔL0%H Ì»dm ” Þ.8çœàœø-¢s”BSç]@ÏxtUÝA½wy^¤,ÓBðŒJʤ,`”ž!&©e½7¶ÑŠ`1‘#gR(!…RR !ƒ>tÁyOO(¡)Dï|×u>8J)çzïSL豉M¡W”œ±˜’1Æ9G -Ê" Zc¥ ’>%Z{ÄõáÆþýû)¥uÓRÆ ¡>xe¼,ûY–1NSŒF)D´ÞÅ?Vóä“OFÄcÄÎù)¥(Š“N:é¾ûî›äý/ïO ½^onnîGZé(æççççç5<ï´÷'h­·mÛvß}÷MGé”)S¦ü„LË“ía?S<ôÝæ–æ³2­í_‰ý^B$8申ºi7†ÃH¨¼ã"J ‘Øq7^­\SLSKe=Yöz›—–üVÏx:xðp×9¥•ÖEô¶5ÆÖmt>xŸ"fB·U…Ö5ãJpÆ(•ŒKÁI$èƒ'„i‘÷³È„€ÊÒ˜Î{Ÿ ÖHF˜÷¡ë £,E`”a@g­³†3–2Áiθ”2Ït‚SÐZ—:Kó0x¿ãñ§l=eK ¸¶²CtÆj¥¥ÃápHÕy&/ò\i¡„`Œ%Ü¡µÃE^DI1"Â(c” ¡RŒ;ɹ<% Ázﻦ±]Ûµ±NI¡ %§ŒB#$ˆ)A¢œë±&¦È8M¬w”S©TBäJp-APžIÉ¡7Óë z@a). ffBDk\ ‘QJ )ŠR0i;Óu.4]ŒF@Œœ€Ñ1Jç…Î[kMg )e^f\R!H@o\fJrNH"6%!F|Ç Ï”"®«1Fë)D46˨T’"Fg[ÊXŒ"EÉ8cŒ†RL1ÅÉ'¥L\r¢uh½÷Á:OŒ“,Sœ3ÊHðŽú(9G’eJ«@©iš®ª›º*¸T²Pˆ–²( Jèj]ï§4b4I1qB&8 nÁp)$>zïz !0J³,#„DIHž«"ÒÔ”‚SCƒ„Ò¦ëöÜÿÊÊj¦U(…Ô:±¤Êó¢?˜é—eAHªª± ¦6•éÂêœÏ|æ3¯¸âеµµ×½îu“#gžyæ•W^ÙuÝ+_ùÊÇêÿøÇ?>/¾øâÿaÙ…^øÙÏ~ö‰O|â÷¾÷½Ÿ^y7mÚôŽw¼ãYÏzVUU×\sÍÕW_&¾ÞÇÁÙgŸýû¿ÿû§vZ]×7ß|ó»Þõ®I¥ôçþçŸùÌg>ãÏȲìòË/_YY9ÒðÃþðìììQgûèG?úùÏþ„nþŸøÄ.¿üò#GŽ}]`Œ½îu¯»ä’K6oÞ|àÀO|âL²ú}¹üòËÿðÿ°,Ëx´?éIOʲì!‚N?ýô_ÿõ_?çœsxà}ìcÿðÿpœò»µŽ=rc·ÞzëÞð†ë¯¿~úª7eÊ”)Sþ[Ø·û>;¬·lßB}° ³óƒ~ µÊu>3;ëb\[[oZ#…d@úYÞË‹d±ZÛÊ ’¨Rõ(pH” ®r© ±í”M.6Á¥^9'EVæÙh}”Xc]g(%r ¨Êc ëëCkºIHXÆ%!4×ÍØ.—yÑÏ”®ëlׅ֘໪Æ$<—µé‚sNéL A! ʲ¥„ÖÄȘÞv.¥²ØT,Î:ë%½™rËÒÖä1Û³%çlçOÙ±ó¤q=¾ovnv0SÇhŠ ¸H˜0ƘRjaa¾7(…àCŒ˜™­[•IEUG:Óº\ç)F ˆ¦3E¡%g²,£mÛZç¼ó©æJp!¥ÒZ36Ƙ:c!%)¤Ê4S4ÎrÁ•–Œ³|^½™ApÎ[Wd$àTe‘—s=™‰ñxR¨šqŒ1¸@cR[ïbˆ±«+«Ãá°sÖ¢g\D uâ"R¦„à‘ÚÎ[g…àªYž#BÓ´”“Þ ›Ÿã< Ž][7ç, ½¯B6ÆXPo\ŒÑìšFNr“zb¤ŒMLØÖZH‰P*…$1Bœ1Þ’RbQAK)‘™Á`ûö­§>éI3ýÁÊáeәѰòÎGµjË–-y^öyÝŽ¥–˜PJÁzK¾ä’Kîºë.JéK_úÒ¯~õ«çž{îcøÀ§ó?†Ÿ"y_ñŠWœ~úéçž{î­·Þ:Q$þàþà}ï{ßp8|Ô¶¯~õ« !¿ôK¿4©¼¾¾þÁ~ðÏxÆ7¾ñ ÇÏ|æ3ï¼óÎ7¼á þç~TÛ׿þõÿzÝu×ÍÍÍ}ík_;¡›Ó›Þtã7åÅzìë>ïyÏ{ùË_þªW½êšk®ùŸÑûo}ë[ï¸ãŽãäëç>÷¹ßýÝß}Ç;Þ±¾¾þ¨ò»Ž]z<#çoþæoÞùÎwþʯüÊQ¦×)S¦L™2åÇÃÌÜlgºªiIæàAàtóÆ–“º¦?ÓïŒñMë«aU«ˆØ ÇC½1ןÍD !œûu£ªrÞÓõ” ¤¸ д–&¾8¿yÛI§lÛ¼ Ͳ|vv¶©«ªVãÑp8$&‘Pëº1m—ë2QDïP ŒrÁ˜H$ !ʲ\X˜O„xH3‘]äÖ;€¨c ¤½¢7:J!ˆ=úÑðÐáƒÁû¼(7mZÊË¢îºÕu.¤‹ay}í;÷|ç®ïÜ{ás/VãïìÙ³6®˜ó›—T–ëzc8 ²<+za´óÆ:ÓµÍp<\ßX“”ëH3"BL„ Å8ÉË"+Ë”"a4ËÄÂâçt8ÚÀzÜ9Ó€ÆYB`„õgS !L‚ NbÃ6M­µ RKZcíúúº¼×Õ5´.Q‚Aï}Œ‘1ê‚—JHÍ KaB÷²9AU®¼óBˆ²×oÚC 1E¦íÚ¶ Îçs)ÅB$)B$Ñ´]=®(rÐ/µ.ºÖ[cRÁUQ^oÐï £1¦®›áh#„033Ø´iÓÂâ‚tÖbðh¦´ó!¥ÄSŠkÉ¥TÎÉãLk-$>xJ0E•&™<“·®ië®ë %¥d‘çZÉõÕUÓvS¦òT¡jÛ¶5$RšZÉET‘$ @UZ1ÊduÝ¢ àœK˜V:Ë!„I~Ni°®öÁYç¬åŒI&2ÅÎûˆØuÝÚÚÚž={ µuk­UZ0ïÝÆÆðСCƒ™²ì郇÷¯GÎF8=êmò’K.€ .¸ ëºo}ë[GŠN9å”}èC÷Þ{ïp8Ü·o߇>ô¡ÅÅÅI!äÃþðûßÿþ#•wìØñ•¯|erª »þ_þôOÿôáWܶmÛ®]»®ºêªÕÕÕ/}éK/xÁ öîÝ{÷Ýw?å)O™T¸ôÒKo¼ñÆ#õÏ8ãŒ/ù˧vÚñ´}T÷¸ÇíÚµëœsÎyË[ÞòÀ,//ÿýßÿý$4Ü1äpÉ%—Ü}÷ÝÃáðÆoܶmÛQgþ¯ä=¶DÎ>ûì›nºéСC‡¾å–[^úÒ—þæâ_þå_Þ·oßDm€k¯½6Ïóç<ç9ÇÓv0ŒF£#:Æ<333ÿ¹²èÜ7¿ùÍã1p-,,\|ñÅûØÇŽß§6oÞ|ÑE]wÝuG¯hóº¯xÅ+¾óïü0 ç _øÂ{î¹gcc㦛n:*Ã1zÿ‹_üâ®]»žûÜçžzê©Gªå¦Ûëõ.¾øâg?ûÙ't?·ß~û…n¾ùfÆØÖ­[OTÞc÷Â#Kg䬬¬üË¿üË«_ýêéKÏ”)S¦LùoAJ5;7¿yëV]ŒK¸s8WëCk¥ "ÐDµÌzEÖµÖù@Wy®‹2QXÝØxðàÁåµµªíÚή®®8pèà¡å•ÕÕ•µÕµU ±7PýA¾´yîñß~Úi;wìØ±}ûöÁ Ï9… ÄBSWk++ì?xàÀÚÚºq'f@!å–­[ÿøÇoÙº%¥H™Ÿ›ÛºesY¢\0’‚w¶3Ö4m3®ê¦m­sÆ»Æt.$ÐZ³º¾¶ï¡‡¾û½ïÞrë×?wãçÿe×®Ýß¹÷ÁƒûïýîÿùÖwÞs÷îÇ–1ÄÙ™ùDzóÌÿëÌgüÜY§ú”M Kѧƒ~hïþ}÷íûÝÿqÏ¿íÞýo÷~ïÞû=t¸VÆØBi­tÆ…ˆ)!b"€Û®[ߨX^YYßX7ÖH-3ƒù…ù­Û·tòI[¶nÙ±cÇââ¢RŠR:IÕ3 ÈŒ#I +²<Ï2Àè­›$|tΑ I!ø½R|qq~iiÓÉ;NÚ´iQÖtuÝÕ”¥¢—ýœ+æÑÕÍxc}umyeueemuucmm¸¾ÑÖM>ÏôììÌ _ Î"ô½Þygñ«Ëëëk£ºêÚÖVU½¾¶Ñ4mÑ»à&›!„0DÎxžýþ ,Ê,Ï˲¤”Zë¼÷œsÁ…R+­¤bŒ…à £4ÅhŒÆkkk‡>tàÐxT%L’ñLJÍ%']°1 Ö›Æ`ÀLfýÞ Ì{ÁvÖ[‰pÊa$&o·.8¼O1Môy Á{#vÆt]×v]gmJ0;ô‹²Ð™’š0FÐyÓv¦íÐz–ˆâB2ž ©„ 1yc¼µ¦í¬±ÎÙδÃÑðà¡xpu}Õ:C)H)„1âáÇïºë®ÛoÿÖ]wݵ²º‚ˆ!àÿÏÎyóÍ7ÿ¯ÿõ¿žþô§_zé¥GY$žö´§=á Oxÿûß¿gÏž­[·¾å-où¹Ÿû¹sÎ9RJW_}õm·Ý¶{÷¾šs~íµ×B>õ©Oiþ‘|®¼òÊ3Î8ãá§Í²ìÙÏ~öÞ½{ßøÆ7~ìcÛ¹sçÞð†·¿ýíW^yåe—]6Ñý~á~áÿ[¦š™yÎsž3 ާí£RųŸýìw¾ó³³³ý×íœ{ÉK^"„@ÄcÈ çwÞµ×^{ýõ×_yå•\pÁ{Þóž£Îü_É{l‰&_oºé¦;î¸ãµ¯}mJ鬳Î:ãŒ3Žg#ÜâââÓžö´G!ìÚµëQ›Ÿ~úé÷ÜsÏ‘¯“ÏOyÊSþñÿñQÛ^ýõ/ùËŸûÜç~éK_¢”^z饼å–[NôÿÁ«^õ*ÎùÇ?þñjuá…2Æn»í¶jõô§?ý–[n9ï¼ó~ë·~«(НýëøÀº®;ÎæZ뫯¾úª«®jÛömo{Û¾ð…SO=õˆê1zÿ£ý(cìòË/ß²eˤåÁ¾cÇŽn¸áÛßþöã|{úé§×u½gÏž•÷ؽðÈÒã9·Þzë›ßüf)å$*ú”)S¦L™òãÄXŸ ¡µJ–ÌÍëÄ#@HxâŒ0  ´ž[Xà‚ .ã„3‡¾s]Ý4ÑcÓ6Àˆ":+‘.3'-nÝ>¿yavS-7j[:µk«ûQFsõxØ55ÅÔƒLx bL‰¡$€>`lÛ€>¦P¥õ®iªº©cн~9?¿Xæ=.„¡5162¨êºmÚI¾Yï="RB!%kÌh42¶Ã"$8ç@8*Å`0 Œ†ˆÎ[LXöÊ€!¦d:㜠PLJi|ë°«ª ]®­ÛΑ$A !ú˜i­•âœg™VZƘBp‚ÑD a´m—‚€3R¢]çÓJIÄd—BM’¦H))£”RÄh•ÕmÛÔ㺪•Êò,Ãàƒ÷ 0eœÒÄxÀcŠ€xçIê8pª5Ę„ &‡¬dý¢0H!2s*¢1%’#\r•ÉbL1AŒŒq)”âÊ»à½÷.t­a„e’ ¢µÆX›0 D)¥\P %)#:‡ßZªT”BP™IJ‚@ÄH¤”0ň˜ ÇC1qí¶&`œ‹q\êf!XßZcŽì眀ˆ×_ýe—]öâ¿øyÏ{Þ‹_üâ#EÿôOÿô™Ï|æÈ×µµµn¸áŒ3θûî»à_ÿõ_ï÷~ï½ï}ï×¾öµ_ûµ_{ò“Ÿ|æ™g>ÜÄô‰O|^óš×|߉àøÀ7¾ñ«®ºêŸÿùŸ?÷¹ÏuÖY/zÑ‹ŽsùaÚ1ÝœuÖY“Wá¿üË¿<yßüæ7ïÙ³çÒK/1~æ3Ÿyüãÿ‚¼àáç<¶¼ÇàiO{ÚÜÜÜ•W^yÇwÀç>÷¹ãlxî¹çÞpà <Þ4Í£F»€ùùùÛo¿}0ìÚµë _øÂýÑMÏ¥o¸á†Ë.»ìoÿöo———ggg÷ìÙsÁÔu}¢²¿æ5¯ùÊW¾²oß¾Õ»®›WŸ¥¥¥'=éIŸýìg?ùÉOÆßùÎw^tÑEÏ}îs³9cìMozÓĸzß}÷}ãßxÙË^öw÷wÚû×^{-<ÿùÏWJMªý(8óÌ3/»ì²w¼ãmÛž¨¼Çî…G–çȹ뮻²,;í´ÓÛÈIS¦L™ò?’Oþã§.ûµK§¿Ãcªs:`40Ês³ÀéòÚr5¬§”ŠzÔª$Ð"$ˆ”çEÎ…€ãº¦`0$-2 ‰`h­ç4Yo;c¼7”Hi<ëŽÛåçœuÖÉÛ¶àIúy¯WÌÎÖ×ֆáí{J˜sAJ¡•H€e¿ f$#I)¥”øúšÎ´OˆªÑ°&ð$£TˆDi(Ë¡F ™iÊ\g§l¢Ñkh’€2BUJc}kiHY¦ºè颯K@N}".ªÄûyR‹Â©¤Î´ V*Î…Ê"&BŒÈ%ËŠÂcJ\мÈó2gŒ…Æuµ1¶mË©¨ª*,‹´žl¡tÆ2F1„º®ÛDÆ9ë—š‹\i6˜¡@fçç #Öšº­;Û1Bb×vu]û„”œ3 ‘2H€Î›®kÀt.8 !AŠQP!—RbÎX­g„Â)K$Œ®ë¬€dŒÓ:\Pà c"Ó9ADç|Œ1J("6MÃ(“ZG£¶®1Q0Ιµ 1PB1 ¥T E!à‚ÓíºlÌ+k !˜¦ Ö£HÈíý€žR&˜H˜:ëJ)† 2©\À€BæYÁ8‹)m ‡Þc×F(M7ÖbŒŒ.¸”"ú˜€pBbŠ€@ QH"ç| ˜R‚˜&A‹ !Œ3B4ÉÖ#¥ð>t]×¶†SJÆ M@‘P0pöˆüœ×]wÝ—¿üå}ûöÝyç×9SJý~ÿ…/|áŽ;z½ÞÄÑtiii¢ƒÀÕW_}á…~þóŸß¶mÛ‹_üâÊZ1&'Æãq¯×û1´ð‘|ä‘¶—cË{öÙgßpà G\o¼ñÆ£tΘ}ûöÅÿøÿøÝï~÷wÞyü1œ>ÿùÏ?2¸èDãT¢bŒ333gœqÆêêêdÒ;Î Ô'Ÿ|òW\qøðán¸ann|åoÿöo¿ñoª¼ÇÓ ß·ô8GÎÚÚlÚ´iúÞ3eÊ”)SþHàò…YV0I«&ï”!ŒQ`ÕhÌuŸ%pÖµˆ½2çYVUuÕÔÞ£·anvS©KÉGo}—k‰)&Î[g-çLpù½ûþc8QÊ´Ö só”Ñ”€È´œ›QRÌÌ œq“<R‰û@"!DeY®4Ĉ!xç€QÊh¯×klÛµ±ÆÃ(dRdJB(ç(ÄÌâê “U£¡išÕÕÕ#p>õ©O]sÍ5“´GÀÝûî»ï¨›Î¹ÉÇ„•••-[¶3337;Û5íòòJB”‚{ĦkÇãÊ4BBïsÃõƒ‡yt‚sžQ¶yi%dnf ˜@Œ‘Q–º×³ÞvÖ„à›ª^Y]e‚qÁ]p”’²(½ +Ë˦éæff˼ÔJaÂa[QÆe&ƒ¦ë®ºïà^Ô¬ëÌÿyèïî ®ë-[¶B&ˆlvP@ÒY6»¸Hs‘÷³DRÓ´#27!DHQDlMg½A@&¤SªÛ¦w1„©$/r c¤ ±í:ÁEW”¦31FJ©Vª?è)%Œµƒ™~®v®VMU#bÕŒ;gŒ(µÀ\¢ ¸`ÑtYœçŒ÷òÒÌÌF‹+k@p= DÆX®U¦(!%ˆØ4õêêª N(Þë÷æÊÞ`nnoxaœJ)d™—‚)’ˆ’*Ö4MŠ)xô>ŽÎ†ÿ]g[€p®kÆPFmÛ1ƃó¡(Š¢ œñ”"b¨Fcëìx4®F‰¤Ô¥PBæ²Ì2BH]×£á°mº Xgó”2’@ÓÖ£õ¥DJ齫ëºë:BåLç¹sèlPYÆ×B *­³ŒRÎxd“Â#z¢ŠƒÁÀ[g¬ !„œs1%†<¥ä¼ÇˆJª™™¡¤iédWmÝ6ug’þÜìüüœ’YÔ4M]דõ‚”"zôÑø^ƒóFH–b@ Ð9SJÏzÖ³ù¬¾÷½ïý÷ÿ÷ /¼à‚ .xÙË^ö𠌱~ðƒ÷ÜsÏSŸúÔ׿þõüà«÷ï‡kY–=æÓÐ÷Ý`v ycŒý~ÿHå#ñr‰®¹æšk®¹fçÎ]tÑUW]õÉO~ò©O}꣞ö¢‹.úa|k÷ìÙ3É5ràÀ8ýôÓ' ðñHtÞyç}å+_9âÆùÅ/~1¥tþùç¿ÎÙï÷õWõãÿ¸1æD»ïðáÃsss'ÚjïÞ½WÑ»® !ÙU »wï¾ð ”Õ\J©µ>r·ý~bÇûïE)õéOzaaá¼óÎ;Jk}Tyµþ«Òã9oÛÇpufÊ”)S¦L9~f3:Ëc}ðè¬7¦kÚÖy¯¤Ì´vm×è2ׯÖmSqÉu&Y¡›®5&’àB‹­­ãºñ®UŒJÁ„dmÛî?´ëæí‹ ›ÖÖÖnþß7C„óÏ;¯Wd€1Fx¢”@LJ©“OÞcjZ3WÃñHJIS¤è| PƼ÷Y‘g½Ü_×¥0öò¢—ÄÅèµm×´-0ŒÓãáHJ>;?×ËKc»µÕUÅU¡3ßÚ£4B<¼¼œ(!’—eŸæru¼^Ýýgï÷¤PkÃu5ÈËùÁ`f9dJmÛyò–°]+µ¸°Ðšf}ce8ÞHâÄÿ—BiJ ctÎ^YÆè¬mƒw„Ò”ÆD+Š‚q.”䜛ÆäE^ê\+ÍSBNÔ0ÆÁ{ý’1æ½kšº­j;nͰFƒÒÿÃÞ›GYVU‡ÿ{ŸñïÕ{UÕ]ÝÕÍÐŒÒÂ#P£FWä‡?bDEô‡SˆsÀ.Äï2Š‘Ä!AAI"”CÐ¥`@AE1 8MCwWuU½Wï½;qÿþx¦¿½TšftH}VÿÑïž{î¹ûÜsnÝ}ö>{ç2CÆÙ½oÿüó9ç;îäÁ¸é¦›vèH;óÇ|ãß8çœsÖ¬Y3??ã~7ÞxãÎçLNNž|òÉ ¿dLJk×®ÝñsffV&Æ—¿üåY–]zé¥àI}÷»ßM’d¿ýö»ûî»w¿Ö7¿ùÍq4q Í8@±ó†Ãá®c/=íiOûÆ7¾{ï½÷ÌÌÌîØ¢w0ò<°Òëç]#„¸òÊ+7nÜø‡ø‡cõïaÉûOáÁJwgäŒÇyUUwÝu×ÊwÏ +¬°Â®ùâ¿\#8¿òŸÿ™3Î8çœÿ§½b¥[%ÑFHNˆŒaSÕuQzçãdCQE¤X[.˜ ¦±õ°¤­¼5щÄÒL!ò<Élã2.0DòýåašjÎтզB‰þ ëw¿Ó[êí½çO;òð$Qœ3" ©"z[íŒ)N €1@òÞ[W×UQ«gפYš´Ò²,kR¥$㬩ï}í\äÒYÓD¤@œO¤B טàq@Ý IDAT&Xן'ZNOq`Þ˜àCš(‹ Z©Le‘Â*4IšZ39»v¶ÕjEmc¼óy–¤RËNÚ‰`‘SUU ÛçGÃjzz•3Ö{/8œsÁ{½¡±ÆY3v9ÌòV–¦i–§yÖj·Ò4]œ_,ŠB1€cßÚ,Ëœ±UQ8cmcŠÑÈ9ƒˆ Rd„’ÉT+@Œ"޽f•ðu]r$A{ŠÞ[¹Aolˆ«ª¬Ë*xOˆUU9g…L0ç=˜¦ªk ‘ñ„”VeÐ@mj_7#âiš ¡ÀG1–E嵇Ûå\æy[ë{½^]7ιNGI¥g×Î ÍÑû¼oå9c‘{¬sÃåa«Õ‚išH®´N’$Á_„¨5@ Ë&ZY–ÓTe#i•H.9òVÞŽ†ÃQYTIš2ä@8Ùje­å^¯(†ec,™êc9,¶o×iŠÎùJ•H059™¦iô!xoŒ1•qÎyï!0ƈÆ|D”R %«¦©I¼.FŠ@12$$Î;çp!c€8çi𠣯”Þû$MiwuÎþð‡/~ñ‹ÿñÿqóæÍ/|á ßð†7ì\úÇüÇçœsÎË_þò{î¹çCúÐýÑ}á _8òÈ#‡ÃáØÄ1Þc™$I–e6l€Á`Ðï÷²ÝÛn» ÞùÎw¾ÿýï?äCÞøÆ7>1ï¦]Ë{ñÅ_~ùåñqÅWœp §žzêÎ¥»–w×wÜqÇsÌ¿øÅ{ï½w¯½ö:ùä“¿ÿýïïŽÞ¸¸¸¸;ñiŒO}êSguÖ%—\rÆglذáïxÇõ×_ÿÓŸþtçsÖ¯_ÿÉO~òW}§¯¾úê³Î:ëÍo~óå—_Þívÿþïÿžˆv6º¾à/ȲlV÷ùÏþÂÂÂO~ò“þð‡;NxÍk^sçw~ûÛß~wþõ¯Ý{ÿŒg<ãWuÎ]´ûéOú-oyË%—\röÙg+¥.¼ðÂáp¸;AzwðÁ~ð¥/}iY–ùÈGŠ¢ØhwFûÿ÷¿þõ¯?ýôÓo¹å–ãOúÓ] ¬ŸwÍE]tÒI'½ë]ï:âˆ#Ž8âˆñÁÿú¯ÿ«‚»#ﮟƒ•îÎÈ€cŽ9æÆo|X++¬°Â ÿ;9ù¤ÿçškÿ픿xlx¸;†VøµP$òÁÆà½HƈéTK弫M…€u]ùà|tĉki¼)ëRHL± g¨$çB’HòRHɘf~a~rÂwÛÓR¨åáòwݵ}ûüriŸ {í»ï†Én‡ˆŒ³BH` Ïeâ!ŽÊÂÕ†3&„`1ØàsY«Õ™ì(­| E$!’ .Dk]Õ4 ”£ˆ3`”H=»z†„\°qL œ“UQÑ-9âôT'™È¹VJ+™p®0W5MY1P$·nvª(‡Î¸N»39Ùž™•J«;ýå¾à¼·Øwn›kŒuuž&*´ÒJð†‹¦©€@Ig­,k%y’¦¿°þYcWSRJ˜ç¹BI)…`Œ÷ J)çD¨•JR!"B „H‘ƒõèS‘0âQ€7Á»ÚE[ñ ¨D%2•-Q£èµÖ9Ç‘ƒ–"ã­cÌS$Edœ1î|hjC8b(ežKD#…cŒDq08ç²,#"¥t»=Ñ4ÆZW×MðËÎÛµ³«’õ©±?ê\°sj¾±ßÝ\pÎ9çï¦]È ŸûÜçŽ;î¸~ô£]tQ¿ß¿è¢‹Þþö·ï(ݵ¼»–(Æø¦7½é}ï{ßøçí·ß¾›y_%÷ÝwßK_úÒÏ|æ3Û¶m€[o½õU¯zÕnÖ=ï¼óºÝî‡?üáqÔß¹¹¹SO=õ–[nÙqÂ'>ñ‰)L/¾øâ±ÂvÖYg~øáGqÄÎø°XXX¸öÚkO9å”_M>¹‹vïºë®W¼âûØÇÆë‹‹‹¯xÅ+vßó³,˯~õ«?ýéOq8žvÚi;|Ywg´æ3ŸyêSŸú¾÷½olžœœ|Ä8w06¶ÿÕ_ýÕΟÿüçwl>¤¼»~ »(Ý‘³víÚãŽ;î—¼ñWXa…VXችMcŒ3D$¥LT’(…„HÖ˜ÚÕ\³\KSÕ£á ™¦-ÁU06Qi"8xo-Z-DèC †B >x$ç!"±QYÜü­oÝÿæQ1|ÒLMvqØÀ… Ò<ít'*V:ë‚÷ƺ²ª†ÅȯÒÄÅP7ç\ V#˜H(uR65pF .x{¢Í“Z!ël]×Þ9Îxô¸Æ4uã"EA€`Meu®ªªÑph­ô%R+kõ{uYû©j¦ÛÑ ÃTÉ‚c¢Õ̪é~¹)B+ÕÊóv»ÅYŒ0Åʲè/ƒmŒ`8Syž έFÃ!çc@"$„$K)’sÎygŒ! ÈÒÇà}0‘uA)c,x@!„²(LcLcbšf1D­´Ö‰1¶,+ç AHGJ*•g­,Ë­31¢ŠsÉwÎc¹0:±L"¬uUYã8ðà#QäZfIÚn·T¢1ƒåeë6 E’B&:!kl›º®…À¦I€)`\¨±±1 òÞcꪌQˆÈ9“R(¡8ÃñŽ\!¹T2qk .¤Ðic¬ë:Æ@HÈ‘!# %%ÁA sD‚HD„ˆ8¢’"ÕZJIÑ+)½· ÑKKK»™CqÀH)ï¸ãŽÝôØ|¬X¿~ýÌÌÌwÜñD&÷{Hy×­[·nݺ»îºkì¯øJ4vלŸŸ¸‰C%I’<ùÉO.ŠâWíTI»ÝÞwß}˲ܴiÓ#޹úÈ8æ˜cn¸á†ý÷ßÿaEK­õÆàŽ;îx&¸õë×ÏÎÎÞyç;ö²þ–ó(å}Ä#çïxÇé§Ÿ¾qãÆ'x`¬°Â +ü6pçwîÎikÖ¬¯Q¾ä%/¹æÚ{ùKOÙaçBìf$ùÝä+_ùʯ¦Ëúµ‡ØÅý_pÁ×ßþ].…õ>„Ø4uQJ‘¦™’ÒY; ½wDÑyc\-ËZ­ÆÔEYb+ŸHÓ´óöÔä¤àX×e«•&Z0B †è}$‡…3±)djÍôš}6ìµùÞ{šªÚsÏõ‡þ”§zèììšDëÁú ¥V Á6¾¿Ø-ƒåù¹mwß}wmš,Ï#’1 ¦º]ÉøDž³HMÕ8çòV{©ßGÁ*Û ‹¡õ¶3ÕI2䙵fyÐ_^^ ärÆ5MÝÔMãݰ.u–v§'“4qÁkw£Ñ¨©k¥ÔÌê™=f×%RoŸ›ï/õ[Ykÿ}ößÃ~(˜ MoÐëõý¥á½÷m¶oµ:išfYÚ鶤äE9ŒÑ÷ûýùùùÑh89¹j²3 USÊQU•Ö¸ºª‚ Y’NOMÍÎÎîµÇžÃápëÖ­‹‹ 1†¼Ï¬]½zõê4Kâ5ñˆJ«D'€P–åÂâÒâÂRÙ”\ |Y×uÓØh"P¢=Ñîv;­˜¦nŒa¤.ø¦iœsœ )u¢ÓV»•$ "c""zïCBˆ‰‰‰,Ë91FÓ˜²ªœu2>ÖÆÕŒóN§»jõjºÛ”R—e]×µ”’ ÙjåIªs½ÞR]צ®!D@‘€ ÕnåY+IR!EŒ±×ëYkcŒÞk³6„@DƘñš‚ä¢ÕjI­€!¸àkkjc ÖMBÈÒtjrŠF8çi’¤:áŒ9çFEá‚—Z%iÚ8; | ˆ¨“¤Ýjb]×Á{DdãÅ`Z%!8këà-Bd(¸à­GàZeIšgIž¤ ãÜØfX Œ©•J¼§‡á°á½ÿMmÇÚ²eË–-[žàFRÞ­[·þêÆ¹ÇD¢ûî»ïáªO MÓ|ï{ß{duG£Ño*õâÍ7ß|Í5×¼óï|ík_û°*cn¿ýöß­aùhx”ò>²‘ÓjµÎ<óÌ×¼æ5+ ç +¬°Â ¿)Šª ‘¡ÛdR4uí#!GF€ÎGDP:Չޢ÷Œ0Ó)"çÀ¼±ˆÜ ï'Áœõue8gy+éNN$Z[ëllƒo|41xã¬ó¡;µjÎl¹ËVçÝö……ýößÿ '=iõª©$Õ‘Àyâ¥Ó«¦Zy®´EÖnMͬ²Î-.ÄD'I– diÖ’ŒçY@€HXÖ ,M=Ž£a€4iîœõ¦(ŠªªFÃQU–Áùà£wÞ6Me I)‹€8*‹ååeB2Ö ÎÓVždIÑ”ÖZऀ–z‹ÈBòN»¥¸^îM¿.Êà¬L‹É<ÏlÓTÖE‘#ó&˜ÚëjS•uQ×¥Ö)GÈ .´N”ãÔY–v:ÚÔ.øÆ4Lð4Ë´¤¼‹µ­šjPŽÝ;cʲ*Mé|¨õÁûè1æ½sÖ;b`‘E"@DθâZ%Œ1"l¼#kc¤ ¸àŠc1ø€È…TDPV¥ó.M!¸s…Dh4 £ñ…$I6Ñi¡Ë£Þò`y~~Þ ‰°ßu:ÝD§yÞc¤¦±McF£Ñ‚R*ÏÒV–h¥8¢1ÆXÓôc¯'„`Œ£5Mã]@@­µËQጵÊ""pÆ%O“$ËsãmmL¬µè€1” 8c¦nbŒ" dZ*Dl”BMU!À8š ÅÈ8ï,G@Š‘|„@b¤@‘ ŒX@ˆJx†C(‹bŒQrCà»Ch…~›9í´ÓvŽ$¼ÂoιÃ;ìwK9_a…VøÍòâ“ÿß•Nxl•…§˜$“<:IÓ˜²(вÔR )4dÖš1IS. .‡ZÊén¦„v.ŒF•2ºXWÜûhÐrγVŒ""BÆòVÖÎ'';ÁÔ"n_ZÊS·[@Ñxÿó{ïݶ}¾·Ü?ð€×Îζۭ$Ñ ˆ„k•r>m½+›9 ‡Ò:º31±fí:F)͉1BZ\Z´Î!1ï} ˆ c>ÆÚ4Þ[@Ìò<1Á­1)¸PIÑ„ˆB9ä!BCà¥Hó$—²ÕjµZ­D+%U+ÉfT¢…T\%Zg: µäÓ“]ŽbËó£AÁWU“¦ÙëÖï³ÏÞÖ6UQÃFJU9J. „1rD-Uš¤Þ8o½”"ÕZa­ !dY¦Ó¤¬ÊÞòÒp4…TÂIjkëÊÕuQTu];ç0 6X" À8òŽŒwÀL¥-.¤Vív PëDÉĹ`­µÖ!F%ã\Jã@»QD­UšdMS3†Z+­µs.Æ ¥`ŒÅ_¨¾1rÆ¥TJ%Rª$MÛ“ÙäÌäâÒâÜÜüpT"ò¢óDȧ&%"q&Ò,cœYï ÀÇÈ‘ žåi [MÝôzýápTW5”Å(ðÞ &¤Tˆh­eÞk¥²,û-s!BˆÎY²˜Ä$o·&&:iðeYCŽ)FÆ8c\ ‘*‘i…>ZcÈ{cLô‘!rdÌ;‘c„ "E  £Ç| ž(@ô@ˆ3@¢è³N‚’ZsÁ|pÞ[g,0Lsµ¢s®ðû@UU¿+®ÿÛ0Ƭ(œ+¬°Â +üf™šYåB@&d¢0ËÒÔyëÝpq©œh·¹Ðñ!z®ÔD{CD¤D¤œ‰@6×9¹Ð a´ÞJÅ˪¶ÁùhÛíL ©“¬•vSÝŽ«¢©Ë†¶&:Y–!Dï]Y£¢Ø¶}žض­311»vvõªUV ˆ1óÑy_ÔÕò``¬‹@I–µ;Ý©Ukà8'  Îm[Ønœ«FåÒ _VUD †ÀÀ_T¥µFj¥ó´àŒ!Xc]Œ¼i çRIdI’&À¡Ýik­u¢9c@QJ>XkMÝ ! ¡ÚsÝl·ÕòÁËe1â©N¦»“{®[Ð κ‰{ïIææç´ qTÕMôQr¥$­¤ª‘"*•(eY»Ý‡®­ëÊzçc@çPR% •uÙëÍc 㜋99#NŽŒµqìôÉÁ³CmM8ðä§;\ÊÖÄDDÖ4&g0U2‰4¶€ãŒ1.u"Uâ¬e ‘çl¼Ë”(ckkalëûŸ ¬ ‘I!…М‹¨®M@ßꤓ“SÞÅ^o‘5Æ6Æ.-õ¬uíÖ"ê$Mó,IÒ‰vgjj¤©Žk„âJ)™è¤•»¼óˆÀœó‚K­4cÌZËãŒYk¹,e€1€óÎË•á’sD%%¥¹âÂ[Ë"ŽÍ²‘²u3k–ËÎ9ï<…àÕYÚJ3Áyˆ!… 2ÆCDFã‰Côb@$ÆQ0‚Qzâ®iêRI%Åଳƨ4 VtÎVXa…VXa…~ŸÙsß ˆœµ'&lcóVŽ€*Õ6øèC»Ý±&X™J¦Je” ‘ŒŽÀc+mAtÍ8‘‹®;5,,,9߬ZÕi·'D+!$ιd2x°·MƒÈ×ήNSÝï/ Ša]VUS÷ƒ¥åex€6ÝwßÌôê=ÖÍæyî­ï-õØòÀÖ­s>†@·ZJ'Öº…Å¥`#€ED&…-½^ê±®’I¥#1Ð!Íó,ISŠÑ6f4ö—zeÝ €Ô$5IÍ1àɺº®«ª([­Ü”uSUŠ«<Í´PH˜hÑÅh°,˜ âX4-åôäÔ>{oèvòµkgÖL¯ºwÓ¦­[·Ýÿ–Í›ˆ.&i¢´È@Ek¼– \DÀ""2VŨ(ŰßïGÖºH‘B¨m]Øct>R ˆ8‚'*©¬jˆR+.¸£àƒ' àˆ’3®dŽí‰‰nwÊ5ÆÄ*I0IS†Œ 8ç½g cŒÎ9gl¤0,CŒœ1Æ(2‘üØÚÉ9WJ!¢q.…Ø4Æ:#j†²VÖît¹P8Ãa1EQ•”*Ij@´Î3Ƴ¼-¥”’ù`b´Ö;£”GFL ɹ.XcPJ©¤Ì²l¬-7MÃqÎ9&¸âó1˜Æ )²$ñœ7ÞZ @€¢mLÃkÍu5*›²²u)’BpÎy´Î‡€ ‘@(.€!çœscŠ\ Þ{ÇI!µ”œqŠ·°ua~Á4åì:Ì’NU5¶é UÑTEåeœµÚYk"WIÂ…ˆ1VUÍØ¼sýÅ¥…¹¹…ùíZkÛ˜¢(ªºŽ‘:®Lôš™™<ÏëÚ8ë———mÝ`ˆBð^$Âz‰”Ö:K“,MuªÅ$KÒ€„àR)D¬UÕ4ÍØ8Å%È["Õ‘SeÛuÈëT#‡¢ÃQ·Ó1e 1®ž^­“vÂ{¯'†Ë%5cŒÖu¥uŠ@RŠ,Mó<Ë[­<Ë'§¦ºÝ{!²…ùEç¢àœIAÈbôMÕ0@Ƙs¶®+Ó4œsüâÒRÕÔÆçq¦1MŒ$W©NZ)Ä "2@Ž‚óqŒU-„ªkˆBJ@0ÑŒCpÎ_[@–¦y«-Bˆ! Χy.¹DDdÌ6¦¬Š#%”P$$’œ'ZŽwrÖu%”R4M‚gŒsÎã1z⥈ÌXçƒÖ÷—•1œ‹V»Í¹d((UuÓï÷³,7ÆzïGE™¦‰N’$MGbœÃ3F§£¶Î[碂 )%g‹> Bˆã/ÐZAô±ªkŒQi%„ !Ʀnœ÷ív.ÓDpÈbŒÄbŒÖ¹²,mcë¦&"ÎTB !†‘LÓ ¢’!ÄÈO”’RZkƒwཱིÖމœqÎ!Äà)FÎYTÕU € CÆ™5À­èœ¿«!öÜsO­õ4Um+“$I¢µàBܺeK¯×+‹RiµzffÍš™ÎÔªµëf÷ßoC»Õ ëå¥Þö|ûh0(ÃÑ`PÖeݯˆ‚.Z§ZjÅ£‘GµTÈÐ:SÔeˆ¡ªŠ^¯·<VuM@™Ö© cȘ÷6†è‚Cïw‘‰óBª\'€XÙj0…þ²”jÍê™<ã‰RÝnGk5޶/F­<ÑÀÛ¢(t¢ÛÅ(¤`)ú餓ó~Þu»333çŸþ3žñŒÑhtÙe—]|ñÅDô˜”þ¦îyçwÞa‡vÁ|ç;ß9á„ÞøÆ7î|ÎÕW_}ÅW<‚{xæ3Ÿyíµ×pÀ?ÿùÏÿ×N“7¾ç=ïYXX8ãŒ3'ø«œp §žzê!‡Òét6oÞ|Ùe—]qÅ;êîúùîºî®9çœsžúÔ§ÍÏÏç;ßù§ú§Çj¹á÷ÆÁüÊW¾òè£^½zõ¦M›þáþá _øÂn–çüõ¯ýK^ò’µk×nݺõòË/ß9IòCòÜç>÷Œ3Î8è ƒŠ¢¸å–[þöoÿv7SO=š÷ÆQGõö·¿}ãÆEQÜxã\pA¿ß1Æžö´§=ýéO?òÈ#Ó4=ãŒ3v9ÕÜ_a…~- “žh¸<ÜRÕˆ¼ÕíÆÂ`´$¥lç¹VZk1!;iƨ.kÁY"µs®r½“yd\1”Ø[ZZ³fͺ5ë¶oß~ï=wÿø‡?¯*<àÀc=IÔY‚ˆI+±è‹ºÌ­”œœœd€õ¨ uC€­nwݺu›6mê÷–Š¢˜˜˜(Ët0ÔÀ؆ {)%¥äÓ“­vªöX¿–Þ¿yóÜÖm¶iúÛ·ÏmÙj eI¦¤öžpíäüâ|m•('L°¹cŒMS£2i©ÁòRš¦i+ìN,.Í%I:9‘ ,ÉXU!ò¡×ëG£ ½Å^g²;¬ë}Q–EUÕu͘Öõæ¹­u°[¶íµ×^Z* ²Æ.l_üÙÏÖ[îC$Þ×,òÈÎî1ëœG¬Ó™Ty -öØk@lLbQTK‹=ï'R-¦§V×e•(À†½ÁòÒÀ4F€pÖ¡s~œJªºöÑ3Î|£bT×ÕÞûl€È("c{Ûç¶mÛæœãŒ5Õ,IQ !¤tÎE…‚3•øg©N­"D@„ˆCcPœ ÞX³8"²U«gV¯ža«ëz´R*çŒbÁò<‰(†#k€($olÝŽŰh®U2ÑVy×Z2L=½$ IDATg[¸È¨LT‹2À¼вáL0Æc„Ð8“å­D¦5Ãbdl#”ÔyŒý_sýúõ'Ÿ|ò%—\òÑ9ßõ®wtÐAãϦv çü¢‹.ºâŠ+Î>ûlc̯føüÚ×¾ö`)CM??d»9Zë¯}íkÝn÷øÀ† >ò‘LOOÿÕ_ýÕ£/ýMÝóžýìg¿ë]ïB\~ùå;tÎ 6œ|òÉ_úÒ—vh 1Æ•ÿˆyÉK^râ‰'J)?ðÜ}÷ÝíüµœtÒIûï¿ÿ7¿ùÍ^¯wÄG\vÙeOúÓwè»~¾»®»kŽ=öØg>ó™ÿüÏÿŒˆûí·ßk_ûÚ3Î8ãøã7Æ<1ãù×òÁ~pãÆ×^{íÜÜÜqÇ÷ùÏþè£>óÌ3w§t¼vvÊ)§|þóŸ¿þúë÷ÜsÏç=ïy»¯s¾ímoûЇ>týõ×⟘˜˜xéK_úƒüàSŸúÔã*ï‘GyÓM7ÝvÛm^xáªU«Î:ë¬g>ó™Ç{ìøqOMM}ë[ßjš¦×ë­[·î¬³ÎÚYç\™û+¬ð¸ëœZ#ã݉‰Æ:ëÜx»#ç<õûý±·g12MÒ5«g”VÎ.…Γ¼(gƒ÷„‘ &¥"€ÑhdŒm·:kg÷ˆ'§¦¥Ö ¥u’ç9Å`TꪈÎi!ó$uÞö—z­öìÚµív{zzzõªUœs"Z\\£5kªéUÓY–¬™™é´Ûy¦¼'ÎqõÌ4Pö—%¢J&­V[+M€1„DéÿäÇ[çîOÛ¹ÎS”h\SJÓDLÓ6ÁV#£\©…R$™‰BгUÓˆÜ8»8èª*†ÐT j«Æûè‚·Îò4Ë©7è-ôîßöÀÂÒ"Pžd…R*kgÁº$Ó{nXß™j»`…÷¾ßŽŠ­wI’´Z-"òÞG¢Tg.sYš%I’éÈ÷ûËK‹‹¶2θbPTEM2• &€0„c£ŸRš)Œ|Öœ Û炳³³ÓÓ“b²£ †½þRQ•ÖYïœoäBˆ_dì´L鈖„äƒ7BŒÑ#D¢Èg>FÔ (xŒ £eo ç"K3­TðÎ;¿u›T<ϳ,ËÓµk¡ilYÕÆZçÈGë™ àÁU®”å  ÑB¢u–%Yžv;“‹K Î9Š‘s®uBÈhùÉO¾îu¯yßûÞ·zõêÇ[ÞW¿úÕˆø‚¼`|r¯×»ä’KŽ<òÈ[n¹†ÃáÓŸþôï}ï{oxÃl4®Ìýžš¦ÑZÿÚ5—¦i’$ù}j(xˆ1âZ$‰Ði"•DDˆQ'š äÓCS7µ©=y‘Š@ÞGœ÷äkS…Q)%´`J4ÖÈDî±×úUkWÀäÔTšguS[çAm«¢(`0N"SŒ+.¦&:ݬ›Ø4ô¶…9ü ŸèvÓ<ïNO5Þei¬ñ@>†ûîÛTUåúuëöÞsϽöÚCpD„N»¥¸˜È[ LpÀà""¦iÒ™èÔu½°°4\"@š¤Yô(Zc½uH •V ¹Ô,xk9pɒɉ$K0UCªºí5«””‚qg-Á™ˆ‘œñÓ“SY’3ÀѨXXØ>*ŠV+ç‚ɦnš† ¦=ÑnsdR(àƒ©¦®“T·Ú­îÔA,ËzaaaTŒƒQ1Iš‰ÎDS5>ø‚s®®ëècðÁë¬ÁÅrX †ã$+ÁEˆØ€INLt’$M’´Õj Á———{ý¥åáÀy‰8EQ0­¥TÞÊ”ÎZ¢,|ȘRIE!DBBCÁ…DÁDg½±ÁÛ}Œž1TJJ%8WClœol¤¬A™¤-•dI’´[mÎY9 ‡Ë¶1 €3–è$IÓ4ɲ @ˆÑzoœó!"ýÏz¥”Òzçœã! Gcôˆ(ƪ,cð>x¢à¼säCDθàdêÆÔM°†EB烱Þ2è™æÞ†Œ Žˆ1D`,pÆ€ñB ÈçI’VR ÎecÛýù¼ÿþûþóŸŸŸŸ_ZZúÒ—¾´Ï>ûì¼Fûñü®»îZ^^Þ¼yóÇ?þñ_úÔQG]wÝusssóóó7ÝtÓŸþéŸî(ºþúëo¸á†ç<ç9OzÒ“nøÆÞ›»Ã.® ÇwÜÍ7ß<77wÝu×=ïyÏ»îºë=ôÐqÑ)§œòå/yÇ™‡rÈW¿úÕ7î¦Dûì³Ï 7ÜpôÑGŸwÞy›6mÚ¾}û•W^É9ȾzÈ{Þ/{ÙËn¸á†ñwä{ßûÞq_{ì±;NØÑï}ï{©î£éç‡l÷˜c޹á†úýþ–-[>þñw»ÝÝï«]ð'ò'›7oüÀç>÷¹,Ëžýìg?úÒÇÝi÷ÿüŸÿó³Ÿýìšk®yÌÍz?úÑ–——¿üå/¯_¿~÷ç/üÙŸýÙwÜÑï÷ÿýßÿýE/zÑu×]7;;û˜ŒöG9ÚíöI'tüñÇ?ÜÞØc=?üðk¯½öë_ÿú‰'žøØ>Áã—lSwÝuç|7gÙ£©ûKüèG?÷À3žŒoûÛ; uã7rÎ×­[·;¥§žzêüãG pÀé§ŸÎ9÷»ß½ãˆsnëÖ­·¼Ng0ìP7mÚ;^†ÖÚ[o½ueõ ¿ ºÙwÞ¹c®ýÒÊò]wÝÕ4Íï“P;˜Û¾}¡ß›_\Ø2·õ¾îÿùÏöó»~ßý›çæç––{Ký^Ý”Œcšê,K˜ã !¡@\QžW,mgéîÔÌôêÙ™Õk¦óN¾vÝš}Ø÷À'°Ïþû¬š™V‰ãc Œ¹ÊV¥­j×T¾ ,fÝVwfš§j±¿´uû|í-×ó"N“V«Õ4ÍæÍ›o¿ýöo~ó[?¾ë'ƒåAô^+™gI»ÝÞ{ÃÞûxà>ûí»jÕjÆØ`8œ››ëõzÖ4YšNv»­V;ÏZYÞʲ‰Vk¢Ýne-)$0&³$ïtòÎD6ÑžZ½jjÍê¼ÛÉ'ÚÝé©5ëf÷ذ÷žûlذß~{í·Ïûì½n¯=VÏ®QY“Z*- ÈØÆyK@RJ­5çÜ:«·[­qc݉V;ç‚r6Ñéì½aÃê™kýp8ŠªªÊ²¬Êª×ëõ{ýÑpdõT¹]ˆˆ€™Æ:’4ŸY³vÃ>ûpàAvè!‡zàAí±÷žÝUSBKâ‘",É!$s> FÅüÂâö… ›^µzzõL«ÝI³VÞšH³Vš·’4W*Js)€jÆ0X €@Oàˆ“( ômðsµóÆ-÷—ûýÞ¨5Mb̲lzzU§ÛEdƒåÁÜÜÜÒâbUV˜¥ÙTwrõÔÔd§ÓnåJpDB@b Á9[E¯×›››«ªÊã½GÆÆÆó4Í´ÒBHÆã\*ªº.Š¢išŒ#¿Ó‚÷1Š1†ÈÓJ )ê¦)«ªª*çÜ/ŒG@(g€ÞZSWMU•Ãápy¹]c #À@ Pp)¸O %¥Ö:MÒ<ÏZ­¼ÕÊ[yžåY’J!h·ãÖî½÷Þ·Ür˦M›ÞúÖ·zïßþö·å+_yò“Ÿõ©‡rÈŽøK/½”s~ÆgÌÎÎîð}ÚM—°]_yÆ ×]wÝw¾ó·½ím‡zè•W^Ùívßÿþ÷ï(}Ö³žµó¥žýìgw:ñÏ]Kyžüñý×=99yÑEYkO>ùd)ea×}µë{Þ5c÷°5kÖ<íiOûÏÿüÏÛo¿}Ǘ͘qž{rÈ/Õ}4ý¼ëv>øà¯~õ«c‰Ö¬Ysþùçoܸñøãß± j}µëv>øà;î¸cÇÏñÿŸüä'ñ‹_|”¥Ùú¦7½é)Oyʃ©úЇV­Zuÿý÷ö³Ÿ½õÖ[w³Ýc=ösŸûÜUW]uî¹çžp øÀvþ>ãϸòÊ+¯¾úêsÏ=÷þà.½ôÒN§“çù£í~.ì½÷ÞW_}õm·ÝöpÂO<ñDïý×¾öµÙÙÙ /¼prrr¼³nõêÕ‡vدžï½¿á†ѳß~û½úÕ¯¾í¶Û~IÛÙçû`uwÎùé§ŸcÅé!å}”ãùaM¢(î¹çžÝ)=âˆ#nºé¦c=öu¯{]žç7ß|óÇ>ö±º®w§¡cŽ9æÞ{ïýµAÔ×§ÕUW½ìe/{Îsžó•¯|…1vÊ)§lÛ¶í¦›nÚý.zds…ß?n¾ùf!„ç.øcÉŵֳ³³ûî»ï¯í»ï¾wß}÷·¿ýíGï–ÿ³ ¡v°ÑZ3ÎG¥¥Œs–fšqôÁD@ÇN‘ Ÿ^3=Ñî¤Y&¥”B0@ïcD¤@¡1+]cLYW “D !µŒ!G)T–¤™N¤RŽ‚”Bå©ne¦4÷m¹? g:ËTÓ”U%9gÀ–ûý¹-Ûææ7>é ýöÙ°~ݬÒZ+©óV·ÛiµÛ£áp4õ{€$šs–dIˆ>RŒŒ¬·Î[%D*µ®© %B ) #pÆ.wÞE\a¥bÀç1Z×Te9,%y–;ëŒ5‘" !\€¢,Šb/Ú|¢ÝÎót48ç|ð€˜çùúõ{p®¤ú1c\#McˆèF<¢MÕŒ`Ȥ’¥’Zé„!ŸìLNONuÚÎD·3ÑqÖ â*뺣¢,o\tž!ç™Ô !+ëÆÇ85ÙÍ[íîä´±®kŠ„€1D.<çÒ[Ç ã À9œgÈ1FÄ1Ä"ã\qî"!ç…4Uíë&XcR­»‰V«•eép°Ü[ª«º²ÆŽT™fy»Õnµ'ò4ó‘Ñ4Æ4–ˆccðÞ:ç¼w¤z<Â9iš .ˆ¢ÞÃ8cœ¹àcÎ9뜵6Æ0ŽÊ+¤R†bˆÞy`œI!¥Œ"zï1@ÀGDÁ¹‘q÷)x$’Œ£D&L„R‰Šjgúƒñ."Bä8g\ ç ¸VR+Å:c‘ÀÅ‚sÖ3d»«s¾ç=ï±Ö>ëYχã5éM›6vÚicíå_ÿõ_w6Ú,--]}õÕ‡rÈx¹ý°Ã›úÿÙ{ó`Ûªê\|Œ1»Õìî´÷r/.jý ÂS¢ò0¯R ÄŠ±‹R•§1mŒÆ>”©§QÊ(` ±‰š(–©"Š•FÌCš˜¨¥•îö÷ÜsöÙgコÙÿþX¾[·®Ä4çûkí=÷škÏ1Ç\k9ÆøÆììÛßþöý×€/~ñ‹GöüÙÏ~žýìg+¥®ºêªGt—Y¿ç׿þõιç<ç9EQ|ö³ŸŸŸÿÝßýÝ ö¼þˆc~~þÌ3Ïl_ /¿üòÈjýÿ¼>n»í¶Ûn»íä“Oþ‹¿ø‹[n¹åÁç¶|Èaœ×¿îÿñ;çÎ?ÿüét “ÉäSŸúÔ9çœóµ¯}íaeµ>æææ¾óïôûý[n¹åÆo|ë[ßÚ~yô­Ö¿.}ìc»ì²Ëî¹çž‡´9ï¿ÿþ~¿ï½á _øð¿÷{¿·Á¶7½éM÷Ýwß‹^ô¢µ×^{ÒI']pÁ\¿oyË[î¿ÿþç?ÿù!„/|á 'tÒóž÷¼_âQhûc·¿ñ¿ñío{2™Üpà œóç<ç9­Ú?ýéO¿æšküû²,[§âÑkÎ÷¾÷½;vÌÏÏ_}õÕ¯|å+d yØù]çÜõ±uëÖ–/jqq±(Šç?ÿùßùÎw62Þ£Ñçã—~é—^ò’—¼ûÝﮪj#­[¶lyÜãwÝu×]}õÕ!„÷¼ç=çwÞ¯þê¯näZÛ·oß³gÏÏ2G»Ù¿æšk^ò’—|æ3Ÿ9tèÐÌÌÌ}÷Ýwî¹çnœÜûQ¯ýMü×ÃÓŸþt)eË®)„8l>Ö×%¢SN9å”SNù/)Õþ Ï… Æd¢’4Áöœ3F$•"%ÈèZkÀ””“i1&I’¦Iš%Ä1MÓ^·OÄ´ÖuU5u3–ãéXJi¬)«ÊZëc 1!÷I’„EUųn¯?;;èõ)‚´ÖVÎFF$ù¾ƒ’N6;;—u;ÚY(°¬ªßsÏâüüŽmÛ«Ëïýßÿ{×íw<ñ O8û<õ¤“OÌò,D/$Ÿ]˜]˜µ¯Œgæfë²­®kDëtmšÕѪ3Ö6|”ŒKD2e#ÖMUë1ò›¦)«²®*ëÜ`0H”’B*)‰ÈY;^›‡«³³³J À¨9ÃûÝ^WH­Ö.¸i1©ª1öúÝÙ™m޵֬®|ô>b‚ ©ÕíõFÓØè!Q) ï­1F7uSc¦RVeÕéäŒ1D–ç])d·×K²Œ ®­Ó¥¥¥C‡•eé¬5Æ0Î º(É3ïcÞíæyŽCtÑD)—²ÓëË$uÎY­ˆAÄ¢÷^7MÐV1î³h IÔ"ŶTŠÞø ”PY\ëˆ(2òÈlðλɴ©J†R¶•SÓNÞáĬuÅ´h*]PBe3iÎ%cÌe^c­­k£÷Þ;g³Î9ï}ëž >J¡CbŒFâ\&Þ#˜F{ï lð1úÉ^•w^ûÆ;Bàœ Æcˆ¢”ÒMDÞù„ˆDœA ÎúQ ÙÍ;¥2)S!S!# qi¸<OM­=W^$iôÞ;g¢”RbŒ!BŒBäbÃùœçwÞ׿þõmÛ¶]صkדŸüäö8ÆØëõ.¼ðÂã?¾Ûí¶a¨[¶li-´Ý»w‡Þö¶·½ï}ïûÞ÷¾÷H÷Ï~R…BGR׬ßóÓžö´¯ýë‡ù_úÒ—6ns®?¢#ýЦÒY_VG)ÿ€8û쳿öµ¯µ'\wÝu‡¿|XY=¬Ç&„0 žøÄ'®¬¬´›a‡Ÿ»GÓz4Zw4ÿùÕ¯~õÖ­[ÿüÏÿü!Ͻúê«ÿú¯ÿº=ž½å–[.¿üòÏ}îsIñ:묳®¹æšÃÁŠ_þò—´9××ÉŸ:÷¦›nzH›óQhûѯ…Ûo¿}ffÆ9÷ˆ4§Ûíž{î¹mbóý÷ßÿãÿøÂ /lmÎ/}éK333¹ä.š—]vÙÜÜÜÙgŸ}Á|ë[ߺì²Ë6>¿?ë܇Åt:½ì²ËqqqñÅ/~ñÅ_ü­o}kÿþý;Þõµýè¥ÑîVüÝßýÝ7¿ùÍÇüÿ¬V!Ä9çœsÎ9ç|ã߀›o¾ùÓŸþô³Ÿýìn¸áa/Ç9ÿY1éìwÜqo|ã—––®¹æšÙÙÙ‹.ºè•¯|åë_ÿúlÍÚßÄ&6±<ñ Oð>„¦iˆ‘Tjnv6ëvbMÓLÆkÞ«®†$S}ÈûÝù¹y©d]×1 ñn÷ž½ËK‡–W–‹¢È²¼ÓénݺuÐ!g 81b­‹‰#rÆb–u FDV#ê†!1D%UÞë .¶uYóD­Ž×V†+ÎØ<Ë’–ÆKÅýÓL%'¿ó¤“NZ>pðÎÛï¸ûŽ;ïºíާ=í©gœù”SO;Åyˆ>0B©äÂ1 ó‹óV›ýûöEˆœóZWe]X:ÈqÁ´Ñ1†™¾.jÄ4ÖZãê²F„n×9㜶c*U"$'ÆZ¿zˆ ©×ízçæçg3}cmˆžãBú|ˆh3ÆXï‹¢\].-ܺåÁ©¶ÕÒ¡E=M²´Ñz8Ç¥)”iŒM]¯×SB! 1MY–`p!Z‡>ë&ãiY•D˜$)o£›ç\]뺩û."1)H0-,˳ÞLŸ ‘uººñãÉD Ùéd±(§®½÷Îû™ÙY¥”Öz¼¶|DBD"dD¤«ºžœ˜sVhéƒOÓœ3D(•"FEQD¢$ïH•’w¡±ÆX“†`œ1F{ë Fëìp¸š*¥¤ôØë{ï˲nšÆ;Z6MÓIó4Ïû3ƒ~¿ßèf2™€÷¾iš¦i¬µUU1Æ´Öãñ¸®ëµµ5)¥RJ)Åç’ Î¥1ˆØ>¼ª²œN¦ÎZ.„s.„CøÉAŒ!„‚÷>zÏ(H¥º=Œ!*!S™¢õ" >„§ÙÜÌ`¾?˜íöR))„º®‡ãµhE’\8@kÃà Cјˆ(œe¬ÖÞ9†¤”â\`²9cóóó^xásžóœ#¿?œâøÔ§>õÆoF­c¡Ý0n³`Ûw¾ßùßù³?û³o}ë[ÖÚ[n¹åµ¯}íwÞ¹ÁÛÄSŸúÔoûÛíñ½÷Þ{òÉ'¹1¼NÏÛ¶m;2JêСC¿7­?¢Ã82®uƒ²:JiüÄììlK’ñ“ð•µ5kíƒ=–ÕF^£;ή]»Ž?þøÑh”ç9"6n¦õh´îQÿç¶Ãë^÷ºv»Uª<Ï{½^ë<’mxuuõ}ï{ß§>õ©³Ï>ûúë¯ØÍé-[¶Iƒy¤¶¯¯“í¹+++‡¿?òøh´ýç²BâµûÙÏ~¶”ÛŠA»víúµ_û5)¥1†ˆ’!ã°É}”šŸúÔ§àÒK/}Ç;ÞѲ§Þ~ûíœßŸuîâ,Ë}èCíñ>ð{î¹ç]ïz×Ë^ö²‡ïúÚ~ôÒèt:_þò—«ªzîsŸûགྷŸÕZ–åÊÊJkpÀç?ÿùOúÓmöïÃ^quuõ! ËVÛ»Ù¿ì²ËN=õÔÖ[{ýõ×ñ‹_¼å–[6RSêQ¯ýMlbõ%X_•Åd:ÕÆcãòÁ%ÎY 1ÍRÆHqÖUYOe„ \eÉãÚp­iêáêhïî½>úÉxê 10äJ(%gFJ¤2ÚUeí|Í8Ïò\ ¥„bŒÕP+©çŠ Æ'òÖmÖº©1âÖíÇ{ÜqËËË«k#  ëº.«2Z`éàìÌ̱[·?ãϸÿ¾ûnÿÑmÿüÏÿtë­?8õ§ýï—ÿî‰'4;Ûc’Cˆ.:gU¢Ê²œN'uS!B7ËçgfuÓ¬MÖʦª›f×¾ý‘q!:D„(¹Â<ƒ<Ë„àMSÛ]{ç‚0© bmjÎ9õû]c]]TÎëLÝ”e9%†ÎÚÉxmÿþ={öîé÷:M£‡£áp4,ëæÝ{'ãéx<îfÁeKB“¥y7ï¤Iºišªlêz<We ‘±4I˜àY–‘µ.Ƙ 1;Ïš¦¥”y7O5šŒcŒRc4 fnp€„!âc@.8€È8ñ„‹D G­•÷íž rÎ9ã€Ñz§”J ;1pλ½Ž÷ÞZ'¤hIYÓ²ôÁ3.˜H"kÊ¢ÔUÉš !¢Dè­ªJ×u–¦išë)³$åÄ´ÖÕ´X²$Kgçç»ýç<†ç9¥‰´6‹€m&çt:­ªÊ9WUUU5Bˆ4ÏÒ,ž£#cŒ ˆ-p] 8ï¢!kmëblMPCÔN3Æ„Œ(*U)ÔÚXß:Ws®!Àåš\QÄ¢³EQxÀIU2Àn§œM›º±Î¹<0Á•$Jqν6Ƨ5ˆŒœõÀÔ†lNï}UUúЇÞüæ7?äÞÿþ÷ßzë­ÏzÖ³ÚÝåsÏ=÷/xÁ‘?øô§?ýéOúÄO<ï¼óÞùÎw^}õÕOzÒ“6x›¸ýöÛŸõ¬gµÇÎçY§çñxÜívÿ²×ëýÔK"þØîdl|D-ìöyXY¥4þ¢ªªÃy°­$….Öò(j«Üwß}-åL›Õö„'<¡5T޾õ(µîÑýçãŽ;®Óé|üã?2d®Úµk×Î;ÜUkûm$2„0ŽÔð#iœÖ×ÉÂÊÊÊ‘ïè?Eõ¨µý¸.¼ðÂÂ[Þò–Ã~¼,ËÎ=÷Ü›nºé¼óÎ[?ºò(5çH\{íµÿçÿüŸ_þå_~H»qýù]ÿÜõ1n½õÖ³Ï>v¼ëkûQJC)õ…/|a~~þÏxƃ÷Öiݵ\102 IDATkבÆa]×ι#ï3ëàÖ[oý­ßú­$IL…ò˜Îþ3žñŒ¯~õ«‡Ãƒoºé¦ã9çœó(êo|íob›Ø ê¢q™ð^¯Ç…HåC(Š’!a„ép­©k£µÖ:@\Yg½Ä˜JÁ„©L9))IâÄQPĦÔðʹhš¦,Kc­›`µ+yéC>ÌÌ ‚T­-gÌ{/wÖ–ÓB7MPYVV%2†“bº<cŒñª®WGk[滽Þ1Çl›Ž'ÞºÉd|Ï=÷\ãÏüŸÿóÄŽŸé÷ó4M‰…—3³3R £õd<©ê2@œŒ'eQTEÙ˜æ'Õ,ïô»½nq¦ëºÓë£!ËÒ<Ͻ÷ã1Æðÿ=@‰1$4MSUe’¨4Í8gãét2s!…àyžcŒ5œhn~ŽAŒUSyë:Ý,DäR)óN‡ˆ:Y"êZ¹[gffÒ$­Öu]ÆÈ8G€¦iœsœ3$‚@!olôÑK‘Z×hc´>B$"Á„¡ªÊ MT‰âLpéŒ Ö‡Œ1RÅèÑ ‘óÞÇHĉ"xmœuÞB"ð!bØhlí·¿ýí_ù•_imè·ž|òÉŸüä'‡3{î¹?ëuüŠ+®èv»ï~÷»cG†?M§Ó#9KŽÄd2yX®‹‡ìùî»ï>ãŒ3ÿæ)OyÊO=Ô¥”ƒÁ }×9ÌgûˆFô(dµi,6¢uô?ßqÇ­pZœqÆW\qÅ›ßüæ¯|å+ÙÕ3ŸùÌV7rÝ;ï¼ó¬³Î:ÒsµqüÁ~p¤†ÿµýè×ÂÌÌÌóž÷¼åååÓü2ÆÎ?ÿüO~ò“‡cé•R«««^xáM7Ýôÿø‡í«Ÿ²7®9üW§žzêO¹°6>¿ëŸû°عsg[täaÇ»¾¶48çû·{Úi§=ó™Ï|0Òú­ßúÖ·Zö V§œr ç|ƒEV¯¾úê—¾ô¥¿ýÛ¿ý‰O|â§šÓÙŸL&[·n=üqqqQí#Zû›ØÄ&6‚ŽL8ã6±ÞÇT%J)FÔ8][_ ׊²(Æ“éxRU•±Ö_W5r„@”$éüüó¼—ö‘ˆÅèÈס±e=ÖRJƘ@i¼³Þ¾,&U A©Ð!"zïã½NW)÷!WW[ÃÀYçÕucœ…ˆ4)ŠƒKçgfææ¶mÛæŒiªÚ9kŒ¹ã®»ò~mmmq~~nvfËÂ\¿ÛãÄT–0É‘‘|e¸¼6·É™ cµíæÚšh=ø€H¶1ØLfDÀ‰S€,Ëãu]Yk‘J¤RªŸghꚈ”’Œ‘ÖM]UiŽišæyÞ¾&YÚÉ2F¨›1:F>zb"Ïs¥$!cŒ%2i*mŒ‰8ãy§³mÛ¶…¹9É¥w®,&ósó3ƒþ®ÝZÖÆZãÊ¢2ÖjÝÄã´(¼÷Î["Š1–U¹ººJŒ”R­[Ïy¯Í;9'2G)8‚’T Áã¼?èi­™’µÎ ÷MS‡(C u³f !Xg…’mþ*|ëÂvmíòpu:-œµÆú²®ÀY¼÷BΣwÖZ€€œ¸d¼(ÊC›¤Í“BP'7Ö禓i‘ˆÖFkRµ‰Ü2„(¤´Ö¶Fc çC]ÕÎû¸@Lr„‘ˆ””1„º®`Ïg 1Æœµ­š#!˜±N*Ä‚sFÛ*VÔXã£o³Çklp–rE.xb$&¸ŒŒ"qÆ"#X〈‘ƒ‚±DÀˆÞ; Ĉø ÞÚg>ó™Gz9š¦i‰=Þóž÷|å+_ùÈG>òž÷¼giiéq{Ü ^ð‚o|ãmäÏøÃç?ÿùó7³{÷î .¸àU¯zÕ‘}žsÎ9OúÓ?÷¹ÏÝÿýÇwÜóž÷¼ïÿû?ebÝzë­¿ÿû¿ÿ²—½ìŸþéŸBwß}÷F*b¯ßó‡?üáo¼ñmo{Û¥—^ú¤'=é5¯yÍ‘ç~÷»ß€w¼ãï}ï{ŸøÄ'þTíõõG´>Ö—ÕF¤ñè077×úu“$ɲ¬uÇã–®óhä¼>>þñ_{íµ—\rÉ{ßûÞÅÅÅ|àû÷ï?²Í£Æ_ýÕ_½ñoüð‡?ü‡ø‡;wî|ë[ßzÓM7~;šÖÇë\·,Ë#ƒ[7ÎÝwßýýïÿð¹7ß|s~þùç¿á oø‡ø‡üà¹î•W^yÕUW½ò•¯üÌg>sî¹ç¾ô¥/ݸN¾ÿýï¿þúë?ô¡}ò“Ÿl3 ^Ú~ôkaûöíûØÇ¾ûÝïnÜæ|Æ3ž1;;{ã7þFk}Ë-·\pÁ¯~õ«WVVÖßM؈æü¬õùÏþºë®ûÁ~P–åYgõ¾÷½oeeåpxäúó»þ¹‹$I~ý×½½¼ð…/ܹsgË]ü°ã=š5¸¾4®¸âŠç>÷¹_|ñgœqxûïßøFkέßúñüu¯{݇?üá7¿ùÍRÊ~ðƒ“Édƒd¹×]wÝÍ7ß|Ùe—Åo¸á†n·{ÑEÝyçŸùÌgÓÙ¿æškÞøÆ7¾öµ¯½êª«ƒÁå—_c<Ò­zþùçgYÖçžwÞyËËËwÝuW»=w4k›ØÄF Doƒ·¶1Îñb4ÆØº®G“ÉhTu1žÔuŒs!O2®¤õΛh+‹ûY?Xc³^ç½Õ6c…MÒ´ÛëÂ6³Ñµµ–õ™”*¯µ©ê ]ã;YæR'$!2ƵÖK‡I)Ó$aœ3!d¢t­s¦®½±,[\Xرã¸àýÁ–W–«Édm2Ùµ{wŒq4åi2èu·,,³°877›¦ÉÌÜL·“ fúkãµù…¹N¿+w©÷úˆŒ«8ºJn Ëi!€”Riš@@k5€1 õÌÆ÷Q³ F£Gï]]•eY"±NÞBµi‘ä¼kjÓÔ@Œ!x$c´ÖµÂ¶Ú5U]”%g¼õ§ ƒcŽÙ𥠄ÐÔÕÂâÜâœR2Â=——óÎyk¬÷ž­s“éÔ{oIÕæ1J!BÑ…4Mó47ÞÆ{ýn !Ä ”ȲÔZ­›&M”÷Þ:-%Ÿ̬×0kmYNÇãipQk@J)çýx²VÔ¥’ “4É;4Ëçlžå©h2É9Ÿ+©Ë©æÌIÓÖÀ´!""0bœsÁEY–ÎÙ6µ’ˆT’dY&½ÓÖb ¡¥¡JÒ4Ë3)•Ö&I’Ÿd #&q°ÎCbÈ8!!„¶ngDι”ÒF͈¤”Ñ­µ±6Ä­µ>Xç½Â„8zÞm\ˆÑùÀ#ƈ}(gœ#Qˆ1`ô1F@Æp9ã!bð€ZÖ"bÁy‡V"I.)Ñ2ââºøâ‹ü¸´´ÔnÜ~õ«_}Ñ‹^t饗¾â¯h›~ô£~â¾öµ¯½öÚkï¸ãسgÏ›ßüæ#£C¯yÍkó¦üÛ¿ýÛK^ò’Ÿºî'>ñ‰3Ï<óÏÿüÏ۽ᙙ™$q­ßóM7Ýôþ÷¿ÿ]ïz×»Þõ.cÌå—_þ¦7½éHßΕW^ù†7¼á oxþ}û.¹ä’~ðƒ‡[×ÑúX_V‘Æ£Ã%—\òò—¿üðÇ6ì’K.9aø¨å¼>þþïÿþíoûÅ_üÆ7¾±õY=÷¹Ï}Dñ¨? »vízñ‹_ü‰O|âÀðÏÿüχ«Þeëc‡£¹î 'œÐÒ @û¶zX…ŸýìgÏ9çœ}èCW\qÅh4ºâŠ+þäOþdƒ:yà 7üÑýÑÅ_üªW½ê»ßýî;ßùÎË.»lƒ±Ðë÷ü Y m`íÍ7ß|ä—×_ýùçŸÿä'?¹­ôóÍ ”ò#ùÈáÄïo~ó›¯zÕ«/±õçwýs7²åÔÒw•eyûí·¿üå/°—ïßYŸ[g{Ëätçw^›“¹~ëwÜqÑEýå_þe»{²²²rÑEm0'?Æø›¿ù›W^yåG?úÑöwèС½èEõxÿôOÿt0\zé¥-«óÁƒ_úÒ—¹ÍôÑ~ôpáÜ+¯¼²Ýîio›G³ö7±‰M¬6%{íÐJŒ ›&ÄȉGìŠÄË ÈÈbD`#@ÊΔ¤à‚÷Æqb’'ˆH¼ñцòÆXã‚yÖí$¹÷¡Öµ7Þ‡àµK²~*ôhÁ£‹µBWMš¤\p!IJFDEQăA'ÏuÓïµÒº¬Êéôà¡%@xÒŸ4·8?N³³I–™ÕQQ”ÃѨÛëyïZ­«*KÒ'<þÔÓÚ1[·dY&”œ›Ÿ_زè‚[ܶ5ïv¹ùòp´:¡€UUí@øX.&ÞÏÍÍÉ™ADX­ï#),z_Y[5u9o‘wmíÆj:ƈ¼“dYÐd­uV×eYçLJ‚דּÜÙ²,G£Cò.Xã E1uÞqÎÓTe©ˆy®æfò4-Êr4žUSé&Ë2)DQÞ;Dàœë¦±Î Τ”½noÐéyï…½~?MÓˆ‘i­ëºbó,B¬Ž†F×-Y‘µb\œ›•œ×&ÃáêÚÚ¸,ʦÒàI© lªÆÔF ´M‚XĪ©}c¹”€¤TÒïõ”J9áòò¢˜zk­6eY>ï!炈!`ŒB@ÂØÖ¬ȳô'„LÞ·TµºÑÞ!|‹KD€ÿI¢Bm`-1tÁ;ç‚÷µõ=cdŒy"Á…ÂS–¥u–sÎÁ鯒d. b$D"Ž\ˆ 8'FœPI¡’DIÉ€œs  çL*Œ„DJ¥ãÌ‹Á3$%¸™gCˆ$‡'¾'¢SO=5˲={öüÔãŸs~Ê)§!n»í¶‡ôÚüñ‹‹‹KKK»wïþùÞMÖïùØc=á„î¸ãŽ;wþË¿ü˳žõ¬#÷¹·oß¾¸¸xÛm·=ø ûaGô¨eõ˜Jã…n·{ê©§Öu}Çw½ïô§8§Ÿ~zQé¥<šÖÇúº Û¶mSJÝ{ï½Ãáð‘^·eˆ½ãŽ;2&s}lÉK›¦yÅ+^qå•W&I²qµ_¿çÿŒkáQÏ`–eÇw\žç»wï>’Õi#ó»þ¹ÿ¥q”PJvÚipÛm·=Š ÕÁ`pÒI'•eyï½÷>¢Óf¼Ýn÷ÄO,ËòxD|ËG¹ö7ñÌÊÞ²eK»Sü¾ðR+å¿$ªªºé¦›îºë®»ï߀€„‰Bˆ4IÓ$áœO§Ó¥¥CÓqQLKcmˆ±vÆûÀ­w‘h~qA‘¤)ãÜ[EÓ4Ƹ¦nœw@¤uÌ1Û³,1ÆÖMS7u]kçÍ 7ôûm’žµ€£R 甤¢?ÛM³¤eqß¾}û–-[””ÞØ¦nÊÉtßž½ûöì±ÚüòSŸvÁsžã­»ç®»oûÑm?¾÷þiÓ¤Y¶eËâ Ç??;=¸ÿ€âüÄvžvêãN>ñ¤mÇË•@­÷ìݳë]k««k+k÷\®@š¦º®ÇãÑêꪔ²ÓÉ9c*•yž1†!¡Ä`ÐïtóÒ4÷ì¹\i·;77/“äŽ;ï~`×.@ê÷gT’ÖuÝtæçò,uÎTE  †i1*ÌÌ'I6ކ+«Ñ;å´ìdùÿzÖÿúgžuüŽRpï½R’F««ÜÿÀ½÷Ý¿g߯ïýt:mLÃ9KÓ$ÆcDD!„R©$U‰ntˆ1‘ 6¶áJZ^š"PJ†VWW¦ãQð!BŒ1*¥N8~§µvyyxèСªª ‚×!˜€¥*•JD=EŒ2‘BJgÝòʲn´ !IÒÁÌìÂüüL¶?Ûç‚‘ÀB]Ö‡Z>°4™L¬¶(¸è¤Ù´˜Xk‘sÎ8Jp"ï¼TIšdˆÌzg­ý µ,€¢Óé$iŠˆcm*&!@l¹m[†!`Œ ÎÛHoç\k²cê¢ÔFÆ­³µm’$áH‘"1ÄÖâED™*©$1$ΰ›g3½^'M P7fRÔÃÕQmŒPJ¦é¸®­ ·-5f–¦Ö˜è¬’Œ‹€Á@OôÈlÎÿÔ8óÌ3lsnb›Rž~úé­0I’›o¾y2™œþù›’ÙÄ&6±‰›smm­­­×:âÚƒ#Y7ñH±wÏÁºn@ á½Läy6èõÓ4…W†Ã={öu£mlð•i\ˆÀ¨2ºÔM€8˜™åB¤Yšu:‰R P3ãéD„IšnÛ¶-I’ª-Ôé}UÕÃáÊÖÅ-óóó‡S ­u1†$I'bÐé¥'œpüÊp¨îóóóƒ~_r±ï¾ÉÚ¸˜N§ãñêʰš¿|öÙ;ŽÝ1ZþøîïÚ³wRVUÕhݳuË“N?ýäO¯w?ðAÌ’ä¸;ÎxÊSžðÄÓ·³5Íò¢ªöìÝûÀý”Ó2ãêGÿö£ýûöw»ÝÇ묭ªêÐÒÒò¡CE1ˆsósÝn^ÕE¥«¼“{ìö¼“íÚ·{ÜL ™¤Ýî»ïþ]{÷í¯CDÈX’¦iš úý$‘Î]·6gœL§iÞÌ̲ûE‘&ÖTõtR8çºy÷äO8fëÖT)†˜¦i›|hŒ1ÆZë¹EYN¦c@J"¡1Z)%„ˆ!„—‰L&kãªjÐ9WVEäq¸ºRÕe>BðÎ…è!@”RBïÜÖÅ-Y–ë:´ººªã&²È”J’,’ǬwÖ;$ !ÔFǼ÷AI¥”âŒc$•«ÁÂlÚ˹àࡘN×VGÓÉT7#0bJʦiœw„Àç‚'ˆÑZï´# $Íd’­u]×!†$MƒA·×cŒE„-¡2ö“»÷Në¦(Š–fˆˆsž&‰Rªå°mU1„à·ÎFˆDˆ.ç)‚d$ŠLðD’ ®„HÓ4Mr¡¸è‘3àŒ sÆY]U“iéc[pSH)‘qòQɼ÷€B„!E`Œ)Á•䉒R"ÿlÎûî»ï¢‹.jS47±‰MÆÚÚÚãÿø3Î8cvvöÀ7Þx㣣KÝÄ&6±‰M=¸@.Yo&Ÿ_œÑº Á麎ŽXÄ´Óéw»B0k›*Äh|ÓÔ1ú^7ߺeaqvVu³œ6Mcmí¬ HIšÍtzݬSÅd2MÆŒ ™$R%ý™ÙˆäeÙmô ×S¹ˆÎEª² 3^É l0Dàĺy'ú@.„™n¿¬êá¡•½»÷t»½n§ÛI³dNÝXc9‰ºÖ ËTT”9£½­­‰ˆsva:™åÔ‹HÈP[ë! #Žˆ¼ˆœqJ“Üç F)¥s^0ÆóÖ‡€ !œÀºÑ“IÑë8g1ƘŠ.•r`Þ9ÉEôž!KUJ@N[k èfÂÇÊè5µõF Fœ‹È Œ!øª.CôÎ!%cÔt{ŒgŒµœGïÁkÛĈc–%¼ušq$$Æ€s‚)%¤dÎùª,w?° "‘u–ˆ†+ƒÅÅŃK§ãÉÜÜÜÌÌLšç[·o“‰ZS¢;è÷ã½ÏòÜ[½ÿÀ~ŒqnîégœyÆ)§œtûm?ºýöÛî¼ë®Ûn¿}×¾½gíÞ}ÜÎú33sóó;vì€H³[QŠá¡¥@873‰\ "“ª×É¥à‚3ŒÞêFCŒœ¤Lgòã‚ ÞO'eQ ¼çŒ”Áº¬2ϲ^·Óë䉒ˆ¨²ì¿‘͹ººzÕUWm>Ì6±‰ã®»îºë®»6å°‰Mlb¿pÈ”£Y>8^ooêºÕFkpŒõ:uyùÄ“NŽ”’MiÊ¢H¤šŸÛ±}DZÛEÄb2©³Lpnšfm²ºB©ÐMSVEZ%sósÑ{+–e9ó6ZYÞáB¬®Žš¦qÖÅB)¸u³¶iô´(mBŒˆ «¢¯Mª²æÄˆ±4K‘ %E"$“‰JÒ$O; ³ó!„ºîÎÌÍpÎʲ¬ê:ïd §ãéЬN‹)CÞÉrÜ4¶59 Ž‚“$"Dˆ¬1UÑDÈ4NJéL0µ3Ìr.R™%"+©tÒ#`”J` •ª6Â]!¥X[é¦áÄ8c1D&™«„ÚH\Ýèࣳ¼WŒ )C`h¬qÞã¿<6· IDATª¦.z}¢IbBBJ!!´¹šB "D"âDŒ1`1¼.hé‚cˆÈ‰b$dŒaëÒôž˲Œ1f½‹!p.˜µ6A©4I2%Dôá'nRï+ÝXçHRJ “!ïŒw€' qɹTIˆ™FíXkO '´ºqÄ”àƒ~v0Óëfˆ`¬åæ­ÝÄ&6±‰Mlb›ØÄ/ÌæÌ¤R¢‡ÉùòCÓÑ´n4Rò¬Ûé¨DdY"„°µ)ƒu¦aY"…àŒP óÎç!8dÈ·ÎVUY7µHºYšã5ÆNªºª‚õ¡¨«!ÍòÉt 1PŒ½nW Ñ )"€¶V[§„P©bІhC€È"cÄ!댶,­®®M¦Ó§³só’KÎD !Z HI‹1)‹Ñx­V2B ƒ™ù£v¶®›I1™LK޼(+‡Œˆ'Bq)c,p .c"%‹Ð%1â2¥Ƙ•ñˆ+ž'y§“ñ4óà]ÀÖúFë¶äDš ¶´,Ü9ïœeŒ²,ñà"‹Ì™%c0Þ !"FÎ2ˆ.XïƒñÆ6!z™–2‘ˆŽÈnŒk´­#™¨$‘uÞ:ãî)2F.šà]¬}]ÕuQFïCyžGˆÚ˜º©'ÓIQ–Œ±Æè¢*kÝ ffæfg¥ÎûáÊJUV1B l³•„˜Õeyç]wmßvÌYgž¡’¤?3³°¸X”¥qn÷ž=H;W×Íž½ûªqypß~ñ §œvöÓž¶ó¸ãëºWÖF£CKKýëltådJZÛ@ĹP$]Y­Ç:º,OÒtÛ±;Ò¸˜e9žLœ1ݬ£¸,'E]ëIY…)ÆhíüܬLÕ–Åq¸²|̒̃ Ñ$\¥YÆëF{7©*N4èô‰³{îúq*²_zò[ŽÙ>˜Ÿ›]Y^ZYÚ¿´´2\%ÁóAoÐé"S7¶n 7™T“ª,‹ºT4Í;Ý™^6èöªº±FU™Bra¬N'¶1£ãÑc䊫$5¬. "O8g,4PW•çè`¦ºS€"OÇu]K)yðÜò2•Š¥Iš(¨+=±LˆD$ €wDj-IQ31e°1H•¨Dyç‘À¹–"¨œNצåÚ‚=fqÛ1³³3Á‡¢(8#)U·ÓA€²*¦å´ÑMˆÁ+¥ˆ•¨DôΛ`@ÈDJQ7å´(´µÄ|vvë1yž&éÜÂüü–ç\€0·0‡„£ÑHÈÆÚ8·0»6Z—S«³ÍíwßícŒˆ[Ó¬+EÊx¢›z8G¶ŸÉ„IUTµ™Öûöì ÎwO<ñøãŽ=vû1€pÊ)'VÓbïîÝ ³ƒøKÿ_SW«ãÕ¥å¥CËK–7ÚjSÚÈÈ 5IÖH%‘ ×è2DË$&)ãâˆ#N;í´=öØcdddÅŠ×\sÍÔ»3¤w—8üðÃW­Zµ×^{=÷Üs¯[5Y¸pá¹çž;66vÊ)§¼R·3öÛo¿¿ù›¿9øàƒ{{{7lØð“Ÿüäßÿýß_ôɕؓN:iÑ¢EåryÓ¦M+V¬¸á†føÞ3Ï<ómo{ÀZ;22òÛßþößþíß^­í†WÌ]R´xñâ¯}ík .L’äþûïÿþ÷¿ßl6g«™à½ï}ï)§œ²ï¾û&IòÐC]pÁ3,Ƴ;:8½vcŒ?ó™ÏüñÛ¶m»þúë§–}ž¾íx]Áó°ç{q¢jä–¼¼Ð¾Wš=¼Ç¬ùóo„Ê缓µw4â‰ñŠ9Ë,çP‚”TRID°1FÈÂZØ[­ú®ïxa©Té¸=kx(l{ÍFÃ(Ùê´EQ@Œ«Õ€b |×j±yÇ6e$È÷|9@ê4K 1”QŒ°6@…Œ|¿â‡}媖d,ÿÐïÓFöŽÃ³`vP‡æÍêÛºåé'Ÿ^·nÃè¶í`AÎ XÈ1@M!Ec¢á«H(ä )†ºŒzUÖxžçûžÖƒvËÀ…H“ÔÀ\7p!(/„5–RêÂжñ±×S"˜(c ¨£rÑÄX#³*3ª6 CRŠz†‡ Æ’s¥¤†'n'qÒÌóT[UËÀv«“™𠬬 ˜ç ÄZÅÒ÷©”šQ”%­‘m:Oc !„ â9޵6/ŠJ­¦­Îò „ ¾•JìB7 V)­µµV¨r™%Ì/÷Uß÷=¥uRt’" Â@M\ì '`[-•²'Ep@1ó£ OÒ‰Vû·þwoO/ÏŠ4QTÅÄmLì nUzó‹<kŽiZÙT^¿yÃðìYˆÍ5"¸V¯i=¯Ñh¸ŽK™  2ä¤iÚŒcä:A) ËDtýÆÍY‘¸¾K]@¨¶8‡LB,×u]"Ï¹Ò X„AÙ+UJÚ%$°˜s‰"„Rª•ÚöÛ&&&BµžšëyÚÀ,E!&Æ;">cJŠmÛ¶K®K¥òæ-›þ¯‡Ÿøïg-Zd”\õõöW£ BhÃ(¡” qšk„”B*eŒÖ¦T.1æ0F#ÝäF¾çJUP4:-¢J9/b©2©t–å/X)¸à܃TJYšç™”Z€!ÔPI!µÐRF1†Äe%ŽífÓAÂŽÛí"Ë<ß ¢Ð÷ýrPBÆqÜ–-«qˆãP„°4F)ͳÄvÿ@€(iÒ8“=ß \‚±²( -¢ØuÆDiʆµÀ£•2Rw’ç£  •² Dˆ4ópµZªV«ƒƒCÃR©›6J)Ò8. ¡€e.C©$0¢(ŒÑ”cJ°Õ&MÚv,¥ŽÂ(MSæPŒ´ "C ¤ Bl‰=<å<çððð±Ç{ÕUWý¯ØœçœsξûîÛ]6½é1¾òÊ+o¸á†3Î8ƒs¾seÑûî»ï¥rÀìŸwùÞWŽãÜwß}•Jå /œ7oÞ?ýÓ?õôô¼ ˆ<àÝï~÷9çœC¹þúë'W¥óæÍ;öØco½õÖÉ•÷«[5ô•ùðÿóÎ;ï½÷ÞK.¹dÿý÷¿êª«úúú¾óï¼,zßÀ qüñÇ/_¾œRzá…>ÿüó¯®Ô½(.ºè¢… ®ZµjÇŽK—.ýéOzðÁõ«_‰ÄsÌ1 ,xðÁÆA´bÅŠ·¿ýí/Ø7y),Y²äðÿùæ›!„óçÏÿÔ§>uÊ)§vØaœó¿Œ¾(¦§è­o}ë<ðè£^~ùåõzýôÓO?üð×,YòSùEyµKœvÚi_|ñš5kþùŸÿ¹T*}ä#yì±Ç~ô£½¦ôN¯ÝÝÝÀN8á§?ýéš5kfÏžý¾÷½oÒæÜeÛ7ðºB­^÷]2b¬VV9œ=8ßù£­í|";íÆöñ‰Í#Åhìö ™9Ë€A£2ÚHe,À„…aP¯×7ÂŽFånÎLŒ¬çQ‚@–¥I§“Kù!FÄB¡ÕJ«)ÃÐH D€J×*‘ç9QжÆb“,%!EšûNà3oK²ýÙ?>WªTÍž?L™7o^„ýõÞ­[¶N4šq;ѹÔiÌ‹\×e>SrÁ¡!ÄÁÖÈrµD ³Ð*+„,p5.ò{úêaklÒŽ¥’’+c4FA@<)€ÄF[&O %ÛY'·JÅóŒ­ RbR4Mó4N²ÀùçE›g˜9€â»ÂÂÔ0".u¬ 4ÆÎ Ø Á‹ñ±Q£M¹Rñ¼A¬MÓtbbBi¬ \'*…”­U»Ý4FcŒÁˆ@©”ÖST­U*=U×s+å*"„0²ÄI ! c„(£•J™Qêy^TöŸµZ%´0Ks‹4çbë ­Ã|‡ùBŽ Hr.ÆÍêøø¼=öМW{j£‚ÿéùgWÞ~Ûøøø[Þrà@¿ãR_AŽŽOL¤Iš¥¹ÑÀ( ¹¶€@@Q7@”ó\kÉÊìPì8„Q‚4¦›á†~0ÌXhµÕÔu1"B± Í‹­;¶w:±ññ8IÒ,_7´‘"KE‘ó¸Ù.â„X[.GRÊv«³cǨïZéf£­•M:ÿå:®ÃØž{Îï©UÏÇa…N»Ùn6Û-.UÁy–ó³ÀX+”äBªNœ´Ûιçx®çZm´PJ)`ÀÁÌ-1 „X#%J+ u¡ÖZ1øs  ‚-Æ)D–$‚sÔAX)•@É!@!‹°µ@i#•–J1׃À2J)ÁX#Eš¦BBLs€ìV×ÔZ‘å¹¶FhIY·v=×qX‘gE‘ 0B”RBp·°ç¹„bmM’%›·nšhN(¥GGÇFGFE.1Dó|/0Ææy*2N)Ji),F˜D°q^!ÒV»Í¹¬TË¥RH)Âh50˜„æØÚÿÿahh¨T*Ýu×]ívûEx¬”]¾÷µpçî·ß~‡zèƒ>Ø]žqÆ—_~y«Õš|ÆuÝ«®ºêŠ+®øò—¿¼sŸüä'§>ü¿>æ³Ï>ûùçŸ?âˆ#º0çüë_ÿúe—]Çñ é}3ÇòåËW¬XqÜqÇ-_¾ü’K.y¥nš½³Gydrwãç?ÿù©§žzÞyç5]JìW¾ò•©Û"×^{íg?ûÙ³Î:k†êÖl6?ñ‰Ot¯=öØ[n¹å裾å–[þ:øR˜ž¢O~ò“£Ž:ªÛU£Ñ¸êª«ÞúÖ·>ôÐC3Ôî—Â>ûìóÿø×\sͧ?ýéî/ßýîw{{{_kz§×î÷¾÷½'žxâÇ?þñ+V¼Ü¶oàõ‡Q„‘PZsYäÜK„¾:Ù( ²Ôj¡Œ4QŠ™ªÝlg¹®Ë3мڸ,•˜ïEA©VjQ¥-HOòh]äy¹\Ê‹b,€c‚-°¡YqÞéÄ>ó<'‚jm(‚žë1J ÆBιµVk+9—BÔ*åÐ÷ÍÆŸ~ºÚWꨆ•Às= ¡Š@ùQRN3^4Ûívš$¼ÈW ´AB(&˜+e-p4ykÍš5k×®}Ï{Þ³Ï>û¬ýt£7g‚iz,]ºô׿þõŽ;V¯^ý¾÷½oõêÕûï¿÷Ö 'œpçwN>¹hÑ¢{ï½·[œp&í±Çk×®=øàƒÏ>ûì 6ŒŽŽÞtÓMã]òj—cž'žxâÚµk»ëÈï|ç;]^-Y²dòIî¼A¾;|Þå{=ôеk×6›Í­[·^}õÕ•Je漚øÀ6mÚÔ]ün¼ñFß÷ßýîwO}æþáž}öÙÛo¿ýÿÈZaú1ï¿ÿþ÷ßÿT›Ä÷ý¥K—ΜÞéÝzøÃZ­ÖwÞ9<<0Ð;4X¨Ô{K=µJ½Þ;808köàì9µ¾¾¨Z*Õr­§Rï«ööU{ûzúú«}}•ZO¹V­÷ö ÷öõù¾¯´æœ#„¢( ÃÀó<Œ±ÕÆ*íPÖ[ëèíïí©W£JÙ/×+õþZ½Ü:!Ô k¸±ÈLa"<Pc¨CÜ’_ª×zëµz–k•ÚàÀààà`oo__oß@ÿ@½§^)—ÇQJ*%ƒ0ž5\©–…·lj´¹(†ˆâ\O?ûÇ{î»÷Þ_Ü÷ÄÓOŽ6Æ50ƒ³†ö]ô¦½î3ðÀ>øànÛJ¥²zõêGyäSŸú”µömo{Û¢E‹&7௽öZŒñ)§œ2888û4ðé{ž7oÞêÕ«ûÛßžvÚiûï¿ÿM7ÝT©T¾÷½ïMÞ}×»Þ5µ«w¿ûÝår¹ûçô‚ 8ì°ÃÎ?ÿüjµzå•W !Ž=öXJ©Özz^M?æéÑ ëïïÿ«¿ú«»ï¾û¿ÿû¿'×j]txÖYg-Z´èmw‡ÏÓ¿w¿ýö»÷Þ{»õ÷÷ŸwÞy .<ì°Ã&#Mëéß»ß~û=ùä““v¯ßô¦7ýìg?›\¨}ñ‹_<ðÀ_jy}ñÅ×ëõÍ›7_wÝuÿõ_ÿõX+L?fJéÔÐÁ.ÿ÷Ýwß;î¸c&ôNƒ%K–Üxã·ÜrËYgµlÙ² /¼pæúûŽw¼ã¦›nZ¹råYguÈ!‡\{íµår9‚Ý—öÝ×…¹sç®\¹òÑG}¹áË—/WJÝwß}ƒƒƒ—_~yµZížìíí=à€v~^)µvíÚÝœ……!I’uëÖM5-¦—Ø.æÏŸÿÉO~òÑG¡¥4ã“O>Ð5œvIïnêà ±3E·Ürˉ'žøž÷¼çž{îAp ۷oà^.¯vÆ¡‡º~ýúM¢öšÎþôÚ}ÐA=ðÀK–,ùô§?Á¯ýëþð‡yžÏ¤íxÝÁ°j|¬¹uËöÖx³ÖSw]ê0œgI–'#±FçÑJ©\)×¢ ¢)1F[‚)¡.1Hi;Ñle¹¨µ“B*ÂØÜ¹³ûëœs‡acMV\kn,î¤Eš-CBß-•Ë•j)OÚíf³Ç?ŒÂÑHk•g™’c´“%騨çc!ÀÈ:©V£0t3^lÛºåð5”{í¹!Ô÷½Ôs²,“Ò*­(¥Q )'ZÍ4Kã9³J) ÝÀMxš§¢RõK‘Ϙc-BwâN×÷[ä…’c-„bŒvl‡R £8£8 C×ñ€FÛ”˜C“TjdÃr$7ÚbŒ°Fk¥¤ÅQNc°ç‡ÝY)sÁÊUÚh†‰µZkeµ”:˜QеŽãJ|/p˜Cm·:išj­]×ÅvËu­ ‘ï÷öÔ%Vk™ U(c‘A–KÞjµÛq¢”bÌ¥Œ \×%„eb?AC¸R*cF\æ{žƒ1HòÌ !BvڱȥÖF)… ¡” Î1ÆCÃCÌ÷ïÁ0Ê IDAT -šI»“Äç1†È£•u[ÍÖæm[ðï&¸Ùn õ ”+å¡9³(cQ9ªÔ*Žçj3`FpžfY;IZ1FT¸Je` XäBQÍ\B(‚ÊJÀ…âA@°Ò:ΕI-!Á,w¡Ü!ÄbÒ‰Ó8ɱ†!õ5…Ñ0 #Ïõ(Fh­‚ÆŽh£Ó<«V«ýýý”ÒN§£Îò è†ðBêû 2ÝÉ[cÑÍÛ6 ™ˆ [ˆl§Ó4›e£1¡¥»®C)6Z¥IšÄ©T–Rf-À#„±FZbBkBBh-°@„s©e@B BSŠÂ3Fþ\'Œ±Öº(Š$MºŸz„Àh- 7RRŒ(&!`-# !TZkm$ç’sk ÀX“åY‘g‚‰ÃÖP,µÕV1æ8®Kf´ÎµîLÊ…”y¬q0AŒY©„¹6Ú.e·\§ã8QXò|ßhl7Ž—X«¥ s]­tžçÖZFi¥R©õT{ë5ìøøèÖ­[ó,³ÖD]×C#„!@;~àD¡çº@•e4‰¹²3µ9Ï=÷\!Ä»Þõ®N§Óݿ߰aÃÇ?þñ®õòÿñS·¢'&&V®\¹hÑ¢îvûP«ÕÎ:ë¬Gy¤»ƒ;µço¼pÄG8ŽórëgNßói§¦”zÿûߟ$É7ÞX¯×ÿîïþn†=OOÑ$êõúÛÞö¶îú²Ë.› ¯¦óôxòÉ'Ÿ|òÉ \xá…k׮ݹm—/Jæîðyú÷~å+_QJuÔQÝ0°N§sÝu×-]ºôþûïß%¯¦GOOÏÃ?\.—×®]{÷Ýwýë_ïþؽ‹ºæšk.½ôÒçž{îEW¥ëׯ/—ËZëã?þ³Ÿýì§?ýé©;^#L?æ?ýéOo}ë[§Š€jµ:“¶Óãïÿþï×­[w 'cn¿ýöùóç}ôÑ3Ôß3Ï>Á¥ÔÖ«=攃°à¹•*S“f˜ ZŠ‹¤È¸5 ŒBŒñ¬ÁY³†çþñTJ1Æ ÀŠH!„Th - žf±’0:‚À ¡À8E#;F”T}½}Z+—9¾ï1Ê”I[c|Ç)9®É9„Pi£¤l%IÁDHd™TŠPìû>0†¹#¹0ÀZŒ#˜R€çyårUjÑl5 Œq9 …à£À÷H`„1"/x^ð„‹TäiÑuyeY‘å— a‚2bB0ÂÖ¡æÏç·ÑÐ/5š£E^@Œ0&‚Ë<Ïã8n5Úã#£E’" ÆÙþÀ£®·bÎ Ê0¦¨“&žãx¾Ã|‡ú 2Ì‹‚[ùÔsÏ´ÓÎðÀ Åd¯ù öÞ{ïÙ{Ξ;.ç¼9>±~ós¶<7:¾5îÄI'ó‰|?me"Óy«ÈK¹ßù4Ô\«¶® UšgŠYž›6mňä0â8 Ãp°¿ \Ö®¿5-&ÆÆ;©ðð½Èë…̨ ´‘A)#Æêvܶ[6Z«gÍšÃ\f;¶Ùl„&&öˆÊb Z!t|gÁÞ{0C’´Sˆ¼Ñì¤iy±Öší¦›_'<ß÷˜C)!¡,Ë“´ðýÐa.AÔw!B ,€­VŒù”b„D`­‘\‚#ˆŘ k­1ª(””R(a­Ai­“$)D`ŒaŒ»ùf±ZImua-BØó‚¨R¢B”eY³ÝÚ±}TkÉ5Fgiše)BÀa C`ÖF !…ÖSAæ:¥@ß÷…yž!Œ0©DIiŒÆò,—Bk(e<ãŽë:Œy¾Ï(3Úhk)ÁQàÛMDŒ åryÎìÙ ß´/öÙgŸM³\JÅ9Gc¥P­VÇs<QF¼((û>ÓFH.!ȵV3µ9<òÈ_þò—CCC“qb7n<ðÀÿ¼%gm©TZ¾|ùܹs£(ꆡö÷÷w-´M›6c¾ño\pÁ¿ûÝï^nZ ¡ã8“ÁZSS×LßóÛßþö_þò—“‹˜;î¸cæ6çôMõ+îœJgz^í&7þâC¹ÿþû'Ï­ZµjòÇ]òj—cL¥RY´hÑøø¸µÖZ;Òù…/|a``à»ßýî‹¶½ùæ›ò“Ÿt¯kµÚÚµk/»ì²Ÿýìg3<9ÔíΘ¯¸âŠŸüä']tÑ-·Ü²hÑ¢Ïþóyžw·»vÙvz,^¼xåÊ•“±ywÞyçT›sz™|AÛ5kÖ¼¨Íù ¤}÷uá©§žªV«J©—%9Q-[¶¬{°yýúõÏ>ûìòåË»6çwÜñ¢KùI[hwfaª}~Ë-·üú׿žå>½Ävq饗öôôrÈ!G}ôƒ>x饗Îðq_z饾¾¾|ä#çœs΃>¸mÛ¶]Ò;½´ï>7^Š¢9sæœ~úé###+W®¬ÕjûØÇ>÷¹ÏvÚiÝÍ„W/BÈKÅP¼¦³?½vSJ—.]ºtéÒ_ýêW€{ï½wÅŠGqÄêÕ«wÙö ¼Þ ¥HsÝi¦£;Æe!fI–­_÷|Q$Ƙ´“‹\x®S©V†*CQ/J­•Æ—J%i´:çê¸@ÌŒŒÇqRN’NÜNâŽRÊsÜ( ëõzœd¹¹T©Pq‘ÇY^ªV*ÕjT®øA¡rtËÖ‰F‹Bм°–dE¡5ZûžC0¤Ì¥ÌSÆtâ”óTiÎy˜Á¤ê¹îÆ;Ξ{Ìïëí Ã0 ¼àÛ¶oß¼ukÜhiæ1Ú[­,FÒšLò<Éͦµ–²\)cBÊÕJÿ@­V“BBÂ0$'IDZ(¸’Z@(¢¤' ¢Øñ\Çõ(¥³^âNœ)ÆÄ£˜¸,£]@¬Ö&p™O=l€(x‘çq–·:m„‰ãzRÊv»¥µqæPF†j­´”EQ)ˆïúNÉqcŒ6#Ìó}ÃzµZÖŽŽì(ŠÜ¡Ä!Ì¥Ldyš¥<ã¦Ð*W"@€ EÔw‡j T*ð|‘¢È‹,Ë¢¨T«öDQÙè8n¥RE¦YÎ%G Íš½eóÖ,NvlÝf„*EÑØø¨±¶Ú[k%­V» 0ò|×jEñ &„ZK¹îÅXr1Ò˜ÐÖò<ß>:²~ÓÆ¹sæÌž={xhhxÞœ ìº>ÄH%U!‡ûûCÃÆG[H™s LèZ)®ònÔ¦†[NAŒ@ˆ…@Š1@Kmµö]GIî:Nàz-ˆŠ4k“PPE\EŽ­bl|tbbü¹uë9—•JÕ‚¨·ôëPÖi·[­f»Ý¬ÕËŽKûû—A‚ÆJÏgQ9 KaÊL)DĈ1r.ŒÒ¥rȃÐRB\Çu?ð¥ëz”2c¬Ña,Š‚sn¡„0F°Bœs¥¥ÖªÈó,Ï1˜PLh× JIÅ»ßJ©ëºŽçt½ ösc­†Ê $ç\K­´±F)å¸.F¨R*)!“4Rp^Xk0A~à#ºù‹´QÐ")xQJI,°ì¹®ÑZ ¡•²Öje­ÒB¬ëˆ1!H(` A9ŽËƒBß'„fiV¤é„Zk×õ!„cBJˆã¸Œ9RJkÆÄs}Œ0°È…µCl Ês9>ÚŒÛJ!€Z.´Æ”ÍÈæÄ×ëõåË—¿ÿýïAœR÷âàƒ¾ûî»›Íf×±ÐÝ0¦”Nº›>ñ‰O|ûÛß~ðÁ¥”k×®ýÒ—¾ôÌ3ÏÌðã{ðÁÿæ7¿é^?ÿüó ,˜êÈš¦ç¡¡¡©QR£££3ÿâOOÑ$¦ÆµÎW»Éÿƒ¨ÕjSÓ~´Z-)åΞy5“et†7nœ;wn³Ù ‚BØ5n»õ N=õÔnô|w‚‚ (•J]—ÚÔ̽Fã‚ .¸îºë9ä»îºk7¥îpÝu×Í™3çÔSOýÊW¾²~ýú¿ýÛ¿]µjÕ¤<}Ûi€êïï{QiŸ^&»mÇÇÇ'Ÿz½;Òþªè‚1æ¤P:âˆ#ºÐnÅ 7¾ï}ïcŒ !B®ëîÜdÒä~ų0‰0 ï¼óÎ,ËŽ9æ˜Iky—;)!€K.¹ä›ßüf7óêSO=5“—¦izÅWt¯/¾øâçž{î;ßùÎÉ'Ÿ¼Kz§—öÝçÆKQt饗öööî³Ï>]?ð]wÝõóŸÿ|íÚµ·ÝvÛ yõRh4/å!|MgzíNÓt||¼kpn½õÖ+VtÏ3ï²íx½aÇöíz#['6<»>îd•r9 =ÇCiÜìÄ Ãnà‘繌 ±Æ«µµ`d¬1ÖŠn«…WIš*cÒ,ít:i–j­ F,ô«¶žäE+ÍÆ: o ÆT’%iÖlw(¥ÚÀ¥BÏ÷!€8Ž=—1ÆYž-)#2åEQœcš Ò¬ÈóL*N(‚äy† n¶š7mœ›xó›˜7wûîcŒéíëw\×B FÜ"„†ci5á$1‚!¢5Ró¬°Š‚+¡¤VÖ˜BÚèrTê«÷ö`„´ÒyžI-’¤Ùh;F‚‰PÅ3A©”VY ´1ÔÁˆai•0«Z˜L@X¥ãNÜŽc!•´š@¨ ÏT‘!¶V d¨ãä + ¶D€zQ9ôÃ`¢¥bŒYkÃ0¬”«ý½½#a«ÕtÆ(3JuÒ¢Óéh¡ ×"“ 1Ƙ‹1Ä„j¸àJJ¡à<ËÓ‚óN»3:6F(5ÖU¾Ûé$f+Ë2Êœj­§§Zõ\Ïóýzoä2&ŒÔJ(éy^"DÐ%¤lÅ×uæåRµZ…ÆŽŽŒÄyê‡~¹ZJ=ñô“Ï>ÿÜðÐð^{-˜=k–ã ¼(€žã2ìGŽÐ¹¦+i€Væ„ÅÀ!¥@Z #ˆb $À ¹®ç¡ž¡Š™5PIm´ȶ‹TaíjI"s€ tˆ¡0U|{cÔ6TÁ“Fk¼Õlïe®K‰D¨´WðüáO}`ÅŠ+V¬ØsÏ=<òÈo}ë[7ß|ó›ßüæ~|Ÿzê©Ã?¼{=yúe&=·Ûí(Š&Ÿ,•J/Xdt÷!ºð<ïeQÔÅÎnŸ]òj7¹ñY–Mžƒír’Rºs±–WP[eݺuÝ”3Ý3`ûí·_×Pé:IÂ0üñ<5\öúë¯ß¸qã¼yóvîªkGÍ<#ËôR÷ÊÆÜu§œ{î¹çž{®çyyžï³Ï>Žã<ýôÓ3i; Œ1Ífsª„OÍÅ2½LcÆÇǧ®Ñ_ÇåKûÿ¢.,_¾Üsæ™gNúñ|ß_¶lÙš5kŽ<òÈé£+_ñ,tá8Îm·ÝV¯×—,Y2Õfx¹{ûí·Ÿ{î¹ïxÇ;fhsNE³Ù|üñÇ9䮫y—±µÓHûnrcŠ–,YòŸÿùŸ“ÇkÖ¬±Ö.]ºô¶Ûn{¹¼züñ}èC®ëE±³[þµ›ýéµ{ãÆSÍÝ<Ï•R“_ÎéÛ¾×Ö?û¼xb´µþ¹ yžÎ=kÖœDT«36>¾Z ¢zµÚTK4 éLÆq'nu~èCŠÝ €q)ÛÍtl¼¹qëæ0‚ÈéÄí$M„”ÖDI…=½õNÎ;…h&YÌy+NÓuWjÀ„0ÇáBæ<“ŠcL,0Úh„a^ä[¶mé$ñÆÍ=×é¯×¥âEÎ…”˜²V;î´;JÊ(Šª ®Œétífœ&â1ÊhVd©@ I‹ÜžÇ\ì°$Ë&Ú­ÁY³çÛGG6oݲyëÖç×??gÖì=÷œÓnŽJ.|7rq4D Õ*%Íe–æJ+žÇÄu€Q×qÐe¡ƒ&­¦4šº.¥´‡:uŠ\H!„ŽÃ Ç #µ [¸MÁDÒR…*€PgY{||ä.¥LiÞl5,°nžK!³4KÓ¤Ñl*%­5”,%Øó€ÂóÝ¼à„²J­B’f…R!l-Ĉø~x>s« c¬R.—¢ˆ9!X*Ùh4—i’jÅ„”RBÁ!Ä9—RvíF%µÖ @K)íFÄ ŒBÌaÌu´ÖB c,&˜Lÿ'ФÍ)¥*²‚Bˆ­B(©Œ5ʘ¼Èó<œK)ýôÓÝuqÐA]yå•gœqÆ=÷Üó¢]½óïìŠÄ _=©{¹cžŠîÊþ3ŸùL–e¿øÅ/^VÛÅ3Ï<³xñ⩞«™Ëäc=6UÂ_Eiß}]¨V«Ç{ìØØØÌ“—bŒ:ê¨k¯½v2–ÞqœF£±|ùò5kÖ<ðÀ“öÕ ,ä™ÏÂKŠrÓM7-\¸ðï|ç Òÿ¼\‰ÝgŸ}^ட90ÆóæÍëhÙ%½ÓKûîpczŠ:ÎÀÀÀäݾ¾>a7¹ÂËåÕ póÍ7ŸtÒI'žxâ¿üË¿¼àÖk:ûÓk÷ƒ>ØÍÔåÀ^{íEÙ¹lì‹¶}¯7tÚÍæX6:ÒŠÛmÏ÷zëõó÷ÄLoÙ†’¤•%²\zûª5¯B$6¹´@k+Ò"B:'³„¤‘VcÇÈöVܲÀdy)ËóF«µcd¤Z+CŒÆ~Öê=µN•GÉêùÈA·è‚!\©VÔͼH‹TI ÂÀ¡Sq·Ö'FcˆÊ•JO½® ”F © ‚4p !ccãýõ>ÁèØX’fÕZµ·o°”‘r¥444èy®ã2l^¤yÎyÞÉ;Ìhâû ­´…€Pj!ä<Ãi%%—ÀØ,I?¼“$I–e‚s Òõ1ÆÖK(#„¼ÀzA ¸ ‚P­ÖÆJ©qc4’K®¡vB·\/û~˜æy¡9•Ô.%4Ë3¡xRÄÀZ) cŒ…#,µJ’X E)s™ƒ,°Æfiž%iÜi­0ÂVžçJ!8»cŒ‚Xd1D„:”1L©¶Sl¥¶Ð@ ¨C Û4O YX ¬Ö#¥’ç»bˆ°ã¹˜PBH9Šæïµ ^©ž¯„ܱ}ëO>1Ö+” ’‡J­0†BJ ȳ8ÑyQp%«åŠ4š+'¥m[Ä\I®Tš7Ûqgll¼·Œ("ßí­÷Ôz*âÄ驌’™4Ë¥–RjcÁSJ‰ãPŸ¸Ìsš¹c— jQáú€Qêº4ôý,‹!´^X´1EÁµ…æ>ò)A„áJ¥L(Bic¬…9ÏIÊ ÆJ*XF©R²(r)8Á8 ¼ dAÄ*•ÐX‚i+Ë8çVk †1æ…AøQÇq§ã¹.A Ây΢µTRYc€µRH­u×àh­­µRJ!d·”ˆR˜‹!ä0‚ „©ãF¤B©D! „ BcLžeJ)JÆD !„°ÿì%#„ † ^´[¦Ýi;žëº.ÆÂãBØ (­°ˆ€1¡OYË×ÖJ¥ )0F„RcmwÌX„ Ä h€1ŒÁŸã{M—Fk­B‘9„€R"¥è>`ŒVJEAi.”L“ÄXíºÁØuÝ0 ÓÝ,ÍZ‚h·>Úqh¸ÂH¬8Ùyi>ÕËQE7±ÇùçŸÏ=÷\}õÕçŸþÈÈÈÞ{ïýáøW¿úU7Rñ‰'ž8î¸ãþõ_ÿuÓ¦MG}ôç?ÿù©}.]ºôÐCýÙÏ~¶~ýú9sæ{챿ÿýï_`b=þøãŸùÌgN>ùä‡zÈó§?ýéyö_Ó÷|ÕUWÝ}÷ÝßøÆ7.¹ä’7¿ùÍ_üâ§¶}ôÑGßüæ7¿÷½ï-Z´èµ×§§hzLÏ«™pã•¡§§§ë×u]×÷ý®C ÝnwÓuÇüãÛo¿ýûßÿþ÷¾÷½¾¾¾‹/¾xÛ¶mSëмbüèG?:ýôÓ¯ºêªSN9eÞ¼y_ÿú×׬YÓµÓ4}A¿®Iùûßÿ~²í½÷ÞÛ ®>ꨣ¾úÕ¯Þwß}=öØk½V˜fÌ€¡¡¡~ðƒ÷ß¿Öú#ùÈ—¿üåo}ë[“Gާo;=~ðƒ\ýõŸûÜçn¸á†eË–tÒI3—É‹.ºè®»îºâŠ+®½öÚî¹»WKÚw_†‡‡¯¹æšG}tæ6ç’%KjµÚÝwß=ù ç|íÚµG}ô¾ð…ñññéwf2 /5ª+¯¼ò˜cŽ9çœs:è É ¯_ýêW###»”Ø[o½uÕªU=öXš¦‹/¾à‚ ÆÇÇg Þíðø@÷;püñÇÏ›7¯›»x—ôîŽö±=óÌ37ÜpÃk:ûÓk÷üãSO=õª«®:ãŒ3c—_~y§Ó™L‡;}Û7ðzƒÃ˜”­¸Ýf.íèë¯Ít\h7FNŒ7{ÊÕZ½b¯hæ¹È|æ–*62Ie¶²bL*^ðœKî8Ìc¡•Jmß¾ýɧžÜwáÞÆZks0 ý0ÐÆ´Z-×u}?ÀQêB‹¼k•°TjŽO´âÄj‰ ò=·V-;CŒ7š\ÊBQ×󤲌±r¥b„ Khâ,m·:‚ L0üùuë†þð‡ƒ:ˆ1ha­Öªš0ô…(¶oÛÁ‹H©¤´fÄBëx ±…Àw¼(Š,\cL–¤yÆqœ&‰ÖÚhÝê´’ò‘y"Ðñãǯ»îºûæD…~ë·~ëŒÄW¾ò•_ú¥_ºßqßýîw?á Oxýë_?Û= Îe)ËÙ÷üÉO~òÿøo¸á†n¸Áóæ7¿ùw÷wïÛ¹ùæ›_þò—¿üå/?yòäÞð†›nºéÌÖ³÷èìœÝVçbÇÞð†k®¹æ¿’sî½wþá™ Ãmç³ów÷w¯zÕ«®¿þúW¼âó˜ÕUW]õ=å£~7Ž=úüç?ÿÝï~÷éÓ§à‹_ü♪÷È¡C‡æR½ó¼µøÃg.ÇÃÊÙÏ™sþº×½nžP§”zãßøÚ×¾öûÒß÷¿ÿýOyÊSÞò–·¼õ­oÇo}ë[_ùÊWžã˜¼õÖ[_úÒ—^ýõ/yÉK¾ô¥/ýáþáŸþ韞c.ôÙ÷ü™ óÄÚO}êS÷ýðŸøÄ³žõ¬Ç<æ1óJ?Ó¨›‡—çÚEgøéŸþéùš½³#„xÇ;ÞqfÑøç>÷¹—¼ä%ç>=æò]u]õ«_½æšk¾=Ê÷ß<ÏÞ£W¿úÕý~ÿÆoœk ¯­­]}õÕ÷u541ÆŸû¹Ÿ»ùæ›ßùÎw2Æ`ccãyÏ{ÞÃÝß³Ïî»îºë…/|áÛÞö¶ùû ­­­¾ð…gÖ]Ÿ½í?j DmtwaÿÁ}Ý^‡2ÂÖ_6º*ŠbØ[d=Ðà”Îl" Á¸äi™Œ&ãˆÈ$E†”"cD&"F y^ ¡'NžÒF?ã™Ï”\)’D «Ú&Ib­÷! á`¸8è{ÑæéíÍ­,IÒ"¯ÛÖ[Ûï\ˆÆ:ŒÁj­½¾õascýôúÆÑ“§ò¢«ñbDâ 4†°µ½]ÎfmÛ&IÖ¶êÄ©ãÃápuu•1FZ«8§ç:hTkÛvs3[^XH½¯™é²U­®›fV"&Ep.ï™LÑG}`„ö:=Jˆµ†R’çi€ ´n´n[ÝTÚXk¬A‚Iš¥IæY ó4a”0B<%Zk­ÁHÊ9ã¬ÈÒh­®ëàc’¦IžA§£ê†x댡N0JI"%p!T£«²Q­2ÚÕ¦¢HRȤÓíä…Q†¡ŒpFeˆÑ(eŒ6ÖÆh¼sA9ÎDšf‰ÓHˆóÁ9‡ !Æi*%ã)eŒq!bc´7®Ÿ¨µe’gEÞë÷ûƒþ`aaiiyy¸ ÊH €§OŸ®ë†TÈA+›úôævˆ¾Ó)’$a”9ï8 2)DšLÇã¶m•R #„R:OŸZ?°{o&;ÛÛåé|;Ï‹ý{VöíÛsáEO|x{{û¿Óg9gÎùE]$¥üÆ7¾ñ㺿óhÉž={îºë®ï˜“yö19/UJ½èE/ºù曓$9÷aö=ÿ0Î…‡r4Y–íß¿?ÏócÇŽÝWê‡×Ø£N§sÞyçÕu}äÈ‘ïUøé÷ûçŸ~]ׇ¾oõˇ¯¿8»¥”—^z)Üyç÷;¥l»Ã/ç¸*{eeeþ¦øß&ÿr×÷¬Ÿ zƒK.½ôÀ¡ýç]xh÷êRš3­ëoÞ}wÊÓŒ¥¾ñí¨Ñcå[OJ.c€²jÕeìææxssTW-!,"]]Ý»ºº§®ëÉdôK¿ôü+æg{ƒ>R6ÇÓÿÝ­ü¿6ÆìÚµ²wÏîå…'xòè½Ý"ï…Ñz}}msm-8»0è­,-fiBò,mêº,˦UÞ‡èœWÚ@Â)6ª6ÚjmeY^tŠbaaá‚óÏ¿à‚ WV–ªmNœ8®UãŒÝÚÜÜØÚWÕfÙÌÚF[ˆ@‰A¥qÁSÁ“4RDkŒ÷~0ôûýù;¦F7€¡œ‹$"©Úf2›ÎQmÛ¦fŒo­VƒàŒP€èj*ˆ1ISmLÛêD&ŒñˆˆœRmMp΂' ±©«È"B(!ŒŠ€ÑG眷!†H(J)))#Þº" ƒÖš"I’DŒóÀ¹\&i"‰„jkcŒŒ !%%Pªi˺¦B,--ïÚµ;M³å¥åG\réþ=«Ý<ÇîþÆ7?÷¹Ï?yÜE ÌêjmýôæhÛy/„‚ÆZ Øôò¼ÈóŒ3®µ>}ê”Ó6’H.ò,/§Ór<[ì,¬.íîu Ʊ°ºkéÐÕÝ»–:Ì÷=÷|þ _˜–-PÑwzmûĩֆn¯Ç8h×h­œ ”2­už`”’:oÿçÌ󴪪µÓë§N®¶&++{zÝa–eƒaw÷ž…Ý=÷ÝÜÜjšÖÙ€HVºÝN–d‹ ‹ËK˼cŒÞZ_?vìØé“'«ª"„ìZÙsÞ…îÞµ:«Ê{î¹÷øñm£31"¥|a¸tþùçïß{àÔ‰“Gî¹·mš$I³$eœ­Œm­5Özg­RF)å‚ÄùÚHcMŒ¡U1Úyëœ5Æ$‰$ˆÀ—i’w ÆX£Õx<O&uÛʃA–¦ÎXÕ¶Áù<Ï¥Ñùy9I"¶­rÖÄÑXݶmšçY–ED­±–sé!†„”yž¦©ˆ¼÷ÖÚyÕ$Ä;§išÆZ‹ˆ”1.e$0&R ÆÒRH)$¥lîßz„I’â<Ñ7ˆBH’,I’ÿô9"‘RöºÝÅ…a¯ß%„ÎD]µ[ëÛm«ûÝ~§èìÙ³û¢‹/¸øâ z"D[–3ö=Ý7CßMÕÀ9wvÁƒ£G=zôaŠ,eÏ'Nœ8qâ|Gñ‰“'O~ÇÒáçÒ£m«‡Õ?(ʲœWYü¾£”úò—¿ü nnnþ ÜÏrÎÖÚûÊ)û §Nºß2Âs“BˆG<â_ùÊW”RI’üʯüÊ?þã?~OïYÎ>ÚçÂC¹ š¦iþgJX?hk<`ʲ|ø2Þ'“É| Å[pvk­¿[¤ýÛîð£CUW”Á®Ý‹+Ë» ]ʰm«Y%@(“Bå´cŽ•ªÇc¬H !¡Øô²¢Ó´ªiõÚÚF]U4"ó+^ˆÄZ7O>úÑ=ò‘zdþ.¤ ʲDÄn·»²´¼²´ÔÉÒ¶œé¶5œù4íöz½~Ÿ3~äÞÃ[£±µ6\pv`ßÞVã¼óÁX“$ë ‹$+òN «¶M¶ÇãIŒ"xïµÚ˜ÉlöwÞ±¹¹|Þ¡ƒ»÷ì–’;rdbFœ“DrZÑk!Ê4áR„¥`J›I9 Æ¡Œ)—2‘Û£‘õV·j†3D2Rg¶hDʈTt²n"RÆxš&Á9!¸nÛªœiÕ@ðàƒàTµå¢wNp|ä¤Ûë:ë˪ÖJ·Á‡‘@Œ@(œ"bCðÖ0„CDd„P „É=ÄmðªÑZ«ã\,”` Á#eb€ˆ„pÎ(eBHçœÒ­ ±Î‡¸p”Ñ,ëd"ÆJÁY"R.X«ÚFµ!ÄnÑ„ê¢kµ>~ìgìÑ—=š2zjãô]_ÿDHeâ½GB"0àR¤m£œóIšP$€„ •2Þ‡4MÓ¢ÀH˜PÎÕ“ÙÆæÉoæ‡îºà¼ûöí úAfÙB’&«Zi‡ñ¸”œœå¹Ì¼uÖ{Š„$½³ RBbŒ Dˆóì_@5­JÁ ÞB8ã1¸ † •–\Î0œsF­w)¡dk{\·_=rä„q6›ÕukÕÆRÆÚFO'³ÍÍó6Ò$ûË—\´wÏÞn·«T­Õt:ÛFå¬jÛ¶mÛ²¬ë¶5ÖxïCðÁ;.yJ$ã0Æ"B ÞZc}Á{cLDÊ(œ9‹H½÷„‘Hk­QÚh“p ˆ1Fã¬o£àœKu«Œ1!„$M)!Þû!„Hãœ3D#¥Ä:gk‚ňˆ@ Á[kœu–3Á¹@‚„P ècŒ„R$”0š¦é¼¦K„8¯Îb¬™Kì ‘`ˆsâJç˜Ršˆ$I²,I£Qžg¹”Iš$uUk­Ú¶í¬“wþ¡Ç>î]|ñ!‚œ³lçæ¾Ã?âdYöoÿöo‡>zôè<óuVvØa‡vøïxËÓ¶+»—Ï?tޮݫÁEeuÕVqZ§eÊÓNgkc]—UN²”§6úJÕ)Me.FJYlœ ÑZOäiÞf¦©TÝ”Z[ë eL?qòŸoûLo0Ø»ÿ€q~mcûî»ï术,¯,/.v‹"\D¿ÐësN1 œ½^§?om®oms‚R°$‘!ĦmÛFYë²$ëuzÃ^¸´¼,sY6SyBÂ8+«¦ CŒ!†­í-cÌ©S'Fã­ÇÆG_|á…2Ûk§%¥ ­µa1ïÐ;c4Í —†œ±NR*ËdZq|€6 (WNMg³Étª­%ŒŠ4£”„À9ϲT Ñ-rˆANxâõΤ"Í ‚ eBÊ2F’v»Ö:O93¦i1†"•‚qž!FïÛYm¬Â½u1F¤$øy&RzïCŒ’‰$M™àU]kçb ,„s*’Dr!8§”SJç^„謵ƅX!„² ¥ZÕVu–æ D0ÎF‡.ø²i¼ 嬊Î66s‘DçOŸ<É[YÙE( Æ7emTØ`B„ˆÀ)L@ˆÊmŒóž1bä\"‚qÖ&IÒ$IEš Emwf{´uzc#Mxkôx6;|ìøpÐO³´¬ÕÂâr§ÓÍrH!$£~¾îQʉœsŒ±R•H…öVGç)ð<é//Ê á*º`5mI2%B0Õ¶1)„àÒÙ཯« |¤@t£eJ©jVÖUƒHÒ$§ŒdM«•Þ1Zëb¨$˜¦m F­ëÅ…þÁýõˆG8°7Ë¥1ZÕÍööÆÚÚé­­Ñt:L'£íÉx2.˪U­±¶Û-Vv­0Aœsˆ(¥ðÞµMmT[Îf³²l´²Öß"žkøÌ…rνuViDd”zDð~¾y^cc‘Æh’&Þûñ[EM¡”ÀàsÁy¢wNQdRrdCðΜrDŠçøˆ §œ sN) >„(RBˆÁh£ŒNŒ‹ˆ‰Þ…V©àX¬¬, {ªõ\0JáGÈç¼çž{^øÂî¨Ïï°Ãý˜L&—\rÉã÷¸ápxúôéø‡xpr©;ì°Ã;$”rA¥bÚ”ÕÂhÁhÓëõ2:ÚcÄ„'¡h @ Œ0Ê)£< !³4§„œ6„2B¥<‚µ^5ÆÌê™2™5ÚlŒ6'³T®§i¢I‹þÒJÞéö²4íw Fâ¤,•÷I@Jò,›».Îi&0/’@ÀCdž.¤)Kòªjœ…H0@´ÖRŒŒ1Á9"E ½s.ø033g|]5ŒÒà=FàœcšÇ‘P¤H ƹ÷®mÛV«BŒ1ËÒ<Ëç Ï yàÀ¾‹.>´²k‘’HÚÖ--ö†››[[[[§ÖN$Ö­”÷,Í’•]Ë]|Q–§ÖÚçÔ]•³º,··¶×76`Äè£2š‘"` ßR¾¥ÝNwqaqaØ'ÊjÖ6•ÖZ©i9«¦³)c„ðÁZgZÕL«r2­B€®Ì‘!Ÿs4½÷½ïÝù1Ûa‡oçë_ÿú׿þõ;ì°Ã;üÀYXX8xèÀ`Ø£4¦™,\ÑZ£ŒeÖQ&a$¨¬A×vS—äyo8ì¦]œñ>ÔuûÍo~³iô°·¸0\TJ.»Y·iÔhÄVëF)c ‰ÑY´>¦Y‡rI©VÚ:9OiU·d{L(&¹D Œq™¤y„1ÍÒ,O˪rιàÆÓñ]_ûÚ®•Å¢H»Ýbמ]ƒAoÏÞÕÞ`©?œ8yjcc³lêà d‚YÊ ‹ˆÑk-`”BÀ€ÚÖJ™äInsO€Õm«ŒHDëRJ+E™9g´“¥EšR„ºª '¼A GãQ°1KSÆg\ ¼WF'RJ¼wmPZ:­Û¶,ÍdF¬C)ó¼3èºÝ~]·F›Ù´4Ör! ¥È¥L³\[c£ORÙ+:Ñ]d…b "±ÆFóNÇ3¥”ª­´M9DI%ÍhÀPi„`¼7> ç‚sÎ '@!dÆ8a·_ä¹”riyie÷®n¿×´õ±cÇ0Ä裃H%çBÁmô.xc¬µÎX ¡qÂcuÖy£T"h´*<ëdI¾+)ò¦ÑH( 2îŒ-kËÙM××·²$t‹…AQ¤‡–º'OlŸ:=Ú°£I=S“¦­ËjV7¥£Çû.ºøüA'eU ![êÍ‘µd’Ä)§ŒuÒ¼­Úµél<™©Ö´­^YÞÕÉ;RJÁ…äI§è.-.¦21­žÍÊIYN«f¸0Ü¿/缳щ­ªËjfŒ6¶¥zJ×£ñæÝ÷|ýС}ý^WJ# MXÁ;ߺdŒ@­Õ¬œ;>Ù¸{ckkk{¼Utr„À(×m3Lg³‰Ö­÷6º}ðˆ¤R)åœ5H "çœ"™—' 1z|0ÁÑsB€’¼1zîë eœrÎK¸HÒLH‚QmÅ)aŒ!€³6ø@ ‰xç­µZk£”7·J›¦ â\r9ÌZDÂØ\¢˜1Æò<Ÿ'ç\Œq.PD’÷:´M3£$M!ØÉóFµ€1o­¶ÆSJƒ¶z{²}âä ÂQ-§Õ”‹Ÿó‡ÆØ¾}û¤”'Nœ¸ŸÈáþýû½÷ßMéá;îÿsÈó|ß¾}ß«\ç;ì°Ã?pƒ!¥”sÆ8E‚Þz.E§×©[³±¾±ƒa!ÃB•Z:¶J•º¡‘`ˆFií,•,ï÷8•ÖåÆm¥8–rGüLW¾ö•QÎhJÉd:I­Û»oÿêî=Ãn—Â)KeÒRZ*“ý‡©ˆm«ÖÖ×;E±{Ïîµõ¶n<8B`V—'OŸò.k•1UUËãÇd"Ó4_¢K½Þpi©+$ϲ„ÞCœw³²ÜØÚÚšŒ«ºD€¡¬ªN‘w:ã;î¼k6+/ºàü^§[•ÕdÜe8çy–åiFŒ!¦ÕUUQÀNÞ!Œ©¦O§J)!Äþýî;ÐïÅyE_ÐÆŽ§³µÍ-ë¬õ~ZÎFãq]×™L»œ*(˜c2I¤ÚéCÊ}BDÈ ÆXô1†#øà#ÞX õèœuJ—‚2 4Ks"¥wnÎMóÜI²,Q*Í3BŒ!"Æç‰ÖZk­Z-g€ÎÔÁÍ•Jcô!8g½ s'€2ª´iž—èB!Œr È%&1»i;Ù IDATZï‚ÎXÊ cl6+à®ÅåÁÂpuïÞÕÕ=»v¯ôû½$M)ÅA¿_•寯Æt:‰“,+ú= àœ±Î…¼5mµ¦Z)¥´wNÕM‘gTrF³ˆ”&‘P&HÕ´ÓÉÔQšficÜÝGŽ­o®wryÁÁ}]ph0\Ú»j&ãf2.··Fu]¯¯­mn¬Æ[u[Ê@bcw¾õ¦vÁ­½ª´VN±VpJV½QkS—u=«šZMÆSÔÚ)ã;–EÀN‘pž¦ ‰±i gtqq(%#d* ýº]˜•“ª)™¥ÊªÓ§[ÝÈ„o·nÿò탅~wØÙ¿o¯V†3N(""OÄpi!/Š¢›#%Æ:ïœZs6lnLªYK(ñÞjÛ¶m#wZëVk£­w‘¤1 ¸C ‘ g ­µ‘F"øàƒsÆz`„P´Î8F …8¯Y(ƒN7kêVk‚§‘QŒ‘^›–S2èõ ú¦i§Ó‰j¥,KSÎyŒ±®km c´×ë¥yžå9e,"dYΫë*D1"AJ)gß*Â9g”{æ«O€œÿ-„H²d<•eY«<ËB Blšjk{Û:ûŸUI¡n¿µI9RŽ<¡œã(ÆÁBÿ¿|ÎË/¿üºë®{Ík^óÿñÿýwØ‹.º(MÓ‡OÀðÿ1®¾úê·½ímEQÀ³Ÿýì¿ýÛ¿½ïÖ¿üË¿œL&W]uÕ÷ÝÎg?îÃÁòòòë^÷ºŸø‰Ÿ(Ëò–[n¹ùæ›ç…wç<ó™Ï|ÙË^vèСõõõ[n¹å]ïz×}·ž½íÃ!äÇ~ìÇžøÄ'>þñOÓôÚk¯½¯vîSŸúÔ«¯¾úQzT¯×;vìØ-·Üò¾÷½ïÌY=õ©OýÍßüÍûîíÃþðûÞ÷¾qW\qÅG?úÑ /¼ðî»ïþ‘&—^zék_ûÚÍÍÍk¯½öû8êôÕÀ{†W¿úÕ~ô£ßð†7Ü~ûíçrÜßû½ß{ž1ÆõõõÛo¿ý¯þ꯾_¯Ê<:KÛw½ë]ƒÁà~ßÏ{Þó±}ì{²ÕwãéOúµ×^{É%—TUõ…/|áÿüŸÿsŽÅxJ/¿üòW¾ò•—^ziUUŸùÌgÞð†7ŒÇãs™û@)ýßøç>÷¹»ví:uêÔ{ßûÞs/ ½ÃÿchešZ ™Zk8d”P漫«™÷^Ouãfë°µµžñ´6v´µÅå”ZcE"³¥³Á;4“0(RÚKl 5´ëô2‘·º×éïZYt‹nÁ(a^ó Áºi×¶·‹<ë/ï^jÍúÖÖÉ“'c’ H8ëéâÂ"œÚ8ÝëõYÂòNÊç‚L&£ýlF…”uœcÞïsƈ„²¢ÛwÞ7McŒÚnnϪR9zúðá“_xáÞ=«m«›²QU]”\F hp‘QÊPp™¹÷±©Û€F ëöò^7'„„Ò¦QGŽç'O®Û6ƒÅ~×{O( 1XgÕ1™ËÕΪjj®1M$¥¬mZ­-cÜhÓ¶Jk)‚³‚œg:§›†‚!"$Osçý¤Q~{d­÷H’¢ œQ$>øÉtñd·×[__ŸN&Y–E_çÑçlS¢„`­u*!$ )å’ €ˆ>ÂH’¤ÞFN¸nuÀ˜ˆ„0Ò4mVÛX×µm5n0\Ø'8M¸Èe1(ò"SMSYžå øÀ(”8Õúè]ô1FÀ(92!cŒ€ÌG­L[»s˜DAx”•u=žN¹”à¿%K%:I딣X#”‰Œ¶ÎM¿úÍikv¯,ïÙ½zhyÂÇÛ££w¾ûß8zŒÆ¢È ÜëAäMãµqÖ£–Mfýá°j”÷˜%…Ï":lI- ¤®Um€é”Ñ^ž¥‰è;L®jµ¶ åÐ2㩳Ѵ™6 QF‚:ør\ÕJálvüÔ©{c\vŠN@/£"¡”Fºgÿž4Ëœ ³i[ÍìtZé ½ò€6‚÷΢×Bô&F‡ù¼¤'!œqÑsÊcŒˆˆ AB‰ Œ"ÑÚ‘Q”ÄÐ{ŠÀ(#ÈbpÎZk ¥>I( àŒ±#ï¼o‚7‚ FgÓr6 ¢œ0¢­Vm0PN‘R`)¡œ¥yF(mÚVCmêb̲¼èt‹<BïCÛ4ÆXðÖ3Æ8eà­5[ãyÝA+‘$Rp1ª¶©µŽ½ US·­êözB’¶­O<á½Ç”â¡CÿËç\]]}Îsžóö·¿ýâs^ýõ—\rÉü±i‡³C)}ë[ßú¾÷½ïºë®ÓZ{eÑOúÓßMæ¡Øùû}GJùéOºßï¿éMo:xðàŸýÙŸ-,,üÑýÑ·êãÿø§>õ©o¼ñ²Ë.{ûÛß¾¼¼|à 7œKÛ‡ápø¯ÿú¯J©Ñh´gÏžW¼â÷õ:®ºêª .¸àóŸÿüh4zÜãwË-·<ñ‰O<ãgô¡3ÞÂ÷·ÒéÏ}îs¯¼òJÎù›Þô¦Ã‡_FÝC¹úg±gxÚÓžvýõ×3ÆÞûÞ÷ž£Ïùä'?ùŠ+®ø›¿ùD<ÿüó_ô¢]{íµ?ù“?©µ~XçàCi뽿oAÎóÎ;ïòË/¿é¦›¾'[}7^ö²—ýÉŸüÉ'?ùÉw¾óÝn÷ùÏþ¿ÿû¿ÿùŸÿùÃÚßÇ?þñŸýìg¿ô¥/ÝtÓM‹‹‹¯xÅ+®¸âŠ'?ùÉóé|ö¹?Wø¼ç=ïøÀ'?ùÉ}ûö=ãÏØñ9di«vÊ+ˆ‡1Rm-@dŒxk›Ià ïwú ¥jŒVY×Zë]¦IQäTðÀ‘ï-"€˜e"‘²›ñL€¤žÆÈÀctÎGJ‘²40$!ÏÒ¥¥Åª¬î¾çðh6Ëó‚‰Dʤªfλ^7ç‚§EžHždY]Í&Õ 9ëw{ý…!Ôg½Îò¤?(ÒL„è¦Ór:m¶¦³‰‘ é#$YÆŠ€Œ%„`c‚Òm[7Û£ºjœ±°w×.FE«ÌÖöx<+ÑküÌg>sî˜i­ÿ÷ÿÍo~sY–Øöác6›=ñ‰Oüò—¿ü’—¼äÆo¼ßÖßùß¹¯ùž÷¼çÅ/~ñ«^õªûšôšk®y¸OòG„+¯¼ò–[nù…_ø…+¯¼òۯŃuåêŸ}ÄÎI’äíoû[Þò–—¾ô¥ßSgÇãñ¯þê¯Îÿ~ÎsžóÁ~ðgög?øÁ>¬sð¡´}ñ‹_|ß/à‡ÿò/ÿrî¶ún\|ñÅo|ãßõ®wýú¯ÿúü“׿þõKKKw¯¹æD|Ö³ž5ÿòh4zûÛßþøÇ?þ _øÂÎý§?ýé/xÁ ~ù—ù–[nÙ™¹;”U‘ëež ¥Æª ¥ìõÉl\ÖU ¦<§H aÓé"p!­µÚX™U7u]+ã!Ò©‹!ðчèCðÆ(o úÀDë1@U’õµSª­µvBð<“R c '×N¾çžYUBŒo5Ê&BQyŒ±j겪¥âtÌOó<‘ÉXMœQ@ ͳް'j¶­ñŽ0ÒôqXÕŠPŠÄ§YN½sÚz`#L›ö艓Œñ…þpiq ŸÖõ¬i]œøbÁù\à„2&8/²¬ÛíhmÚ¶™LÆËËýnÁŠN¶¸¸€ÎûnÑaŒ¶u=«ªHŒ³BŠáÂB’ʹ,-ÚíõÐ;AI œ.DD@¤œ %gÜ9'…0Z5#q¾3FBIp!¸àç'I(Íòœ a­%Hz!¤È‹¹f©6ó"G­5"fYšHY–%A!"ET œ·b@€y2m$>D$„QJ Áyï"GäBp)´6Óª<½¹Þ˜jTnoŽ×vï^îwúÍTUªÖÎÁn¿wñ#.ݽºçĉc­U³ºlu«­Ê»9— ¹”]Á3_´U«K×(Å8çB¢5­ñÚzÃ@0A–··F¦5ÖB ¾iuÓ®«¦!åò®cl–åÛÛ£YÝêà}€“4íøèCˆ“4‰ÛÛ#‚tîAˆ@IVä„Sš`ëº ,Ê"e „Y=«ªY£êcÇRçat{´=›M뺪ë*IRÈa^¡Ôy×*uìØ±º¬Ž=¾±¹-óL$ÁKN{‚`lªÆ*¿µ=J±¼¼”¥J—gùÂâ Ë¥±íæhÝê6‹1rÁy"ª¶)›Z{ÝêÖxÑ;Êiš¥‚ó`}[7MÛ4u ”0ŒÈJ(A ˆH(¡ŒÎXðÞrÞ´Jik­#TPÊBŒÖ9­µÓÊ[ƒˆ½~¿ÛëRJgU©´BB(¥ó±@Râ!j­‰s!Æ*L³,Ïó¢ÓaŒc뺩›º®ëy-Âãœ!%ó¥ŸÖ9å­À„3D†ó²+Á9Œ@)¥„J¡Àˆ”ÆY„¨”êtŠÍÍMrî7Á .¸àøÀúúúööö‡>ô¡C‡ÙtðàÁw¼ãwÝu×d29vìØ;ÞñŽûýÀ_~ùå·ÞzëÚÚÚúúúg?ûÙŸÿùŸ?³é“Ÿüäm·ÝöS?õS_|ñmÿÉ<{ó\8Ëžà)OyÊç>÷¹µµµ[o½õÏxÆ­·ÞzÙe—Í7=ïyÏûøÇ?~æ›zÔ£>õ©OÍ‹žK:tÛm·ýøÿø«_ýê#GŽlllüõ_ÿõ<õùì¶zÀs> /xÁ n»í¶ùsä 7Ü0·Õ“Ÿüä3_8cÀo<;?àqŸô¤'ÝvÛmãñøäÉ“ïxÇ;úýþ¹Ûê,üÌÏü̱cÇæðþ÷¿?˲§=íió/»ì²Ï|æ3gãþþïÿ>˲§<å)çÒöáÃóÅ/~ñ»¥5Þ/ny×]wQJÏ}´?`XïŽ;î˜L&ÿøÇWWWÏ}þÀ/þâ/ÞyçãñøcûسŸýì[o½u÷îÝß—ÑþçB§Ó¹êª«~ò'ò{µÆÞ½{ûØÇ~ô£ýçþç+¯¼òÜ>”‘sö«ö;çþà¾ùÍo~ä#y(#áŽ;î˜[ࡪ‡bso»¸¸xÕUWýÅ_üÅ™\Ós±Õwã×~í×(¥¯yÍkÎ|b­=uêÔÃÝß^¯7NÏx§GŽ€37óÏý«¯¾úk_ûڎùÜɴÚO›F…0÷)"ËÒNQB[³=ÞÞÚÞ,«ÊZ[–¥V†s!¸4ÊmžÞ<}üô©ã§ÖNœ^?½¾µ±9ªÉd6•£ñlk{{m}óÔ鶬‚µ$FŽØÖõáo~ãß¾òåÍu‚NpLS¾{÷âåOxü¥—^Üïu%$‚3ÆhÝ6 Ä(¥$릩šF9S6Õh:ͦ³¦ªu;žNN¯¯mlo6ZÁ%&úÅ]+—=æ1—=ú1«{÷‚RÊ(Ëó¬Óí0Á›¶UÆ¥â¤*œ8ö•;þcZWE¿·zàÀþC‡öîÝ7\X`”j­Û¦5F{ï¡ßëîÙ½k8ì[gNž>qäÈ‘íñ¸¬je a¬?îYÝ3èc!Ħi×76ÖÖÖOZ[__ßÜÚÆãñ¤®›‘¸}Ê%—‰µ®mµs*„ÌŠ\JÉ8eŒ ÎÁàlŸIYä¹L’ù4'„p.’$Éó¼Óét»Ý4M‹¢èõzÃápqiqÏêž=«{Vv­ìÝ·ºïÀ¾Õý«—>êÒå]Ë~wayqy÷òpqa¸¸°wßÞ•Ý+ ‹ Ý~O¦)2b}p!Ìã˜HÀxc½ó1ø\ðÖÛV·j”5 F9Ö»ñt|ôı»ï9|âôÉíÙØ¢g©¤‰ˆœŠ<ݽoï¡ /8pÞ¡áâ"eÜG˜ÍªÑö¤iá<ÁyV3`!ÏMRIÄ"%H étòù2BkŒ1ÚÖÓòÿgï=£-«ª´á•×'ß|+% "4"ˆh¿~-ØÐF1`w«h+fQT”aT¤`tà¨%¢MÔ[AQ‚(©ª¸•¨›NÜi¥¹¾[︣€Ë…‚Ö÷•ç×Ik³æžsŸ5לó™ýzø¿¼íÆŸþôû?¼ú¦ÿ¾ùÁM-øÖÈÈê5kGÇÇGÆFƒ0J+cLG“cã£+''F‡‡9¡I2PZSF™TrɸU屎ÇÀ¨cÄRÜM“-n`óç6ÏÌͪ˜™™Þ°aÃ]wÝùûßÿnjjjnnv ²,ëv{s³sý^ŸE¡¬×lÚ´ùöÛý£ýè?øáÖ_ýƒõWÿð‡×\à ¿üÕmwÿö®ÍlrNOŒ>o¿½÷ØkõªÕ{ï»Ç¡/<øE/:ü°¿zá!/8è ƒØo¿}÷ÜsݪU+ÇÇ'ÆÇÆGGF‡šCÕJ]ðÀ;Oøà½öÚëâ‹/Þ´iÓäääÇ?þñC9äˆ#Ž(Ç6ë®»î7¿ùÍi§æ½?ì°Ã<ðÀ…øË.»ŒRúö·¿}bbb!÷i™)aKϼvíÚë®»î׿þõûÞ÷¾ç?ÿùßùÎwÆg>ó™…w_þò—/žê¯ÿú¯ëõzùté!„â8~éK_zî¹ç6›ÍK.¹Dk}ÒI'qÎsKËjéß¼4Êô°±±±¿ú«¿ºþúëï¾ûî…M‰R€guÖ¸ËØÝ‘óÒß{ÀÜtÓMåŠÆÆÆ>õ©Oí·ß~/}éK¶KÈjéï=à€î½÷Þ…§åãý÷ßÿ{ßûBˆs¾xs_®åyÏ{^Y¶ôØ?ì¹çžo~ó›ï¸ãŽ]vßÿü燇‡·nÝzùå—ÿêW¿ZælG}ô•W^ùÝï~÷¬³Î:öØc?÷¹Ï-ß~_üâç;ßY¿~ýYguä‘G^vÙeõz=ŽãÝ×öÝ·…5kÖ¬_¿þŽ;îxª á'žx¢µö§?ýéÄÄľð…f³YVÖŒŒ|ðÁý¼µöæ›o~V5gi-­w½ë]‡rÈ”Ò7½éM¡ÒqzÒõîŽ >ScßøÆ72Æ.¿üòåËj uÔQ›7o~\µgõê÷»ß}Ýë^÷ŠW¼âÆo$„œrÊ)>úèÏþóåØþ¡‡úóŸÿüè£~ë[ßÇñ/~ñ‹/~ñ‹yž?ç}ýeBë’¼ÞÀÖzÊQ #DF<66’õ‹¹ó;g§•E¦ c½ÃŒ2ŒÅÜ‚ç„E2– Àc È:O&é,u9ò<ø—"&• ªq‘ó³s×ýסapìäŠ Œc|íÚ•ÞûJ?ºm;”’®syšJ© À8뉪JifÔŽéq‡"ÌTñð#›SoÞÈå*Û²uÛÞ{ï»÷þ+„ m;Q_)U‰EµV'”8çz½¢˜0æ¬/¬Ù1;»sçΤÈößÿVkèù‡œeÙôôÌöíÛçÚí$M³<ËÒ,Ë2Êç¬Z¯æy^éÌüLVôwNl5‡(å;vNÏÌÍcÆž·ß~"vNÏÌÌÌ ’„f´Í‹\駘Š)F‚‹ ˆ¡ƒAêÀRFQd­››ÓÖ O(ÅRò‚UdBðZ£™È´É‹‚ ¨TkÆA¡•À[kóøàV«uÖYgýæ7¿)O¬Ï|å•W"„^ùÊWJ)ŸjÿÌ¥g~ßûÞg­}Õ«^•$É•W^9<<ü–·¼e™3/½¢ÅÇó‡vX¹¾è¢‹–#«¥óÒ¸÷Þ{ï½÷Þ½öÚësŸûÜÍ7ßüر¥w™»#祿÷ý￵öøã/ÓÞúýþå—_~Ì1ÇÜrË-O*«¥144tûí·×ëõ›o¾ùúë¯ÿÈG>R¾X¾ûàƒ¾ð…/\ìt!„XI–û§ÅwÞ¹jÕªááá«®ºêïxÇb‘Í›7×ëuçÜk^óšû·{ë[ߺ̚®}èC›6m:å”SàꫯÞsÏ=O8á„eÚï‡?üáÍ›7Ÿ|òÉðƒü`Ï=÷<餓7õTµýÙ³…'ÅßýÝßÝvÛmý~ÿºë®cŒ½êU¯*Õþ¨£ŽZ¿~ýc?Ÿ¦itzö4gi%„|õ«_½ð ~øá§ásŽ—|Q£££I’œ|òÉ·ß~ûrÖ»;6øL}Ë[Þò“Ÿüd1ÇÏÒ²Z+V¬Øºuë¹£ÏÞÕ_¿~ýë_ÿúoûÛ333ÍfsÓ¦MÇ{ì.äÞOdûcccûì³Ï5×\sÕUWÀ¹çž{Üqǽâ¯xÎûúËÄÈȤ±<Í2M¨à „ FL0Ée6^Xc{óƒ¬È1¢•¸ŠVi‘§™3†L‹$sÎåEQ…6ŽR޹Œœcмua¢ ¾Q‰IµêµytÛ¶Í>è FF[”qm\²‰‰QUd¡ ®ˆ`ûô޳;ûYFg’FõZͤijÑà*‚ÇõªÑ¦;èwÒn/é"Jò<ŸnÏmݾ= £¹öüìÌ,%„QÎçB”1ÊƸÐBÞ,¼ï¡‡sc:ð 5kÖ4ZCQBù4K”Ê3ƒ~Þ•˜PêÀæªÀŸ« Óëlzd*Ž+Q¥ª”™ŸSÚpÔëM­¡×OúƒÔ9ïûýÁÜÜ\¯;(ò¼Eœ!E%®Hö©Ò&Œ*A:ë(¥QÅAÀ(I°t!8”Òz‚½á\Vªµ‰ñÉ0®¤yÖíw³"SJQN=&hIBP§3Ÿe¥´Óï`F#›·>â½Ãcl´AàkÕºRÊ#<Â#„‡2I’‚)2¶c IDATv€½Ã¦œRA1òa%ÄăÇ3Á¥ ƒPÖ»4ÏœW„‚q…Ã(èA‘j0Ê›DeݤŸª¢.kQµÖl 7{ý$ôzFcL0cÀ½AÎCÒO4c2àcÊ(¥œsë\‘½îI&= gCiàÒV1ΰˆ´3ÖºÂÙ ?4==3µjÛêɕíáz½>1<$ª±¨T¨”#ï‘g3. *q-Œ¤u^éç!×Èj­1Gˆ3£•5…V& CGP¡ŒCŽKVˆ‡ÎVƒÔUyf=äEŽ0‘BJrÆ¡8‚HFY†ŒÐ^Ðît= Æd£94119>ÒªÖâ‘¡¡8¬ ½n’dý¼Ðã“ÃÃ5ˆ0æA@‡[íLmyd˶NÏÎåª(Y€=!„Q„1ÅÜêÔeµccD8c!cŒ³†\F=Ø<Ͻ~ž&FΔ"Š*€0Áœ3ÂY@©à …¡Eœ î¼ÏµRÆBX(0£ÆÆ¡ <ò9pÈÿÁç,»q‚÷!Œ !„3ÆG”Xc,xdXðÆ#¬µ.´¦ŒÆ•¸9Ôh¶QmBAÈ{gŒ×ºp` ÅA(1–˜¨RiÔ›‚sµüzÎãŽ;îg?ûÙääääädùÊÔÔÔ!‡R>öÞ×jµO7;ûðÔ#¡~šLŽOÔªÕz½ÆvPбäœ1ÂUÖ”tŸt^¤Ö) ±1ÖYáÐðh­Vo åYaŒIÒ” 199sÎy‡)BbŒu®»Ê8g¼÷Bˆ ûƒB¼wΖ©‰qÕ«Œy«ÃÀÛÈ(mŒNs3È Ì˜ ç}®Š$Mò<·ÎzΡ?ô=dÌZ“eƘ1œ6Øc àöŒRc¬ÑÆ€e”yðÞyP—SZimçŒ2çœGˆPRÅŒ3„I £j¥^©Ö¢@:äœU…BÆæI’·¼Hм°FYãóìÑéé‡7mlÔíN;W…%i­ÒàT¦Ib ç B@Ò,K)B+¥ ÈYf´öÎy¬ÇT`Œœ³ù?dTÊ@x† 8ï!D´;×Þ9?)m“B­á,hÔ¢j<—’qž&‰µÜFH‚bˆ Ÿfiš"JPY—ÖcZèÂXÞG’x,hÈbÁY\­V뵚Á˜ö|»Ûï—U¹¥Ü1¦„`‚‘G„Z½N.ÿjµÆb¾Ûé´»îØY«F؃G¾^©U+XÒ:`礟t´žˆã0®„«×­nNŽW«Õ~2xàÁ»½A¥Z£B‚G*ׯ:ι5Þ8Ï(FeRi£=e" ´‚3R4`Œ1AˆbŒaŒ ¥Ä# àÁz‚©àŽÀ5Î ²”sn¬yV²kÞwß}e°eá3ívû³Ÿýìå—_~ä‘G^{íµKOH‘ºXÛ—ÖÉrìÜÜÜÂë‹?#¶OƒQ镯|¥c\v šššú›¿ù!DyÛ]èÞ¶Ë=#š³ôu"-ûs¼ç=ï);d•7œ8ŽkµZ"~R¤izñÅ—?ÿùÏ?üðßüä'ßô¦7=éz—ÖöÝ‘Æ2ÇžvÚi½^o—ðãÒÖ½4ÚíöEDŸÕ«á…ŽŒŒì»ï¾Y–!„®½öÚýèG7ß|óâžRKØþÜÜÜ…Ò÷¿ÿý+®¸¢¬v~Îû D\©[G²ÜdYVZHÎg„q&wThÂáTbÖ¨4˜lî$O(âÖjçÀåÂ!ã&T²( 8eØÀ˜b‚0‰„¨…a% cCº·6O“î¿ohdèyaÆa‘kBI³Yó¹vIVT*yQ÷Ä+kÔœUÎ`N3«óBe…"”0B•Ò½$©»*£ÔX£­AK£¸ª e%jÕ+'WDa…xThåŒqÆäyÈ—>žGa’Eše¹RóíöÚU«ž·÷>ù@ˆj\!k«•3X#Ìb$…C!¡´ÓëYç "ÎcÚëƒÇ„²j½aFR+åÊ™™Ù¹¹¹<Ï£0j¶Œqi2 £”REaŒ…"W£A’ëœ5`-Æ^IÖæYfŒñÞ£Œ³pIJ)ðVÖÎYT‰0ÆIš–åA:këz…’ Àa`’ÅÕ¸Èr¥4ç!’e™RºÕlb•ÒZkc,BÞ[d¹—ÞsbyF1ò`´±Æ ŒÂå)š³Öm)õØycO)òN È{<¡½G³íÙ î«×ÎÚA rðpldÔ9·cûö;wª\1ƨ§œp‚ˆÑ: ²Z)°â”b!h­#ÌcRäE*Ò0’BJˆc˜S.¸ˆy@(K»ƒ¤P[ÝÑé÷g;íósÍf£544:1V¢¹™™"ÏâPcŒÖFk0Æ*Ud)œJ°'‚N5„R†9§TD’YF0a—M£8J‰±º×ëxŒÂ¸J¥ Yc0&ŒjŒˆeŒn ‡Aˆ1.Év¼½~:ô·nÝAöPF]Í|»S­Vå”ãT’õ´)0EŒN¢@õZ•3–$Éö&™òmc­Àˆbጂ1òÀe”8G1#”`΃"K!BaPžcˆG„1ìqŒ5˜PÆ¡x’«$Ë2H`D¥Œ@EÕj•2nŒE3Ƭ³ØZB)ç<ÍÓ,˼ó2Â(’RRB”ÒI’xç…a"L¸Ç ÅªT*kÖ¬ãÀeIJ ")9ç„{œµVL‘ÖJ[÷Ï#eT½YãL,ËçtÎeYvñÅŸyæ™ûóÏ?ÿž{îyÙË^Vž.{챯~õ«àŠ+®¸âŠ+öØcãŽ;îŸøÄUW]uÐA-óæ{ß}÷½ìe/+?¶¾e‰™{½^µZ]ød­VÛe“1^x†áSZQ‰Ç†}žTV»)?CdY¶P[J’sþØf-O#T¸iÓ¦’r¦¬z:à€JGe!4qÎ9çœsÎ9aæy¾ï¾ûJ)7lذœ±»©uÏ®¾úêsÎ9çÅ/~q¹ïܥ﷜Hèt:‹5|1ÓÒ: sss‹÷è»P@=mmÿÚ‰'žþð‡âxQ{ì±7ÜpÃqÇ·tvånjÎÒÙO¤±«W¯®T*_ÿú×§Rë[ßšššZ»víSý¢N§sÏ=÷yä‘e¨ùIsk—ÐöÝ‘ÆrÆÖjµ“O>ùòË//Šb™²zRÜsÏ=ÿôOÿÁ.s.G»³Þ£>ú'?ùIép–ùÞûcŽ9æqûïbûSSS‹á²ˆÒ~¿ßéô…àRä c|¸ZÁŒ¶;=LIÀÃj­¦¶È3£-BÃÎiAcœ`‚$%‚ó€°ÆkçÆ B ”- §Í¯W+Öh„Éôô£›7ml 5W¬Z Îc‚)›ºégI¯Ç)­Wjµju¾ßA@DZŒ\rP(eÀòÔYë=`J…”ãA’F2l5šCÍ¡PÊÑæ°3Æ#ÜïÀ9« rP¤™óà12Ö*c”1cJh–;wî4Z#ðíVFcc£ýA?I“LŒ3ω'Sä±G)¥TpÁ˜PZÏ·ç…ÕjPÇQ³9TÖjRÊ0&”`F™$’`äœQª(”vÎ9çµÚX™5 {„8k¼3:Ï´RÆhk-e†=FYç”Vxà‚—‡V…RŒ1Œ±÷ž2ZoÖ¥”Ø{Æá3WãPˆ^¯çÁ#Œ8¥¹5à,öÄYkµ±Æ!„¼gPÀQŒ#)ÁjF A(AAXÎ÷ÈjU¤˜xOöÞ!ä!!뽋)ªTã( <ÌÎÍh¥¥Î8o}5Œ[õ#„¦@Úóí¢(8£4®`à Ïs‘àc¤µq€0#Ù,Ïâ¨"8+«…dœ1e5Êà ˆ+‚ò!³~»ÛM’¬PÝ4é¦ik¨µbåŠÑ±‘8Š&VLy–Í›™ÕÖ&³ªk1%yJqDT b˜G!„‘GƒvÖéÂ:SÌã å!!°Æ)UPä ¡cŒµÎCÂ1÷µJm¸5T«Ö0&ós]¥4x\FóùV£Q­U6Ó3sR)e–d^{zvºŸ F`„Rê"„)FÇÇöØcÏÕ«œži;ÀÚXpyŒɳ’Œ1BpÉË‹q $3Š£ƒ3Þypð‡N›˜BŒqÚX0¡ æ=ÆÈSŠ1&ˆ÷Ä#d= kB˜)eFP«Õdhc¬r˜’ ­µEQBc”0kÁjM#„H) !ÖyŒ‰CÖ8mŒµVÈ€‚fœ·††FÇF´Qý~Ï9+¥àŒ‚uÎ:ïœ-t‘æ)!”qj­3VcŒ9ð,Ïâˆ,7·ö¶Ûn{ùË_^ÚÌcßÝk¯½.»ì²…t¦c=ö‰¶ —\rIµZýÔ§>E)]œþ4 s–,F¿ßR®‹ÇùÁ<ôÐC>³¸:¨ÜÐ !Fyv¾Àgû”Vô4dµi<{XBÎO¿ûÝï?üpBH+(wºÏH—ןýìgþð‡ÇÆÆ¦§§BeuÓ.)» »ä·½ímY–ý÷ÿ÷SûDXŽÖí>öÝwß]›‹ñ’—¼¤TãåLuÿý÷~øá‹#WË×Éßþö·‹5üÔöÝ·…f³yÒI'ÍÎÎ.ŸÊ•RzüñÇ_vÙe ¹ôRÊv»}â‰'Þpà ?ÿùÏü«]<äåkÎÓøUKkì† JÃ)q衇^rÉ%gžyæ7Þøt6¬”®]»¶Ýn#„žt½KkûîHc9c_ÿú×GQtÙe—-_VOŠ«®ºê oxÃë^÷ºo|㻼õ¬^ý~¿?>>¾ðtttcüD$Æ»Øþ­·ÞZ²•¯ì½÷ÞŒ±å7•}ÿÁƒ'˜A”åy?éŒ0Bàq64<Œíté@ Ê0Tý$MÒ<-°'¡1ØÌ÷uÄc„Æc¬Ò&7˜;*½èd¹)ñN fœ{ä굚q°}ë–f³Q«ÖCM„=ñ¨R­ºÓo·w,(ƒ r¦R©R)’"£ŒSF²÷Üs§§§÷ÙgŸW¿úÕÿó?ÿSfýýîw¿;ùä“ÿó?ÿsË–-'œpÂé§Ÿ¾xÎcŽ9樣ŽúÞ÷¾·yóæÕ«WŸtÒIwÝu×..Ö=÷Üó¶·½íMozÓ/ùKxðÁwa–\,=ó—¾ô¥ë¯¿þ£ýè\pÐA½ë]ïZ<öŽ;î@}ìcûÌg>sà.îÍý¤+ZKËj9Òxz*ãºADQT†Gz½^I×¹;r^_ÿúׯ¾úêóÎ;ï3ŸùÌèèèç?ÿù;v,îCó´ñµ¯}íŒ3ÎøÒ—¾ôö·¿}íÚµùÈGn¸á†lrròþán¹åçÜk_ûÚ÷¾÷½ŸøÄ'Êw—û¬âøã¢¨¤Ç<î¸ãfggxàÒ ÿþ÷¿Í5×üö·¿MÓôðÃÿìg?;77·:ûµ¯}í¦›n*Â?þø|à?ýéOûÛß.çK/½ôÒo}ë[ïxÇ;¾ýío{ì±oxÖ¯“çŸþµ×^{ñÅ_vÙee¥Ù3¥í»o +V¬øêW¿zÇw,ß»;úè£[­Öõ×_¿ðŠRêæ›o>á„ÞùÎwÎÍÍ-}š°ÍYâW-qõ—ÐØ4M'¨—!¯|ð®»îZ檃 øÛ¿ýÛò>ðš×¼fíÚµ%wñ“®wwlpii,gì[Þò–û¤;ZŒ¥­{i\sÍ57ÝtÓ…^轿îºëªÕê©§žzÿý÷ûÛß~V¯þúõëÏ8ãŒw¿ûÝßúÖ·ÆE]ä½_«.mû_ÿú×ßóž÷|éK_:óÌ3…_øÂúýþŸÉösø_ Å1—bÛ¶­[¦6Ïí(…dI/™f3#“£ëöØ#›ƒvÊ·ZúouO5dµ„ PùÀYåÀ8¥5Xƨ`Ò˜Üy¢åy> ÆÇÇ¢ عc‡.ŠF«™¦‰u.Œâ­Û¦´ÕQÿÕ‹ŽÈR‚S&cÙjÕç땊lg{®È‹f«‰ î'Išj¥µÖ6Ë3•„’‘‰ñf£i”‘B®šX962Z¯Ö%—çC«VwÛmê=Eˆ"ì´ÑL(k xI9 (#œsN(EÖJʺƒ,Ë·nÛF²¬ IÈÁ9 Ôð`œ¤iµRcL&Iš$ H)ËÞý~vvŽ¢¨×ëB1"³.Kó­[¶­††šÃÃÂË,/*•*’qFÖª‚\ºÈŠÔ{„ÁQ`,/ ‹!ÄY«”ÊóœPœ«Â8ÛétÀ{댜s^E¯×“\4›ug­g6NGq˜ 2­T CFX–Jé‘‘ì©Gq5Š’$ e8:<ê,0J›µšÉ‹áfÃã¼%QJ²A2¤ZÎ$ÂD)•õ•jÅAKD°.²öì|fä=&˜0Bãqa‡8"’a¯],ƒZ\“\TEr÷è#Û´ÓB0*0a˜qê±#EQ­^©Ò´Ýî¡…""ÐJk]0FJ¦€*E9rÆšÜèŠ 1bŒxl=òÞ[„£I– 6nܶuëC­ÖþûíÛ¬Õã8Z·v]¿Ý ÒÙî<"¤pÀsÎÀè¢H•R„1J)¤³œ „zB±C*ÍÛ¨ƒ´.%BP@1VcLÊûŒ3Î(cVÿ÷ÿŒä£NMM½öµ¯ýÆ7¾ñè£"„~õ«_-t½GqÎ?õ©O•égEQüÇüÇb’¥Ç>«øÊW¾²ÐóÒK/-ºR8Bˆ/ùË …Á¿øÅ/N?ýô…K°nݺ’^!TîVTèIqå•WsÌ1_|ñ%—\Òét.¹ä’~ðƒËÔÉë®»î½ï}ïÙgŸ}úé§ßqÇŸøÄ'.¼ðÂeæB/=óŸÄÊÄÚ›nºiñ‹×^{íñÇÈ!‡”~ž¶ÖíÎÕ_ZcwÿÈ©¤ïJÓô¾ûî{ó›ßüØ(ß3nƒ»9ö/xÁ¡‡ºXQ—iÝO#òþÿñ/½ôÒ¯|å+Œ1„ÐÌÌÌ)§œòl¯÷ãÿx£Ñ¸à‚ JVç;w¾á oX8JXÚö7lØpê©§~ñ‹_,O‹æææN=õÔ§ÄAðþ_ç‚qŽ)Y1¹!g»Ý>ƈ³!ÌG ÃHKH’¬;7èv:—C£ÍJ¥??¿í‘Þºj9°….8†é ×§ˆ‚qÚäWcBˆ(¹`ÖÎy–&Îã²×înøý½“+&VNzÎ[)ÂæØH´c['H!šõF’gí~¯×ífªÈÒT[ È—¹ Bˆñññz£¦ˆ\Zm½…‘¡¡É±qI¹Ó&²Y­U+UιQ&Ï2yåLšiž;­¬µRJâ±.”ÕŠ3&c„¦Yª V«È@H‚ÎxÎEL€×Úõ…Ui’ö{}mt¢©VjÆ(B¦ižgF3ޫ֨,Ë8”RбÌYÛïõffgÁ˜ÒZ£J¨¬³” ÊyUÖ«•˜$IÐë£<óÖ{Fys!%…QBÈXÛï÷ƒP2F€‚b’$‰ÑšQB(òT^0Jd\ dÀ˜ˆ¢X+C1­ÄU‚©A%Œ1 4Í‹4C9LÅ2§RJç!D•'…6„cŒ¢ hÖQ$S½þ =?×ït @ž0Æ"´êA&››é€¡ Ç×­;øÀƒVN®D€¶mÙÖ™k{ç9¦õj£ÚŒ1CZY6 #ïÁ{Áx£^OpVÊ{ÎFÞç˜CQB”5ý^T ’a\©8*/À[16ÊívÚí¹^>;3=ý¨¶j´ÕŠEPÞ“¤x IDAT*C­ÖÐÐHµ[›Ú¾uÇìNU(Š< $GDrÚ¶€SV CÄ…Ì­ÒÄC–¤ÞC^( Ž1F¹ô”Z…Ê\p qà:ýîæ©GæçÛ“Þ`ÎpN )%“NgàÜT§Ó! ey’&}„ç^±bÅèèè½÷ÞûØö“®èiËêY•ÆŸ Õjuß}÷Íó|Æ »;Ý%€³ÿþû'IòØ(%ç|Ÿ}ö‘R>øàƒYbìŸ Q­^½:Žã-[¶,fý)122299)¥Ü¸qãüüüS¼dˆÝ°aÃãæë.­“å‘dQ§vÚ¥—^ZÒú=#Úþ£-îft™Ø±cÇB—ùåë¤bÿý÷¿û¢‚àŸÿùŸo¼ñƧtβ´¶ÿßh Ï’æ<©Æþybw¤ñ´ÇºÝnYCñ¿¹ÞÁ`ðDùðKÛ>BH)õ¤qøçð—< Œ›FÖÚB)­lži«‘*ŒG˜3A Õ…šŸÅ›j6šõš¤ä??OºSS›¼u’qJ)'\0!e`©ó…q…œåiVäÊhe´ü/ð .¥N÷ÎßܱnÝ{ì¹.Fˆ 64:Òîu‹; !jQ¾}úÑ<Ë$çŽÐÜX«MEQ‚¥”³–x¬ MÒï6mÚ,¹jµ&'FÛsFh½Q¯ÔªLpã ¡Ì;°Ú Æ” ´6€¬às„VJcBa­µ8eM¥ZqòL ’>€cŒcLúýn\©DQ‡!ÁÈ­)òœÂ(H‚‚,K1¥aWª•0Œ‹”Y¥rÖð( +•Š2šPF)£Œ#Œó¼€P†)¬÷˜1µ! ‹5`Òjaò"7ÆBâJÔj­Z³šQ2?7§u‘ç€ ‚ ªÄQ 1Bã =øÂ‚=ñBàXç&„PŒ¼¯µ±¥R†”’°ÐÀhë¼÷Ežgyf¬a‚"ŒœwižÎÎÍ"ï+• ˆ`zf¦—ôeŒŒ Ò~§kÁyÁ„³Öhë=¢„B1cœYçJ¢VïÁýÿì½y´fEuð½k>Ã3Þ©ûÞ†î! "‚ÂÔeb4vpãl\NKÔ$b4jˆfƒ‰‰&’ $hD[C  Æ4FqB£_Ä!BwÓô|‡g8SÍûûãñí¯?‘K›†$¯éß_ç9Cª]»î­]{Ÿ]ÆX&h‹¶ãJðTÉ¥áÒ’óÝN=úœw2I€QÂ)¥”EA¸ˆ„ØITœ ÞCcœÅ85=ÕïO3!¸àÃb8IwŒ>Ðyí‚o% côÞ{ï"'BJpÞWuUiícTYÞâ<`t.4FSJ‘ Wœ.…hw[kf»yš¦ÁFp"&•”R%i–¤ ¤y25£¹ÁE@ $Z«•Èe’eíN–g„ŠT@’ò©éαëNش鄎wÎ×M¹k÷®íÛ·X\rÞï5œqF™qf\e©‹ÎŲ¬³g @Œ¡nªª)œgY‹Ì/ôÒË[Ö8B(Dfë°4XÅZV5:`”‰äRH‘{ "ôÁÇ#@,"RN‘DŒq:„€ˆ„!„R ‘TU5ÉSC)£„MÜžŒ1)眱ÆQ „Rƹà‚qNÑZ×eE(S*qÎB”l¥IcŒ1RJgggSa!“]=%çR*Œ1†H© LpÆeLH¡’TácX\\¬Æ££±µG9ÊQŽr”£å(ÿS`ŒÄ#gœ)–ªIÆtSÅîýûïݱ­htíL1.IJ*†•• ¡©+ $oåœÑIÆ•Lóª.ÓÒ9'„A" ¥´Óém–––ŠbLÉò,KSÆà‚S&:ݾ֖#–e9ŽêºQB¤y>FãqS7J(ÆyÕ4”QQPƼ±Œ3J ‘QL0Jå\ei‹nB’DQÆ#!Œ 郣íN;Ësm´w^Ê""¢’jíü| ØÔMšfy§c4´ñæÇÛ·¡óF)d’$!XÆç‚ !:­ç"˹RJ%J&*x7šF—EAYäœ1JgÞ:J,¥TIBXwÌ1*QÖïÅ(Í¥„´6| $DoGêj\ŽFiÚÊò4‘ŒÐV«5ÝϦûÓˆÐ4ÍpT8ç¬ Öu]£”0B‰2Œc¬›Š2Ð#‰‚,Q‰â‚ Ú˜rÿ±à1xÇŸì×c½61‚ h™€v+íäY¿×'@³,YY^ÄA—õ`Pei½±ÞpN–‡Ki*©WV–´©÷î}à˜cÍ;]k}­5!¬ÝÍ:y·)4zêLô!¶ZynÌ`4ÔF#`¯7 …`>¸F7Æè½³ÖDˆx Päœ#bAk]×5fŒá|òµ&“BMv>'”ªŸ¬5PÅ=ÆX×i4¥Tª$o·Z­ܹ@8çI– !0"EÈ“THÕítÓ Ú½6cTI™&i·Ýåœ×Ue+ËR/-9­c@$„‰Š2潌†ÅòÊÔôÔQ›óÿV8çÇ{¬Rj×®]?•Ôqýúõ!„‡Êôè½÷(ÿsÈóüØcýyÓuå(G9ÊQþÛiʆIÑíB JðDf” %FÅxçî€SÁ•o\SÔÁz$³¸wÏpÏžz42uéµ¶Ö"¢”Špfœm´åJ¥IJ£g‚I%£ÁxςڛÂVT€‘rȲ".î_®Ë’0º2µ—§æf匢^[b–gk×ÌV† sk­3vÛ½û——IUv×NkS"“„+i˜³àsÁ"…º®#†^¯›fYˆ1n¬[\Z†è½LÔÜÚ9gLð®nêÁpb@J¸R<È@ÏÙîu|ä‰jõºh½6&Vu– TRñÄXË£ŒFô" )ò<+«: 6ºq!r.ãYž.¬[7ÓÊàh@Öjaĺ®'ÙƒÐZ;———öíÛë¬M]¬‹:Ï[B0îc’!UV)¡c„V«Í-Šb¬µ÷žPâ¢÷6LM÷CŒÖÛZ×RðRWJʈBJž¨„sA—B)‘†ˆ”Áe–§Ñ{ã¼õÁYg„TR%ˆ1Ä|!8ëeÝnÖíö¢Ë8BBˆ r!˜USGç ¥P7uYŒ´n!”PJiˆ±ªJÁ%"„à„„ ’<"•èÆPNy«‘ÈD*•µЦ†8ël ^r&¥˺ŽÆue(D‘H‰ŒÖƒÁ UªÓjFûý~·Ûmå­¦Ö|ïÞñ¸”Î+)ÅbŒižJŒwÚZãq.pÁ!øˆH‘H©²,Īªwí.Çi¼Ãª e集4:8•„Îìl¿Ýî0JB’³v–·òV§ÝÄÈšÊ:ïG£‘6Õp°ÔîdY®}YÃÁÊw¿óÿXl<îÄå¥ÁÝwÿÛキߟõÓÐïôO<é¤õ›l¨SVÕÞ}û–——¬³íïÓ$ÑZ//-Wuí¬­ë&Æ@)çBD&Ù›Ó4í®?6ÄC¾ç<묳ÞúÖ·¾ë]ïšl_þ_Ìcó˜4M*ÝßQ~Š—¼ä%õWÕjµà¹Ï}îg>ó™C¯^ýõÃáð¢‹.zÄå¼ú{q(¥OzÒ“Î9çœ3Ï<3MÓK.¹äМ®^xáK^ò’ÓN;­Ûíîܹó†n¸ñÆ'I´&Wßð†7ZÚ–-[n¼ñÆG»kV¯ód ½å-o9å”Sʲ¼óÎ;ßûÞ÷ƒƒWçææ.¿üò§<å)EQÜpà ù—y°E?O}êSo¹å–O<ñÞ{ïý_;LN9å”w¿ûÝ‹‹‹—\rÉÏõàºV×ÉSO=õ·~ë·Î>ûìÙÙÙ;v\wÝuÿ÷èãÏ|æ3/½ôÒãŽ;nÿþý7ÜpÃ5×\s˜ï}ÛÛÞöÄ'>qÿþýßüæ7ÿîïþî‘ZnxDtòïxÇgœñÞ÷¾÷›ßüæäÌ5×\Óï÷ê¶k¯½öÖ[o=Y=,¿üË¿|É%—œ|òÉeY~ík_{ßûÞw˜›ñI{WéÁÕuãûGù Z)[S]Ö((Ï3/ˆõ!r‚Ãå•m÷î–dÅJI=™i÷z*SH\U‡ZSŠ)ÂISÁ™$€ž§‚$Ta„ÑF£õ.˜8'"ç]Ô¡fŽyôMS/Xô²×-ÆõâQªÚýv6É#•f©.‹…µsbS–ÞÙ:z ]l*§¢—J.E¦¬w½äL%J0!¹Ì”j§­T&Y’ëæç×Àº.ÆÕhXK]{ÆZ1,’X:-óTdj²g¥Aç)ð„AåŒ+‹\7³S½N–d‰pÎùçNªº©¥J’,çR‚Ö„ ÓÔ*cBJRëf8Þ¿s_·n~v¶Õî¤yžæ—,ÉÒ”$Œ1k ¾•IŹb¬.Æu°ÉÌtÕ8í£išÁÊÊh4²Á!# d¸2ÇM]1Jm ¦²ÎzƇBJ™$Yž+‘,¯ ¤ài–Æ³È ÁÅ`%œsB˜>oµ…ˆ 8WRpŬ7©TYžJ!)¡‚ ΄wÞæŒ§‰H’„ ¢µ¥ (S7i˜wÆÛb]ÕUQ™fi6X\©F ,/¯JëN-UB(e‚[ïôØPDN( ÎÆ²,K”\!ÚØ$M±i&””€÷^pD´>X$§DØè\Œˆ$ãŒI­Ãè´®’4V—Eˆkfg÷@¡ÜûÊ#¤ŒbDˆ?É<Q{뢧œ%y:=Ó'›ºFàS4§”cm¤Œ !=`BB5 R×Új묳F3â{9Wœ"RkcU»ªöÚørž£çœ•E•%*OSNhUVFg=P‡; IDATAdŒRB¬suSËB.(@ôÞ6U]ÕÞýÃ5só”òá ´6zóvgÓI'®]»F*É(œ†£Û·íÞµ³(Æ}šªþT.–÷ìÛ7ŽF#6zÁF 8cLL2 "FpÎB(e$Ti|t!b"I…T cÚiK)#@ Í’¼•!`Q”ÚÆ8’@¤RmÑ‘R%Iª”¬uUWƹ"8½_ŠËº©Ç£±µ) £ !ˆ(A @€K©˜üÿlÎuëÖ]|ñÅW_}õ‹ÍùÎw¾óä“OžL›Ž²:Œ±|ä#7Þxã[ßúVc̃wýâ¿øP9`ŽDÎûÞGœ©©©¯~õ«Zë•••………7¿ù͇Úo]tѦM›îºë®•••'<á 7ÜpÃ9çœsÐÎܸqãÅ_üéOúàÌû‘Ý5ô?Wç3Ï<óË_þò·¾õ­«®ºjffæÍo~óSŸúÔóÎ;oRI¥Ô¿øÅ^¯wÅWlܸñ/þâ/¦§§ÿøÿø¨ÎÿçxþóŸ¿yóf!ÄW\qß}÷æSGÒ «ëäûßÿþSN9å–[nÙ·oßùçŸÿ‰O|âì³Ïþ½ßû½ƒË·ÝvÛ¾ð…~ðƒ§Ÿ~úÕW_=77÷'ò'‡óÞóÎ;ï©O}ê'?ùIBÈ 'œðêW¿ú’K.¹à‚ Œ1G(ÃGD'Ÿþô§¿óïäœìc;hsLí8áøã?묳®ºêªÃ‘ÕÃr饗~àøÜç>÷×ý×Nç…/|áw¿ûÝ¿ù›¿yTÛ»z®®GÇþQ%T»H(3rE „Êk @Œ>¬,2ÑɸjІ¸ØMóé¼Ý*šC ”cw”P&"0ä'‰%‘0âbðÁ™ eà­‚P4ð„¤0€ Ñn§Ýn§7Z;7d’§í¼cm0feq+ËZIÒo·õô\·²ƒi,SIÚÉÒ#„z#bÖÉr•¥iŽ"Díæí5³3º1Bcõ`4hÚÙJÞµ}c|YUÖB'~mt;OZ½Nà`Œ)m#˜Ð+]Wºæ’MõZ’ñ:†<§4QJ©WYŒÙˆ*Kµ÷Išå­–óÞy?·ïØvÆH!@zzi4(m#¥’ûà)N»“HÖk·:yFc<°oï`™3*jŠÚç#"ÆHA@J gÜëŒå„sÂH$€=m¸Äˆœ ÕÄ—£‚bÃ8Ñ#Ä$‘­,ÉRîœCJj’4çŒSÊ¡˜±¥õ¢ 18º¬¥Y– !¤ „Æ@$Ó¶Ž#!µn¬±V[c­m,E*3¥vÖyʪV‰rÖ©4RÈDYï¼wœRÉE€à%”RÁx»Õbœkk¸u]K¥£FëbÔcH®b` ¸r"0B¼wUS]BóDq‚Íx\×5D$Y«Ýs=ÖP+™d*á‚ DrÆç”j‚U”IÖ#=&Hž+Æ".„“ÝYµnê¦qŒ1ÊÙO\ÞyÇ|*ï3&x/ œ3ƨó$ "A gÝÀYë÷/uÚy;Ë8¡ÑNYžå€F)H’$Ëc›ª,"zç"¡ÀX’åÂØ¿oió™“Œ1oûÛ?ô¡Eq8Õ /ùË'Ç_|ñÍ7ßüœç<çæ›o>B¹N&IrõÕWøÃ~ãßxèù×¾öµ‡þüÄ'>155õ¯ÿú¯WÇV‘ÕêœtÒIþç~Í5×¼æ5¯™œyÏ{Þ3;;ûh·wõ\]7ŽŽý£üÿÖ>¤’\øàk­Sgç.zcÖµ5F&1úà¼6uítLŒŒ TB²¥D©ÄúÐhm}¬³€8g½ECb#:ât0Æ7ÒóÑx,•PD0)Ò<©¶Ë‘5u³¼¼Ì[ùÔÌìÄOÂÉÛ­Lª„óåÅýM,¼w1„,M»í Rµ{°d¬§„æY&RQ×õx\´Ó¼ÛéåI&©¤”GÅ8DIÅÚ¹9ïç\)955U7uY—K˃i]kÀC¤(A‚Z79v²V!eŒ2%“vî¼Óeµ2­÷³’+Ê¥ÄB”RÀ8" F¡d¿ßgL¤Y*¤$œQÇз¼²ŒÞwÚmž¨ Çm(u¨ÊÆy¿vn®×ëÍö{Ý<”äiÒJÓªj hSÀ9•¬¬Ê¢.¥`*IãÁûDª#L0Á8O3 ¸’y«-¸pÆ@1Î9ã@ 4O², ãñ¨ªj¢ó®ÑšRÒéö„`1¼uÖ9™$ŒpB¨3ÖK“,A©Ê”J >I²T´©ä£Ñ¨.k)T»Õ²µ>Ω·®*«€òÞ¹ÊcM¤R*Kcô’3É9E@ï!Ä`];Ïû½^Þn%1Íòœ A) !ÃQЦÄa&í]Uƒè‘0Jó´b¤Þ…à‰À9Œ3•fIf£«dÚjµ YÁGˆ”’qŽ)§i’ä­Œ1Z7£)©tí— L0–åÙÄӀ릩‹ñx\U>¢LR™dŒs«1v4.œ³y–§I‚½ó#ÚÔÞÒÈX œ3!òV;§$øhkê¦6†3¼ÇЇNž·[­vÞ²6,¯Œ"’N·Ûí´µi–—3”‚Jd¢’àüââòx\ƈR¦R&‚Ë5kÖžtòÉ›NÚØîHD0 YÖiµNX7?7,íÞ½s<^Y^YµóF*#Æ ‘ÈZ-!eˆ> œ¨DÉ)#TÐ#£,Æ(jY×€B4Î1ÎFeª¨ >8çö¾ÐŸk&‰…´kŠQ1.Æ’'‰5Î;o­EŒ€”ÂJ)8c‘R„H(ñÞJ1¼ÇHËóV+Ï#ôðÿnÚ´éŸøÄþýû———?ýéOwÜq/mܸñ£ýè~ðƒáp¸sçÎ~ô£?õþ¬³ÎºýöÛ÷íÛ·ÿþ/ùË¿ñ¿qðÒç>÷¹­[·>ãÏ8餓¶þ&Ñ›‡Ã*%ÀùçŸÿ•¯|eß¾}·ß~û¯üʯÜ~ûí§Ÿ~úäÒ ^ð‚Ûn»íà§vÚ¾ð…Éæ„‡Ó¢ãŽ;nëÖ­gŸ}ö;ÞñŽ;v8pàãÿ8cìaeõ°u^…½èE[·nÌ#ÿäOþd"«óÎ;ïà ø`÷È‘Èùaß{î¹çnݺu0ìÞ½û£ýh¯×;|Y­‚µöë_ÿúC…þ”ßò?øcìð5çQbõ:w»ÝÑhtp¹cÇ8(®_ûµ_Û¹sçdÒ 7ÝtS–eOúÓß­÷½ï}o8ÞvÛmëÖ­;üñ ¿ù›¿yÏ=÷ ƒ[o½õ¹Ï}îí·ß>??ÿˆhûŽ…v»}ÑE]pÁ?oGsÌ1üão¹å–ù—Ù¼yóá?x$½°ºN~ãß8ô†;31¶°°0ùyúé§ßyç‡ZYY–þùÿ %üÞ÷¾7‘À‘ëóê$üÑýÑüãÏ~ö³«Ü333sÑE]wÝu£IW—Õê¼â¯`Œ½ë]ï:xÆ9·gÏžG»½«÷àêºqär>Ê/3kgfçæºÝ.!ÄZ•T‰RˆÑ5 >zctÕÔ…6•±uQå`ØŒ5šrÕM;³Ý©ùé™…Ù™…™Ù…ÙÉAof*oµ„’@i à|hjW—Z×Î6¡©œ®|1¬K£b\Q¦ûS³³kfggçfg³T ËßÿÁ=ûö ¬ñŒ‚ÊÄÌÂìÏ:ká˜cÚ½— (ጷ[™þL¦ò¦h†KC[Ô§›¦i&»• LíLQW?øñþyëw|aëÿãGEQ$I²°0ÿ˜O<夓fgf²$ï}D\äyΫªÚY§TÒétó¼­TÚŸšÚ¸qã‰yÌú zýÞ•AÙh™¦y·'ÒÄ… µ.˲, ÛhIX¯Ýj·2Fc$ÏÓN·E(hÝDíÌ UMÝÊ[6¬_w̺<Ëc@kìx8Òu]ŒŠÝ»öÜwßöÝ{÷q.Ö»~Ãqy§K8O³Tª$XïD’¬]X»ñø ³kf€Äˆ2HRÕívææf×®[³vaÍìš™ÞT·ÝmÏÎζZ9ãDÑjµ»Ý.¡´¬ªb\®,ì_<°´4Ãáx\xa1bˆ‘:µöÖED¦ŠªÖ£¢ZZ^9°¸´ïÀÒÒòpe0Ú»wñöîÝw`8QB…`RòÿùÏ?ö±XžqÆ›6múð‡?¼mÛ¶………w¼ã{ÜãÎ>ûìɳ½^ïöÛo¿ûî»_ýêW#âŸøÄÓN;íàüµ×^Ë»ä’KæççÆ>fHØê%oܸñöÛoÿæ7¿y饗ž~úéÿøÇ{½ÞŸýÙŸ¼ú´§=íТžþô§w»ÝÉÏÕ[yž_pÁú§Úï÷?ò‘Xk/¾øb!DauY­^çÕ™„‡­Y³æIOzÒwÜñï|ç Ý2a"ÀË.»ì´ÓNû©gDΫ¿÷ÔSOý¾0iÑš5k.¿üòSN9å‚ .88}\EVÔèN8ᕯ|å·¾õ­ŸšY~à˜™™yிþú¯ýëÿí3‰›o¾ùE/zÑ3žñŒÏþó”Ò¼à{÷îýò—¿|P’÷ÜsÏÁ›'Ç}ìc?õ©O=lÉçwÞM7ÝtóÍ7_vÙe^xáW\qøã÷)OyÊÇ?þñ-[¶\vÙeO~ò“¯½öÚn·›çù‘kû‘… 6lÙ²å[ßúÖϾyófïý¿øÅùùù«®ºªßïO¾›=ãŒ3|¿÷~ëÖ­GØ ‡£“9õÔS˲ܶmÛä§âÐ¥ŠÉØ<ùä“'ß7>Œ±W¼â01`¶½«s„Ò8ýôÓû·ûq{ÜêðË^ö2Îùõ×_¿J5•Õêœ{î¹Û·oÿ™IÔÕÞ?ü|°níiOÇ“Uç;v¼ìe/›X/ÿðÿpè2öòòò–-[N;í´Érûgœ155uÙe—Ý}÷Ý“ÕßCK¾é¦›à™Ï|¦RêçÝ?sõ’/½ôRïý³Ÿýì²,oºé¦™™™W½êU‡Yòê-:tyþ‰O|âdý¡}èpdµzWçž{î¹çž{6mÚtÅWlݺõÁÏNø3›y$r^ý½ozÓ›¼÷ÏzÖ³&!dãñøúë¯?ÿüóï¼ó·•Õ‘óíoûØc™™ùä'?ùº×½îЬÛ·oïv»!„ç?ÿù¯}ík_óš×üíßþíïLbË–-/~ñ‹o¼ñÆôûýmÛ¶]xá…ÓÿNOOãßèv»[·n½ãŽ;Þþö·ONNÉ¿ÿû¿¿mÛ¶¼à1ÆÏ~ö³'œpÂsžóœÃ¿o{ÛÛ¶oßþ¼ç=/Æø™Ï|æ„N¸øâ‹¦3êçÕöGo,<,¿þë¿þÕ¯~u<ß~ûíœóg?ûÙµ?÷Üs·lÙòàû«ªš8ޤV'òøÇ?þÅ/~ñå—_^×õäÌüÇœy晇."Àƒ³ì<k׮䋚››+ËòyÏ{Þ7¾ñÃiïê‰4(¥×\sÍ•W^yï½÷®ns¾êU¯úçþç‡Êñó`Y­Îºuëxà‡2G½Þ?œ|(Ý8r­;Ê/‹ƒ%ÖQ©èfIÖxC@Œ h®’©n7ZS‡,"z+S©à”P À ß7\,ƒîÄ~¯×oem®¤ >ŸbÚTºÔ52€H £JrI1A…àÚc#'Ê©à\ D(ë’¬,9<„¢,·mënܸ®×mS @)!t݆ \J|©Íp÷.»ï@wv¦•ä3Ý©öíÚñãmч¹¹5ÑWÓºªê¢.¹Hdôž ΄ ”J¥¤”Q0>35UŒŠvžÕUY5uS‹>0BÃÉwr”@¡Ñ5F¯«zT ›²Ê” K‹+ã±j²3D«ÕvÎ!ŠsɹP2OÒºª­n(#ŒóZ×£wNk-… ”Eˆký¼i¯]°žF€9ít$UUG#çì`0NS¨ÊR ” Þ›šNZíö$õNÝTÝn[ !¹ˆ!k¬”3¤$Äè­”÷ºí™îLÞNëºÒZ7MS×5çÜù@Oò¶²Ýêdyž$<ÄB4ÆJ)゠ɤ¤Œe\*!çœ ˆÚ{Î9Wiʨ 2`œI"³ºÖ¶˜bšæ’QF†è‘2*%GBÀb€B0çݨ(†£‘׆S†!../íØyÿ¨@Ý4½©þüüüôôôš5ktݸÆüà{÷„0 |õ©Ãü>j­;Ö¯_ÿæ7¿yÿþý[¶l™ššzéK_úº×½îÒK/L=c1Æ^¯wÚi§---!""N2œuÖY[¶l9¿wÛm·js®®“?õìç>÷¹Ÿisþ'´ýÈÇÂ÷¿ÿý~¿h²™Ã¡Ýn_xá…“›·oßþãÿxóæÍ›óÖ[oý™†ÜÁÙÿ‘ôÂê:y¨õ~óÍ7å+_94þÃþðu×]÷þ÷¿ÿæ›o>í´Ó^ÿú×7M3Ùáúp(ŠâÊ+¯$„ÌÍͽð…/|ç;ßy×]wíÙ³çaÛ»º¶‰4Þð†7¬]»ö=ïyÏú%'†váÏ’ÕêpÎ*†âQíýÃéÁ‡Ò#׺£ü"q`yQõ2Ò‘ALJÁ02Éx¯ÝrÞ›ª ‰BH Ñ#0F#!ƹÆèíÐ7CWõm?MRJHÚÍò¬µ|`Eé&s¹#è"">‚Ç0P @¸u1hækk*£†H£ö†›JÙ„0Â(£Áî]»ºíÖT¿'AfÝvßÙùcŽ••EŒFÎXt®7mšzçž;~|Ÿol·ßgŒc––—"`¢Bô€c¤´;Õ[wì1í,e„êZ6¬ßPWz°²2´i‘%ŒEB1 w“R"@Äh¬uÞ!`Ä蛢ˆ~Ä9oçùÜôL’$­s>ú@(´¥±Ñ PY‚ˆ”1Ê™C¤RpÁ9ç½^oM­½õ^;ɸ3zCÀ¦±ÎùT'„R*„#$rN ELÈcY•€8 Ö^HCˆÑ¦¬+cÖÊe’RÆ'ŒÑ¥•EQ!8cŒ á˲( ç\ÄØêt¤T”²VÞjw»”2@@ DJÅc„%I*U*…JR#U‰âœsÎe¢œs.ØV»Í%G@ŒÑzÄ„,MÚy;ø§ùÄÏ c@ïüh<Ž"ƸP:gªÆ{çʲtÞQFc>„¥åekm»Ý–JÕuíbHTâ¬mµZyÞZXXØuÿN%•dB1ƒ ͸vч „+™(mµCOs–f)¸в—eže„ á4mç2J(ñ1x(¥BÊ,Ïï=ᆘR"’Ä#”M3ªË¢nzÝÞÌÔL»Ó¦H²¤Ó±Ö:„踣@ç­ÊÓ$KõÎ:ƒ§„$B ©"¢5¦jj#"ïäyžµ[­Cð– :®Æq¿Ëƪ×ép®„b.ºa1*êq–%Æè¦®0FÂa8îÞ³Û[“DZ#ƒCDâ½Ù·ï¿ý[ص÷þuëÖ=ö”Ç3?ßï÷³4á„BDàJµ8;þ„M2͹H£Æí_â<¡D`ˆž¹:Úz¼ IDAT:hbpÁ9ë…(±Öµ±vòe/å<¸!F1F¥è½ ‚3ÊA!¸J$ç #:ëc „S–§Yž·•€Ê$a$†|¤„8«ËBEQ7Ö¦ªjmM¤L2J#Fïô°lNÆØÌÌÌæÍ›ŸýìgÿTœÒäàì³Ï¾ãŽ;ƒÁı0Y0Bt7½üå/×»Þu×]w9ç¶nÝú;¿ó;?üáóïÙgŸýÕ¯~ur|ß}÷mÚ´éPGÖ*%/,,­tàÀÃÿ‹¿z‹rh\ëaÊê¥ñ?©©©I œ ÃáÐ9÷àúËêa÷Á~ðÿð'™*¿ÿýïÿ¿ì½y°¥WU÷¿öÚÓ3sîÔ÷öît:“€¼j^±^¨`•¯&%Š ” R”"C N)ª!RLV’RB(­¢Ë@EПXþ’9žîxÆgØãÚ¿?¿®®Ü4‚ýùëÞ3ìsöÚëyγžµöwͧ_3ßö¶·}èCzò“Ÿ|óÍ7?J¯{”òž={.¿üòyÆææ›oþû¿ÿûÏ}îsó®3³Ù¬ªª£G^xᅣѨ,KÆØÙHÈ âÚÚÚ™¹gzûî>9ïöööéÇÏüûÑxûwäX ¢sQù¹Ÿû9¥clÞ1èèÑ£?û³?«”rÎ!b–eßú–Ó!÷9¯Â#ú䜪ªþáþ¡mÛg=ëYgÆÒúЇ:ôªW½êw~çwî»ï¾_ÿõ_ÿÄ'>qösošæºë®›ÿýŽw¼ãî»ï~Ó›Þôâ¿øç»»·Ÿ³5æ?^õªW)¥”RóShY–ý~žô>ÍK_úÒÉdòéLJ³Õî ‡Ã‡Ë?¦«6+øp¾ñè½îº!߶޷κà˜@ëõƹRªëºkj‰œ3ctÁ£șΤRš#†;ÛÀ ßïEBpÎzïóRéªêiAbJiÆCÁ°iqq‰#c •RóæœY‘C¡¤à"ËtQÖYÜâÒR–k€D)µÝ´é¦œCUVl™I.‹¬bÞùSŠÉc½å\0Æ“(|ðÎYcL¤¨´R\p‚¨ëº®ë¦ÓiÕë…î¼óÎisccïêZU”¾³ˆXUe™çÎL`œïê&¦˜¾ÙÙ“ !‚ 1QŒÄ !…”ˆ,Ƙ Î¥VJËèCˆ!F 1x8bYUƒÁBYVÆg]ÓuJgƒþ@ê ¹˜N§³¶”bLÎú"+8Ã2/òèCJI™imƒ(9!K!E"R0މ¥‰CÈr=X,.ª²2¦›NFÆu[C3™`žgöôªb”l°Æ¶M;‹€H(6mc†€Rɼȼ‹‰X q2ÙÐnn:qìØp{xäÂ#‡¾`ÿÞ~U ΕLòœza°´´´„Á§ª,˼Ç(g3! éZïP"Œ)Åà‚÷ÞXC‰‚ Béè)&@`€Œ±”Š"Ë2ZH‘¹8‚Êd¦³àÃt2µÆsd€$b®•"BhÛº®›®íœuÁ…®ëÚ®³Æ†r•gºÈ¹\K%%K)øœõgsÆÛ¶½îºë^÷º×=ä Þþö·ßzë­OúÓçw—¯¼òÊç>÷¹g¾àÃþð‡?üá#GŽ\uÕUoxÃ>úÑ>ñ‰O<Ë“ïm·Ýöô§?}þw×uzv—‘'“I¯×;ýÊ~¿ÿ ‹ ÆØéó<ÿ¶f4ç[Ó>h«Giÿ†´m{zìÜ’RÊomÖòX÷VùøÇ?þÆ7¾ñ'ò'ϼ¾Puö C»{Ý9ó”§<峟ýìéÁ[n¹%¥ô´§=msÞ{ï½s‰ù.¯'<á óÀì‡%¢Ñht¦‡Ÿ)ã´»OÑööö™×è’€:goÿ Ï|æ3‰èõ¯ýé<^QW^yå-·ÜrÕUWí^]yΫp6>©µþÛ¿ýÛ•••§<å)ŠFRJo|ãßøÆ7æyÞuÝå—_®µ¾ýöÛÏásG£Ñ­·Þúä'?yžj~ÄÚÚ]¼ýœ­qèСªª>ðœYÐ~ÓM7=zôðáÃgž–Ÿóœç|èC2Ʀ«ÿm­àƒ|ã;èuçù PhM§LçQ"ðQ¸TO§]Ýç1klŠQd9ôÁÇHÀSD-ƒ¾P²³¶iÛn6u]‘峦ٙM½A¾X`¡• ukëÖQç¼ FpD]ðRºWª*œjßÛññ­ã$ÒÞ{‹2Ï‹BeÊ9;™Œ§ ƒ¢¬rD…®ý²ßRY㬱U¥úeYæ™’\‘8ë•¥*r"±$”h­áÈCJw[ÃN[]Yæ Ê*˲¢È‰¨®‡£­í­ñdÚ§U†Z…޹äBÍDÆY"/Š^U2ÄÑdškg9&¦3Þ .RJJIà­™Æ ¤ÞïÑ ¢ŒyOaJ)®$ ^”å¾ ™‘§Íõ­Å…&6«›€œI©MW‘®óC‰fõTjå)HËíXgm" DŒs¥dÙ«T¦užËL )±M= ÞgyδmS×u]7ZçeÙã\fy.¥L‰qέqRÊ^^pÎÀòò"£D”æ‘cLHäGŠZ«¢*ª^)ˆ¤—–„!¢HÉÖ ¡ä™RsÕ™Lå]kœ1D)„h‚K%BJÄ9ˤŽIÅbðiÎPºÎ0¢Ø5­wŽ ¡µ‡_šþç±cÇö¯í[Y\.³ëLÛu yÇ‘•EÎ0Κ¶­ckÚ=ÅØYODJ ``LG1°”¼ ™Ê @ÆBÂH¾mkººÆ­íñÎìþ»>táe—^ºwm­*ó^¯š×õÌZ»3ßuǽۛÃàR™õö­(´ ]3]ߨØÜÚœÖë„àÜyC.Î%—ιà2É€#WJ Å9ƒÅ~ÐÏ‹ 9 1tÆP (P+í’…”RÄ ˜„@dM[O¦£ÉxRÏê¦iºÆP"DN”8yÕË2à€¹JpžBô11ïüÙÖÖþÛ¿ýÛOÿôO3ÆroÒ%—\rã7ž.gºòÊ+r{ï½÷úë¯ïõzo~ó›9çg–?Íf³35KÎd:>¢ÖÅCŽ|çw^qŧ_sæN›y¢”ZXX˜_ֳ͜ý¶ft¶:kuîg9ÚÙxÝ90N÷îÝ{f.ˆ1vZwäóŸÿüë_ÿúµµµ ø™ŸùxP‰òÃño|ãIOzÒ™™«³÷ɯ~õ«gzøwÐÛý±°¸¸øìg?{kkkwáÓe_¯¾úêo¼ñt-ýü·ð™Ï|æ-·Üò/ÿò/§ã«EÈg¿ gù­ä“Bˆ¿ú«¿zÜã÷Ô§>uÕyÔ÷²—½¬mÛú§:7ãœ>|xÞVäç»»·Ÿ³5n¿ýöù©`ÎW\qýõ׿îu¯ûô§?}æ{_ð‚Eqã7>èsÏÒVÉG?úѾð…¿ò+¿òÁ~ðAO}wVÿlVðA¾ñhŽýóüæ9»¦0Õ²LKÛÔíp;=±=O¼uÈ4†1VªBK\$™kˆÁ¥Ø:¿8èWEÉ”2MZëfuã½½ô’#‹KË,CÎxòàYt,Dž0‚T75!‰£R,ò"8-óÓnb][š lm޽÷UUƒõ©OýÁüÁ;ßùÎ'>ñ‰¯xÅ+Î|ï—¾ô%ø£?ú£·¾õ­?üÃ?|º7÷é8j—íÎî¶:kœËËËó¼n–eEQÌ“ “Éd.×ùhì¼;øÀ>þñ_{íµo}ë[WWWßñŽwœ4†«¯¾º(йÔäUW]µµµuÇwÌÚ¿ù›¿ùÄ'>ñÕ¯~µiš'=éIo{ÛÛ¶··O—ξÿýïÿÌg>3/®¾úê«_óš×üã?þãW¿úÕïÂåÂ.ßùcûØk_ûÚW¾ò•7ÝtÓ»ßýî”ÒéÄËûßÿþ×¾öµïyÏ{~ó7óðáÿÿû¿Ë-·œeœ|à 7ÜtÓM¿õ[¿õ‘|äÊ+¯|á _xö>ùö·¿ýæ›o¾îºën¼ñÆùN³ï”·?úcáÀþçþ¥/}éìcΧ<å)KKKŸúÔ§N?b­ýÜç>÷Œg<ã·û····w¿›p6«ðpßjwŸ¼þúëŸõ¬g]sÍ5W\qÅéÛa_øÂæaÆþýûá~áŸÿùŸcŒÏþó_ýêW¿á o8½ýɲìçþççç_þå_>|øð\»øç»;çl¦iÎ,¹ŸW´Þyç_þò—Ï|ïoüÆoÜvÛms¹£3ÙÝV»ó‰O|â3ŸùÌ»Þõ®”Ò'?ùÉ^¯÷¢½èßøÆG>ò‘Çtõw_ÁG<_ó±žXÆPð@ÑYÈ&‚(µ$H(9rÄÑhÜu”’b¤H1Ž"zJ‘€GQ–=Ž‚(QbÎ¥TÙ«\´UU)”’ñèÂÆÖæÎööêòÊêòÊ|£¡Ô Û™§Ó)×"«r!yS×£ÙÌ[‡ÈU¦…’Ș”<+òÞ`Ò˜f³Y¡$‚EQ ú=)"RÆs>DŸ€…sB¸èˆHJ©¤VB¥CVèAPÏš¦nºÖ4u7Mª¢$]myâY¦‡Û;£áÎÒòÂêêšB‰¼¿oíÉO~ÊÿþßÿçÒË Š‹)KÀPp"²ÎYc¤”œ 1øè‹R­Ÿ8Õ´3çm$"J Hi]…b5]×™¦õÆ)¥mÓŽº)K — “PL³”…(¥È„Ö\!™\ ˜brÁPŠ,¡sîÁ1ç5×\sæ¿ó´Ìg?ûÙç=ïyï|ç;_úҗΟú¯ÿú¯Ó¿¸¯|å+?þñÏ‹ˆŽ;öº×½îÌz*"zÅ+^qZIâ+_ùÊ ^ð‚}î?øÁÿñÿ“?ù“yægqqñlŠ©vù–[nyûÛßþ¦7½éMoz“sîÝï~÷ïýÞï™Û¹á†^óš×¼æ5¯9qâĵ×^ûgög§ŸÝ}F»³»­ÎÆçƵ×^û’—¼äô¿óº¬k¯½öt…á9Ûywþîïþîÿð¯¹æš×¾öµóœÕ³žõ¬ïT=êûÞ÷¾Ó­&o¸á†y€4ÿ ¥Ô{ßûÞÓ›lÿõ_ÿõå/ùéé\tÑEs©Þù‘ó±}ìôr<Öìòÿøÿxaaáï|ç\÷u}}ý…/|áéKó£G>ÿùÏÿà?xêÔ)ø÷ÿ÷_ûµ_;ËýË¿ü˧=íi×]wÝõ×_?®¿þúßýÝß=KŸüä'?ùêW¿úšk®yùË_þ¥/}é oxûÞõ®³¬…Þ}äïɱ0/¬ýÌg>sæƒ7ß|óÕW_ý£?ú£óN?»ðhVawŸœ'ŸçÊF§¹êª«>ùÉO€”òÍo~ó¼LÝó§ú§'«óp·œæò]MÓÜvÛm/yÉK¾5Ëw<k<"?öc?vÅWœé¨JÔ?œ­v'¥ô‹¿ø‹7ÜpÃûÞ÷¾ùoçæææóž÷¼Çz¾»¯àî¾ñ˜Úù<ßwdZ"BŒngk+ÆŸŒÇ“ñØY·§·DžÅmgƒ ÁQÖš¬,ty¦PKÈ$8­ïŒõœ± ë6‡Ûª•:ËËr€ZæUF …wÞ'G,%„&´ÔFÞ1Û™™k@¡.3U(.9ç¼®g³é:Ť”.Ëj8­®®¥Ä€A¯_]|ÉÅ]Ó­ŸZ?vÿQoíâÊR‘åµíœ.ú™ig¶ ,õÒÒ¢÷>øà¼gŒçî¹ÿ¾fVŠ*WºÈòª*sMÆÓ¶kCŒBˆ¼(Ê…O4jgŽˆ:cˆ"…Ø…‘÷.„aÝH))%Ç`m=7Ó 8kû}d¨”쬫›:¤„ÈÁGï|0`ðÍ’ïÜV»µ½±“ë|ßž½ËKKBH TU½¼(óFŸgª*Šádº9çeomuµ*roºÉÎN=kË,ë—U™y‘·ާÀ¸p!tÖ¬íÛGT®9ò¶i›º‰>öÊÞû®­¬yQ@ʲ|ÿþýKK‹mÛÞzë­wÝs÷©õS6z]h]hRJ*­'“áÆ©“Ít¶ØïRïB)¥`£ŸµMmŒó~ÞmBk½¶²Zõ{eYi•Ck—2øP–UÕ«RJÓétssÃ:›e™àÂZ›(´mëcÈ8)±¶ë(F)e¯ß€Ùl,% )"CIÁ2Æ‘á<Ʀ@ÀQ ç‰È;ç½§÷ìÙ#•OFÛÛÛœcs%]@`šËÕ•=ý¢—ˆBŒÎ{ãlb,$â\.,,\xðÐ.ü<ñ‰¼paÐSŠq]×~æ3ÿø¡ß´±µ…\p¡|ŒuÛµ]×[è/.-q)ŒëB  ëõzZJg2†À‚àÈÓv2Æ…`œ'J­éº®£”²<«ª*+sühg§­[rQJ¹T…ÎçZ©²,{ý~¡ïBÍFuW»à}M[kSJ1F‚ova‰‰¤Ö ‹ ýAŸ >Œ•ä@Ñ;K!Ekºâ…TRpÎ{e5 2Yk=V×3Ši0X¼àÀ .¸`¡?0ÖÖÓÆ4v:n6NmrÑþ{St÷Ý{ïÑ£÷Yç´Ì´Î—×~ú§ÿﯸdaPà@ æ]_»ÎŒFãÍÍãÇß~ûmwÝ}×½÷ß?™N±ì•£áx}}Ýy_–Åââ ¿Pnm­o·»®KBÉ,ÏúýA¡Çzïu¦ë¦Ó©·®(ŠÅ…Å"/£·Îv)Q—êzþ IDAT !Å@” &–åÅââWÒGß“XÊ ]T%"kºn2íÄ·uÞ$¢‡SD!ì.wqôèÑ£G>góÝG>~üøñãÇàLáŠÓœ8qâ![‡ŸÍŒÎÙV©5¾WÌf³y—Åï&mÛî"ù»µµõí^ô×lµK•¯1æ?ÿó?Ïmä“'Oî²ùíá|R)õøÇ?þ+_ùŠ1&˲_ýÕ_ýô§?ýmÝgÙÝÛ¿…s^…Ý}rw¼÷gJmÿXã{Ëx<žï¡ø®Íw÷|Dßø>µóy¾ã”™F1¥H!ÔõÔt­R²ÔUŒqޔƽ Þ…D  y®eJ!%ãóv~.—…ÌŠ2¶&8çÚ¶cLE‚¢ÄªW䀑À×Ý,1 –€#¤’«² º©ÙØÙ^ì-,^\XXTb=úàëšöûr.9çkk+ˆÈ÷¬.ÿÄO<©«ëÛn»­n[Gd:[wmâ¬5M]Ï,™IJ¤•Z[[ÓR‘®5*Ë…ÒLH‘g Ë+¹¨ÈtpAJ%•.ËÞñ“'k2qD`1Ï2¼“’k¥råY.9‡Dc¤˜Râ‚SÄd¼K\ô\¨,Ë:ãœqÖyJÉ´&ëç’ †¨”rÊq.T¦K­5ÀX¯×ކ Œ ûöí ‡ýªÜ·ºÚÔ³YWÏu}¤`•šñÅ~•œ'ë]kÚùÆQï;o}J ‘Aˆ˜Ødîq€‡ÔY9ÏyÎsžó|ÐJ ɤ@±‰¡«k)ÄÊÕî­ß{’ qΕV1…D‘xÂä)2Bˆ„ÉH ­s³à‚w¶¬J .Zç¢Gg)%\õªJ*™kµ²²ä6Œµ¦i%CDBeeŸ“ ­MÆûI3K t–sÄàBp(Ù¶»ûÎ;óe3]×Ô5EÊ‹<$"H‰1d€Lr.÷Á—e™gYôÑ[ïKÀƒCÝ6|¸cƒWZI!ûÕ *ª\ð®*K@V7Íx:m5ÆÄ)iM×v[Û“ñ0xÏ2!P MäMë‚RJ^–θY=ÛÞØ^,.-/!¢µÖ;ßuÝh4ÒZçÜ'y†J¨\ý^"b[× gã•fÚäªÐ(pÖNÛ¦+g³¶ínýê..,)W+™ ©%‹@ó®EŠtÕëˆ)ÏsDvï½÷t]¹R{×öDšºnÛV ‘ˬWT”ˆqŒ)Yo£' ‰kÎF…’3!¥F䌡"AŒD”BL  ¡¸ QBÎ ÅH) Áż·°`!d¹þsÞ{ï½/zÑ‹Mêò<çùd<ÿÐýÐW\±´´têÔ©O}êS'ÿ{žóœç<çy¬‘ˆe®¹æÍp:ÜÞ‰!\°ÿà%‡.Ê’šlŽGÍ(¦ ”àJ!!…È¢Äc„”΋~¯sÝÎx§ikÓ5ílÊ )-:Ûy”v.•ºÈò,ÓÎuÞÛ¶B^äˆÈ%Ι§ˆB°[cŒµ uÍl²3òûM^õ67·o¿í¶²,/½ìâ"×Á%Æamßê¾ýû6¶¶ë‹ \ÉI;“QæE^ÔÓ­Ñö´™Þï}ù¾}ûµÒ*ϤR „õÁN§pâÄÒR¿_Tûöì]]^ì÷«Ó7îºk}s;!ö‹Í&ƒªRZPð)„yãÍå=+i:3ÞçY¦•gÓ±ëC!´ÐEDô.0!Š²ÒªB wÆ]gªép²3ÜƸ”B )”±Ö‡(D£•ž6õÖÆÆæöfŒnÿÚZ;›m¬ŸªòB!#ïÓr%‹¢ÐR° …8MÖ'SŒÉv¦më0¦•B)‰ƒ’¢,ò,ËLÛµ ÎÇ@Öyk1¦Ìò…~ÿàþý—\rqkŒíšL=xk¢÷1$ލ¥.‹ŠK#x žb$—¢%ò ¾ÙA4RðÖš" .užóL(!¹æ1䂤HH0&²¼È‹à]¦µ–Êt P Þ@Jȸ,:Ÿ‚—™FÆœuÑ{ãlˆ‰;¢ÔÄžÜÞÜjgÍt:òж~–_?U›Î…àCDŽZȲê'B(Ó9—ùòÒ’Þ+fÓÙÖöVô>q$"HÀ$1†PϦÖuÕ ¢b À:ã‚ Rï]Š)d±’œ%hš&ŒÇ‚‹"Ï{½jÐ+÷¬,k-gu=µ@®¸àU…\hK®´ÌЬäLú`#D>2x@ÖI&—Jñ”R;AB%Æ›ºFÎ۶ͲÌyo½³Ö"&HÓ¶¶>¢¬Ê‹"WB f<`DÅË… ÜÜ<Ù4ÓÙxflsòäÉõõSÇN}ÂýOxü>îÈúE+Ë+k{׃>"ó>Fïó*ëõ{½^5ôW–—.½ôÒª¬Œíî¿ÿ¾D‘CòÖ­®ì ‘†£Ñöp‡ó¶ÏûŒcˆ1†È€1”R3ÆY"ˆ!ã:/0ï%@”(r!¤dR":ë&8bpDQ(I‰Î×Öžç<ç9ÏyÎsžóüw¡žN%OŒ3Ûu½²X]Ý“çùh4¾çÞ{·wvŒ1ð 8â(%O cŠã *2’M;u® Á;g( ‰|¢.€7-:[Ú“·./4ã¬nfé8Š`|´1!Gy–Û"l&ílÆ<ÝsÏ=ɸÑpÔL¦#¡ÇÃá‘#]räˆ*r&¹s®iL™g ¡èûöï½ààÇNnLêzaiQdÒEÏéL™……*TãzZ×u–ey¦³í<.MFÃÍ $7“åÅLl4#cY–AðÞÙK@!FLÞ:Óv]S¥í­$EÛ¶D‚—’OgS0ðE¢ŸµµÑZK‰é,#H‰%JÉzË8,,¬ìYÙ³gÏþýûÊÒ;?«gúX8º=Ž½ã ½Í$çFBLRDH!÷Â#r@†(”H ¬µ‰’2¥Ô¶ÝÉ'c ;;[>ض­ ×YU–˜bn:Ϙ(Åè YÂà"Å„ ”ÐŒJ!@d,rFÄ"”=”Q¥P’\dJgZK.€&`Þ:Ó™à=G”BPd(˵Ε €(¥”Rb‚s&5W¹ˆÂ‹`4m; ¡¡ñ5ãl6mq1%Îe^T‹ {²¬”(‰™Ä¢(R°¾žÖÑ¥&者ì•=ß·õ¬i›š#. öìY™LÆÎš¦žzë1¢À8‹”8pL0O{»D1†H”¬q>zÆc 8¦#c1±è}ÓÛv,%“µ‚æ”ýª¥”Ƴ:Ìw5zëlgS$-/ª\k)x >Eç"‹\j-UJàC\É”¬³Öº©óEYÄHÆ9lš@äCÐYV·MÝ4sqÞUY^•UY(j°ÔõŠþÊÞ彬îŒ6¹cLÄ&³á½GïêRs|ãØÚêÞË.»ä’K.]YYÖ…JŒaÛ6Z«#Gެ­®^|Ña!Äd2îêÙ©Ç%猋2/ã‰è¬àR„Dm×"@†È°”ržA"©T^•1˜Kž@J”p.¤RDÉ{GŒ1ÆEB(Æè!E.¡nÚó1ç÷+Bˆƒj­?þ ÄC‡ÅNé±ûÜóü÷¡,˃~»rç9ÏyÎsžï9]ÛP°í@²=K+‹å‚kÝ©ãëÇ8ÙL[$d (¦H(óRHdŒK†ÀRˆÝ¬ñ­åš+˜Xô!†¨„d’ ®1ã›è= ÑÔm´VHDΚ®ñÎ$êåY¯·(TÀŠSˆÉª›öøÉ“©uÔ:gÝx4>uòÄöæÁ¬,/Ú»€º®›L¦¹Î(.øƒ.¿ü²ûŽÛ¾mXä™Êô¤™gçýªÇ8J%·FCÓv'ŽŸhÛNª|0hµÖ4ÆÜ~×]!„Ù¬Y]^í=–ã,%êºv<ÎfÓàƒ1¦àc  ! ‘1m.z½o¦Süp´ÃH%¸à‘ ({!QL©éÚÍí­2ë¬1ŒAˆÁYÔy‘κ–yhÞK“# ÛÙÜY[Þ³ïÀ#9|èƒkk‚óáhTôû„Üú0N¬uÁ{HI“ÈS!Ër²,Cˆ1xH6ë=˜e2%b”ʲd E'…Ryž[kSJm×nllÔÍ,¥˜çYžgy^ô=iBàÈœÖ"§H SB!ƒÖµ)R‘ç’¡1-S*£÷Î;.„TZ™xçIVª(Ê<ÏÀYKs ‚yK©½Ië “Rr”’Á b¦µg …dœ³”(PDâ\dy^U•Ъ³Î˜ÎZ\ ‡H)Pbœ«L…RK K+ËË‘b×µÆ)¦LgEži);–@+µ0h)FÃédÜ™N|ócI 2Š6oc¤ µÎò„œcR*†œ"…!C–¥DÈQHCð!´¦k:³½3Xê ú«kškÅ6¶ŒsR Z ­T[7κL+)D¢È£÷‚àHÀœuÞÿì½y˜]U•6¾ö|ιçu«*•©T ÌT ³ð³”4>ˆ#Ú6ލ­¢Ø ¨>H«ÍLƒ vh4ÒD Š€(*(CƒdN%5ÝñL{þþ¸ÝõÔ RàëßÞ¿Î=ûœ½Ïzï:÷îµ×ÚkL¦„ŒaÒË'Œ1eÔ#/•Ü66Öj·ÁD˜DD¬T8£2ϦšS~­ò‹G¼³" Ê•²R;†%g§Eºqó†ÉÖĦM›ÆÆ·nݶm·Ý¿æ5»ÄQ©Ùl­_»¶Ûé,\¸`ï½÷ª”ËFJFI__§<Ëò¬” k³ÐZ¤µÚ:ƒœí¥# ˜Xgœëe½"¹ÔÆ9€<‡ôÐC:è 0 O?ýôíòÐ.[¶ì _øÂ>ûì“$ɽ÷Þûío»ÙlN·Î›7ï¼óÎ;üðûÝîu×]÷ï|§Wzë%Å~ûí÷7ó7‡rÈàààúõ믹æšÿøÿ˜cëòåË?õ©OÍìmÕªU×_ý_ðÇsÌ­·ÞºÇ{üùÏ~ž&ûì³Ï¹çž;11qúé§¿ ÿbÍY¾|ù©§žºtéÒjµºqãÆë®»îú믟yï,=ïPÛgÁÙgŸý†7¼¼÷ccc¿ùÍoþýßÿýÅZnø‹Ù˜]¢ruÜqÇqÆ‹/»îºë®¾úêôþþÕ_ýÕé§Ÿ¾÷Þ{'Iòàƒžþùs,ÆóË{õÕW÷õõmwråÊ•·ÝvÛ%Ú!¯âι’y·Ýéèï k6±ÖØÖ cÉTš b`¬¶y‹Ákò"'ÆÆ"Y·è6Ó 9Ny£Å ì"Bœ:ŒT7%08˼­Á;¥µw9œLuóZ&bÚKó⠔ŒqNB´ç€ãBɱñ±õÖåV‹’àQP(©”ŒÂ0 8!¸ÚWÛm÷Åûî³wcªœÅà €QRk¨Tâ¬(¡”ÔíV;—*"ë\½ÞOã¸H»­–GÄ8¿`З£˜3ìÁYg¬wÞ{¥M„pFŒ¥k¤5Ö9Ë)¥„‚õ&—&WÖY‰ „à‘±Þ{£œ)Œ´™3Ö`@<¢ÚÊ4±@åŒr°À: ë à|·Ó ¹PZ!JÃR©h^†A§ÚŒ·ÚÛÆ'¹9£Öo Rs”1Á÷ÞBgªÐÎJ£¥QÆ[L‰s> XÄa/µ %Ô{¯µðÀ90#T0棅!*¤õ(åœaЬ²€\Õj¬•,r‡)D,$a º€ N©w6Í3O€qN A€ÁQ  ǤT…’SJ Á”c&³ˆho¡‚ÆceM®¦‚Á3ŒÆ„S)u¯0L—ÊÕj\©A•Í”RFË:k½³Ö«ÓÆ™\T°»Î_´ë¢"OGG7qA)aå¸Ç¥Rd 7QÈ9sÞ)%Áû0õz_!„ô¬-{å$µTR)c,8Âê¥KBÈÊœµªy ž`à÷.(hAÐ-2hxí¬¢ˆñ Œ"Dˆó^i0Ž¢’N·iš= aŒŒ¢°(2笳Nbç(hê8%Œ cL('„ „•ªF£NG&I»T*!‚µñV#¥l’æÖ;mu–0L°Þö,K§¥ÉÓBYeÁB„ ós`uR)© Œ0§÷ª¸8D<¶ÖæyžÏ¬•²Ë.»œ|òÉW^yåÿ›ó«_ýêÞ{ïÝ›6½ŠÙA¹âŠ+®¿þú³Î:KJùìÊ¢÷ÜsÏóå€Ùžw8z½þÀEÑh4.\xæ™gΜ³tÐA÷ÝwßÃ?|Ùe— œyæ™ÇsÌ‘GÙ›j !î¹çžZ­vÁŒŒŒüÓ?ýSÿv%æ_ \xá…ûì³Ï­·ÞºmÛ¶£Ž:ê?øÁ!‡òùÏ~.­###'Ÿ|ò~ô£ikáe«túÿK¼ë]ïZ±bcì‚ .xæ™gæx×ÎhÎI'´dÉ’ûï¿¿Ñh¼þõ¯¿îºë=ôÐéu„Ù{ž]ÛgÇ‘GyÌ1ÇÜtÓM¡Ýwßý#ùÈé§Ÿ~ôÑGK)w’Ãacv‰fçê˜c޹ýöÛï¾ûî‹/¾ø€¸òÊ+çÍ›÷o|cŽ}Æg\tÑEwÝu׿üË¿T*•÷¼ç=<òÈw¿ûÝ—T^kíÌr»»í¶Û²eË.»ì²¹H4;¯â•†¡¡V³©•*As´¹yöɱ¦+PȪ‰0€T‰RÏBf¬Î³c„qHC« iK@ÂI„,eHD¡ÐHgVaA°äˆ7:·`¢ÈX—I«5ÆØ!bS´²¼yÌ5°$x°€Ë&RÒ&.Y`€bmìT«¹aÓFG0yµÞÇ®tÁ8]<² Œ†æÏ;â°Cœ1¿ôY·£dQ¤i®eÿ`£ÑPJƒCS‚ÁZÛévEÖëQ\B•Ëeäm*‹F·„‚rB–Ã’UÒ[ Îe€0F„Š@„8ÐFäY’v­4Á”" ĪA9ͳB* qÎc‚¥QÊ[Œ‰gcB8óØx¬òZ¬LjRF sàóÆ 8 Â4M×oÜ8Ðß_ïë¨;Dp•å˜ò¡¡>ž ÌEÞ¥Ýdlë‡á œ³Ö`ŠKQä³È‚ëÊ<3º\«„·cL ét:år9 "-M^Þyo]© .â„„„¡¤ÇžBDh_½R«Ä­¶!e¬D0ÖÚD¥‚&c¡b$0ÆÈ(= yP¤i–dã"Ï»ij¼ÓÎ9ðaTJ  !A @00ŠSà gB1ŽS†)J%€<Í Œq¥Réy8=6€­1fëÖQΘᱳ s•&EZæ•þ¡úâ%Ãv‹ü´UŒ0Ήó¼‹Â€Q„B>ͺ`tá‚!©¥1ƃ·Öv»I§ÛqÆZ©­¶„ «¼Qðœó!BAÈz‡¬AV‹0„@c,òˆ``4±kª¦¦:yF%J¨1†sÎ3Ö:ïƒ ðÞSF¥’ aÌ8ϵ‘P<ÁˆÂñ‚ ¥à¼w6Šç zÛ²0 IDATó™óÎ;¯Ñhì°uZ®—ú!_!X±bÅu×]wÊ)§¬X±âÙúó|ØÍùÜç>7s™`åÊ•ÿøÇÏ9çœÞ+3{ϳkûÑl6?øÁöŽO>ùä›o¾ùÄO¼ùæ›w’Ãacv‰fçê+_ùÊ3ÏÎ.Ñìl¼ŠWæ a„数Ͼ;™¤“ ä¾ÄâjTÇžÆNéTji ,`ùv·”\šf, 8õ¾>m¥CÖÏ9䬷<äa­’·’,˸'‚ Hžå€1¦ˆ¡ˆR‚è\æiždy–ç¹M¥c Ê0BA.‹f»µ­ÚÛ×WŽã¸w:f«]ï«!FÙ¢áau°$=òè£ÍVÃCµšM!"Ô#%y^h¥+¤TZ•P©TŽ+•rÈ™-Š´ÛÙ°yccjB0!U!U¡”tÞJEXï¦Z-£sð¦W"“ Πʣ(Ò’…BDœõJkADŒ N8Á ! Ö]†rÎ"Œ¥c’åy.;T*xÏQV¯×‹¢H“îääÔÿôX–eFcß}öÞuØ{Ÿe2Iò"+jÕêü]æ×ûúœ1ͩɀó‰‰1£U&ežçÎy«´Fig¬3ˆaie©T ‚Àƒ E@F0vÎ[d1Áˆâ¸TìŸÇ¹HÓ,IctTŽËÕ2FXcV„ ðŽR\­UÆÖ– Öð@¥NH[8g­waÆ 'eÎ8ÁT*¥´Î”$œeTB(fœp¡ƒBÊÜ:10Îç!‚±ˆ#ƹ- ã-Ljs`â¼WÊ*£ÇÇ'œ7ÕjX­†cЉRÒy"ÑZµ:-g›L±T9¢ÅQ¹Z®÷׌֛¶l|úÏO N‡¼u|µZµZ©`€ ç+%;v7I ©<Ø0(BB½CÆfàp–fÖCìb&¨G>Ësd­w†a¤e±µÙàœ×úúJqÄœ‘Ö:@„àÔyè$Ùød#Ï2Jéð®» 0Æ!¥r¹( ÎÁÄyJ0A\ˆ¸Vuàò"M“Ä*ƒ¬·ÈzðX«œg½* ¥uNigÒhñzÜÑÍLI)ÕÖyív;mwºÍ¶ÉL5ŠŒCC ¥”ÍF§ÝIŒQŒ#)=%D+ÈÒÜŒÑ3ÍF—2ºeB¾È¤÷¿é¯Ïë´“'žxúñ'žÎ¥­Væ/XØW­QF³,ŸݶE0àË•¡Xiir¥ŒòÞzŠ)%å¨Ä"Þè¶-²Àß :ðsƸžšyBIDyY¤yZd´È €çþ#¸dÉ’üàcccSSS?úÑ/^<Ý422rÕUW=ñÄ­VkãÆW]uÕvðË–-[½zõ¶mÛÆÆÆî»ï¾w¼ãÓMwÝuך5kÞüæ7ïµ×^kþ½è͹`–žਣŽúÕ¯~µmÛ¶Õ«W¿å-oY½zõÐkz÷»ß}ûí·O_¹téһᄏWœp.-^¼xÍš5‡rÈW¾ò•õë×ßxã„rµÃgžï}ï{׬YÓ›G~ãßèquä‘GN_0Mà³;ÃóÇ=âˆ#Ö¬YÓl6·lÙrÕUWÕjµ¹s5 ”R¿þõ¯Ÿ/D°Z­¶Ûíé¹àúõë`zè·½ím7nìMà†nˆ¢èMozÓK=Wx衇fÎï½÷^BÈÂ… çÒºón½?ýéO­VëöÛoße—]æþþÀ;ßùÎÇ{¬ÙlÞvÛmoûÛW¯^½`Á‚EÛwò](—Ë'tÒÑGýBÙxÍk^óº×½îÖ[oýùϾbÅŠ¹ß¸3š³_ú‰'ž „L¿e³÷<»¶¿ üéOê1°ó]í ³K4;WpÀ½÷Þ;su&Š¢£Ž:j.ãžvÚi„¯ýëÓg´Ö£££/µ¼3100pÒI']sÍ5Óñ±³K4;¯â•m\»vÚi£Ùi·»Ø¡¾J}°o°$"- B<åÀCÂ#JL¸§!â!BÂcf1ó…ISÙl˜G•€ØR‚Áyog¼^¯Qèœ÷€‘C€(%„F#Œ“@ð@p†AcŒ0BÈ8D‘ˆ‚jµR­T9ãyV8ç1&a•ãŠàA·lÞ¸yj²épÁ‚Pì¹×‡|è¢E‹Ëq%%¬1Ù Î:k­6¦ÒCìÛÝö–Ñ-ë7¬ß66–å9á¬ÇLð,ϧ ­u†qÇ¥¸Z©UË5Šh·ÕÝ<:ºytlÛÄÔT“1N) ¨¯ÖWˆ¢Hˆ^Za­m·ZY–+¥µÖÖ:@â`B{.ÙsÏÝvï¯Ö¦Ä"l ))§°õà\kª159991Ñl6³4uÆq* ÃRªIóÂy¯µÛ²eK»Õ2ÆfY655µaÆ ë×oÛšv;E–zoK¥°¿¿¿VD•ržA§cÆÆºÏ<3úÈ#OýéOoÝÚ|≵þú·þä§ßùçï}ëÛ—^|ÑW]¹ò®Õ÷¬ýóFçÐ’=w;ú˜#Žý?G¿õÄãþúí'wÂ_|ðA##»Öû«¥r—£J¥„,ŽD((BÎ{‹÷ÆpB8eœò€Q•ÂRFÿ­_å¸\­„Q€)9ç­õqWâj­2W?ç¢E‹|ðÁõë×ö³Ÿ5Æ|á _øéOºï¾ûö,<ðÀ%K–\~ùåk×®]¸páW¾ò•×¾öµ‡rHïÞZ­¶zõêßþö·ùÈG¼÷oxÖ.]:½¿råJBÈé§Ÿ¾`Á‚騧9†„ÍÞóÈÈÈêÕ«ó›ßœqÆpÀ7ÞX«Õ¾õ­oM·{ì±3»zÓ›ÞT­V{g—J¥ÒÑGýÍo~³¯¯ïŠ+®PJ|òÉŒ1kíì\Íþ̳£644tðÁßyçøÃ¦m­zžsÎ9K—.ÝîÞáyöq÷Ûo¿»ï¾»'ÑÐÐÐyç·Ï>û}ôÑÓ“­Y¸Ú™å›o¾ù½ï}ï›ßüæŸþô§ãw¿ûÝ[·n½ï¾û¦Ÿê±Ç›¾¸w¼ï¾ûþð‡?|9§ûí·_’$k×®{ëE]400°iÓ¦k¯½ö׿þõ:òÈ#o¸á†›o¾ùœsÎY¾|ù\0÷÷÷ðÿñÆW­ZuÎ9çvØa+W®¬V«¥Riçµ}çß…E‹­Zµêá‡~¡á+V¬0ÆÜsÏ= ,¸ì²Ëúúúz{}<ðÀg_oŒY³fÍ‹¨9»ï¾û‡>ô¡‡~xÚÚyyt’rÚi§@ÏpÚ¡¼;Tà—ᙟÍcl¦±Úû¥Ú{ï½§÷F΂#Ž8bݺuÏ™Díeûö?ðPJ¯½öÚé3s—èÙl¼ŠW(´ÓI§Òv€CƒJTåÐi_¦ÓÖ„;îÀik1ÎyÌ8¢‰n™2”£JDc˜(rRRjð@£’SÎkkŒ³Þ!BÜo4ÞY‚‘ Ü ÁÃ[„F!J© 65¦›&ÿõÔSûpÚ?4Ï:€ËåªRflÛ„`¼¯VsÆ‹P,Þs='¦&s%Ó"WJy€0 i h hx" E1Ƥ”i–Â$rÖTJa% +•JȲ>é¤f›Q-D€­"Àš0Êáà1§Ô9[äÒÄè-èxï€R†a©Wªcu.sŒ)&#˜à^0-åŒ2 Êl´ÔJ[c¬åB„Ö"ðc ¤Û¸ai·S¥T½op` %eš&iÒ5JV*•R\î«×wy‘²ˆÆÇ“4q»œJ°ZåE¡Ê1FBpB)B²ÖFxÀ %=òIžæJr.(aÎYo B(Ïó$I”Rã ”P„ Ï2£¡ÄZË(ëå@%„PpÆ*.„x9*õ «­Ìs Ä(g ¥0!€‘À”†¡„ *·Þ"‚k,$Bà¼7ZZ)k°Ö„Q­­±Lñà³Ìç<Ì ƒ#mBp9.‡aÉXçæœk7lÜàSR&i2²hdÏ=öÄà7mØðÌÓOMNŒcL¹òBnÝš¦i\*k£(Œ¢°\.W«µ $IZPÊ fŒqá¡Ès!åÌ{¯µ¦ˆÀ{k¥RÖ9B ÆXkÍŒaœU*yžƒr”1Æx D¥RQJyï¥R=óUQ*•(¥uç!Îû4M›†ÌЬÝÍ:m•çH»€‹jXÆò4UÖPŒr­t‘çZB9!Î;kÂc„0Aˆr+£€PJŠ"§œ‡¡ˆÂ (d€Ày<2Úi™†¼£i"-÷AU*€18o”Ì&ƧŠD…aÜWë¯ÕÊq¼ÿk—´ìµ•J9™unþ.ƒ•¾HÙlll aá¼kµ›E‘§i’æ)B(BÓË]¦´Ñ†0Š)vÅÞ{kÁó€|¡ pFå§‚³@xsµ9Ï=÷\¥Ô±ÇÛ[é¹÷Þ{ׯ_ÿ| g½üçþç-·Ü2}ñÔÔÔªU«–.]Ú[n?ðÀëõú9çœóÛßþ¶·¾;³çn¸Ž;î8!Ä ­Ÿ9{Ïgœq†1æ­o}k’$7ÜpÃÀÀÀ‡?üá9ö<»D3³ßð†7ô&З^zé\¸šý™gÇc=öØc-Y²ä‚ .X³fͳïíøœbî ϳû¹Ï}Îs 'ô‚Ä:ε×^{ÔQGÝ{ï½;äjg°jÕª÷½ï}×_ýøøx__ßÚµk—/_>J·¿¿ÿ¡‡ªV«kÖ¬¹óÎ;¿øÅ/öN¾œó†×½îuï{ßûÎ;ï¼,ËæØºnݺjµj­}×»Þõñü£ýè÷¾÷½¹Œõ÷ÿ÷k×®}÷»ß휻å–[vß}÷O¹C®vÃÃÃgžyæØØØªU«êõúûßÿþO|âgœqFo¢FqÎÕjµ¥K—NNNöv›Ì% w‡Z7G Ü|óÍ¿úÕ¯ž3ñÉs¶ÞtÓM×\sMï¸^¯¯Y³æÒK/ýá8—½dË–-[µjÕt„Þí·ß>Óæœ]'·»÷®»îzN›ó/Ðöüñ¾¾¾™©Yæ‚r¹¼|ùòÞÆæuëÖ=ýôÓ+V¬èÙœ·ÝvÛsš.ÓóûÔ¸ä’Kúûû;ì°O<ñþûï¿ä’K^¬žgA·Û½ä’KBóæÍ{Ï{ÞóÕ¯~õþûïÝ¡¼³kûKú̳puùå—_sÍ5^xáÍ7ß¼téÒO~ò“yžc<§Í ”Òç‹¡x¾ýžeÛË™<óä\$z>6^Å+ÎÏIxÆQT¶%_¥þR_-®„4@!¤U©Î‰"&D*d ¢1´•…4+eŒóÁ”ç '”@†aÀ䑵ŽÓ@Ic´·È§5Xäµ3Êjç-Ü› GQ J!R†FõxŒÂØzW²ÝîlÙ2:19U©V‡w]$„H»Ù¨ÝÆ)~ x@ÌŸ¿pá.åøI‚I•(eÊa̵Fk­ Ø…"@Ñ–S"j¶”Ì [ÓåR%ŽckÁù4I ™+!xÅ£ZåJæÎ:í=&Ô:—å9F!9íœs6Ëò0Ͻð ­5Ö2Ê<&Öyë",$˜ •cB(%”b‚µV€ïÿ»z aà¼A€s£J¥¼`ႽöÚ«R.­·mã”ý)M²øÁ~ýë_¿ÿþûµÖkÖ¬ùô§?ýä“OÎñÇ÷CyàzÇÏ<óÌ’%Kf:…féyáÂ…3£¤ÆÇÇçþ‹?»DÓ˜×:G®v’ÿ…¨×ë½´==´Z-­õ³=Ïæjçg«ƒƒƒ{íµWÏOxÇwüä'?Y³fM¯‚K·ÛãxÆ ‹-j6›¥R !4—$;Ôº¹ ŽãÛo¿=˲“N:éÙöÒóµÎÌ6Üh4Î?ÿük¯½ö°Ã»ãŽ;fc<4443)èLmŸ]'{÷NNNNŸŸy¼3Úþ¢¼ ι¿ £ÒqÇÇ9Gõ*mذá-oy ç\)…1‚àÙ·L›Ü;©9Ћ¨¼øâ‹¿üå/÷²§>þøã/Jϳ MÓË/¿¼w|ÑEýùÏþÆ7¾qÚi§íPÞÙµý%}æY¸ºöÚk‡‡‡?ó™Ï|îsŸ[·nÝßþíßÞzë­sÔ„F£ñ|Ñ—áÛ€|ä#ív{;‡ê\$z>6^Å+ F{„3QŠâ¾¸6P믈˜8lµ%Œq,\ ÖK¼1Î[‰|Ï{W¦$w.aDX‹Áj™©f£[HCfŒpNÉ Ka—1¡FÛB*¥+ …Ü[‹8sryLvÀuaP„L3à1gµ5Ä#Àµº‡±T&àQšæãc*W•¨Rï¯"ÕZyxø5ÃÃÃS͆ÃÈYçwà<ò½ÈOm !HD‚‚4KsëM¡ 26•zJM4'‹w!˜"„d^dižçE¹GQH˜·JZmÁ#ΘGžRJ é… !Œ5ÖØ¢(ÀÊ™¯Œ–ZAkCÔ[0 ÂSª­uÞq!‚ hw[T0†ÞÙ^ôiÀ.(8ÈSÙM“8.;ðœó¸sιYžMµY–ŽŽŽN6¦¦šM Ž F)åB8€ˆ  Å$Ëå8 §Œ¤Yæ,PF2Ê´Ñ€±6Žà<`ŒŒKa)`Âhc´ÎóÂ9‡ ©Tk•J5.ÇÝn×yÇ×J§{Ång€ÜÃe˜P„å!˜fIš9+­s!Œ‘ÁÞçišvÚpeIn é´µgï1ÆŒ1‚iig{žEÇ(­õÕB”…yH ƒÐX¯­Æ:cœp#m­V RZNNMmMʱÊ%£¬<0cœ¤©¶¦P*/Tš¥œÞ;ï‰6®ÆX%„²ÐÍfwªÕt€b=Áä½ÏóÔ;[ Cç|žåÝNGi]Á­uÒí&y„€÷¦ÐFj%e–çRÉR)Îó¼9ÕHº]ç\EÖÚÁþÆ%#\ŠJ}ÕªS´¦œwœP ˆ&Ï£ÈZC)ͲL*i­Œ!„1Œ¼ï}ì%.6Öhc˜`Œ1„rŽbJ)±ÖæE.eAé¨Çå‹ *ÅÆC¥¯á1dE^ŠÊàa|lÜ: ÈI™X§‡îÒßW‹:ÉT·›(%›­¶”I¥üññ?±‹ïV©Äà½RºÝí ýõE#‹úû½÷q) [A†aA€gY–¤¹ÕÖ{ÐÆz„`çÁ[ç­Ç€B„¡p 0BÄSDÑÀÖzN6§µ6˲Ë/¿ü¬³ÎzÎ .¼ðÂG}ô˜cŽé­./_¾üï|çÌ ®»îºë®»n·Ýv;þøã¿öµ¯ÝtÓMûï¿ÿ|üñcŽ9¦wœçùv­³ôÜn·Ëåòô••Je»IFÏKþß¡,aø‚$êáÙnŸrµ“lü/D–eÓû`{L2Æž]¬åE¯­rä‘Gþìg?›L½ë®»¼÷GuTÏæ\»vm/]MoOÔ~ûí×3r^­›BˆÿøÇGyä³gɳ·ÎDÏö›K¤s®ÙlÎÔð™iœf×IçÜäääÌ9úv) þbmÿø.¬X±Â9wöÙgOûñ¢(Z¾|ù]wÝuüñÇÏ]¹“š3·Ür˹çž{øá‡÷,‡±çÙÑlü¸0 IDAT6}ôÑÃ;¬çjÞalí,Úþ²=óv\yïÏ=÷ÜsÏ=7 Ã<Ï÷Úk/!ÄO<1—®}ôÑw¼ãAEñl·üKýíW*•SN9åÚk¯Ýnô$Ñvl¼ŠW8  Ä(Ot;M: Ê"£Hà(Š«™ôRùÄä^cä8öEž‚2p-x†0͵΋B[«R£òÄ ADsåj™‡A¹ZÑZ‡å’´Æ,}BEÉ(²)ï xN¥8ŠJ&·Ö[© ëXØe#qZä“S ëP?<"èÕhnX¿qó†MÎÚc=–3Œ0 ¿á eR™Çž|BKmÀýwQì1BÚj„saĸè&IÚnGŒUˆZy£Ù°¶m›Ü66ÕM3g](Vf¼×ÞJË+Œqà‚ ¬”Ë”Yd!L°EcWâ aµZaQÆõ"©VšQçRún—PÊ‚ÀJ™$Ya4 ø¼ùóƒ(ŠÊ%•çÞX ž" *È#@­<+šíæ¯ó”rÏ=öX<21áüýÝþëׯŸš˜l6Ò,MóÌ#D+•J" c !Ô_ï«”*A 0F¨ ¼7[èÙ®êò¬ÀSÊœóà}/³S† &B„!Ä#›ϲ4ŽK}µ:¥ÔY‹)Fà·cÎX­^7JSD°GÈyì²hQ…yžoÚ²QDÁnKvÛu×aJhš¤8Mò±­ã“ã­v+IRg!Ž"Œ°qÞ#¬œ7àŒw”1À^D‚ ¦MA=FœcŒ¼÷Þ‡¡œus­}àŽ=öX„Ðsî0Y²dÉÊ•+§Ã™–/_þœ¬]»öŠ+®(—Ëçw^/qÖÌÕô™9Kf¢Óéì0×ÅsöüÔSO½þõ¯Ÿ¾fæ^šÞ„žs^«Õzóþé|¶/H¢¿€«¹°ñÒažÿbüñ\¶lƸç+èÍt_†*¯NgþüùÓçÍ›‡šÎÒñ‹_üâì³Ï€7¿ùͰ]¸ïìÏ%ÃÊsÄDQzã7î³Ï>o|ãŸdöÖíðÆ7¾±§Æs÷É'Ÿ\¶lÙLÏÕÜuò‘G™©á/¢¶ïü»Ð××wòÉ'OLLÌÜ_=;!'œpÂÊ•+§cé…FcÅŠwÝu×}÷Ý7m_mg!Ï]sæøT{íµ×L÷õNêäÜAéàÙ¡¼³kû‹ÈÆìØŽ«iôlà}ìcY–ýüç?ŸKW7ÝtÓ©§žúÞ÷¾÷_ÿõ_·kz¾ý÷½ï}Q­\¹òùo.=¯â‚‡&.—ãrÊÚR«nÚ)"<,ÅõþJ(q§›4<öà G= ÓZ¹â1ñÄÓOQ„Ñe1Ü•i–$Æêú@= ƒ Ò$G:%„P†¥Z­V«Õ6ZqB°â8ŽK¥41ªYš‰(ÈTfÁWk}õz©¥Ýv¥V“J¦2×Þö¼IÎyëœTª„ y\(«6M³j_­>8Æ1bÄ„¥HYƒ(‰J¥@«•³VÖäYÞÍo=C¼ÙnŽVûª•j¥R)J‡Tújž¢úèÖv§=15Ùêtµ‘À0á !¬¥Ìó¬žÝîöÊ! ÁëÕŒ$APB­qÎzJ%$ASœ„“$“JõÛ(%à8.3F1Á€"Da­Q…rZ!ä9ev¬ë¬ÒNJHžå$1ÖÁÚ ˆXfÓR)©‘óœPç½EŽ2Jd•YîŒQ²PE!¥Ä÷×ú+å ÁDÓMR­4Â$ B°[ ÓJ\æ" RÎFžàB+„ Ä ‚€ Öh57mÚÔ_ëë«öE‘Es²Q«ÕvÙe \Ž6nÜä=pPJ)ÎZk\§Ó¥”LkµªÖ¦W*ÙZX”ËB;ƒ1€¼…,Ë´6Œ³¨TbŒQB­¶;ÌYF" ­²EQôþâ8òÞ7x£Ûî€÷Lð¾z¼ŸŸÏÓ¬Èòþþþ64/OÓv»Ýíve‘‡QF¢— èœ{ê©§¶Ëÿœ˜½ç+¯¼òÎ;ïüÒ—¾tñÅï¿ÿþ÷w7óÞ‡~¾üå/ë[ßZºtévÕ·g—hvÌÎÕ\ØøËÐßßßóëAEÑÈÈHÏÙÛK×¹3<ÏŽï}ï{·ÜrË·¿ýío}ë[óæÍ»è¢‹FGGgÖ¡Ùœp QõRMüñÿõ_ÿÕ3hW­Zuæ™g~úÓŸþþ÷¿_«Õ.½ôRïý´ã»ßýî™gžyå•Wž~úé###_üâïºë®9Úo;ƒ+®¸â¤“NúêW¿úú׿~zÉã—¿üeo ;{ëw¿ûݻᄏ~ '|þóŸ¿çž{y䑹Œûï|çûßÿþ'>ñ‰ë¯¿~ùòå§žzêÜuò /¼ãŽ;.¿üò•+Wöö’½XÚ¾óïÂ.»ìrõÕW?üðÃs·gŽ<òÈz½~çwNŸ‘R®Y³æÄOüÔ§>5999ûjÂ\4çùžêG?úÑ­·ÞúÈ#¤iºlÙ²óÏ?rrr:4z‡=Ï¢í;Do{ÛÛz¿ïz×»FFFz¹‹w(ïìØ6f—hv®.\øö·¿ýÞ{ïµÖ¾ç=ïùìg?ûµ¯}mzsþì¸õÖ[ï¾ûîK.¹Ä{¿zõêr¹üþ÷¿ÿÉ'Ÿ¼þúë_Òo¿‡øÃ?þx/ÓLÌ.Ñìl¼ŠW¸ÐTªåIN³S¹Å^”ÃÚ`Ãxȇ“aŽ”Fûì½×YûÜ=¬½Vˆ¨D )R Öï\žçœóÅ>øª ˆdŒ©ërcÝ0dË'V´T’ ‘R­£÷Èw1ÛÊDZkÐ[gÚÖ«…Üžœ·U­§mÓ¶UmL뜥9ÑrÁclšÆÔ #ŠÞ66”(%„PJ—mcA X )h0Ô¶íƒ>hêvfj&X7Þh)766Ž=#:çC¤à£”¼ÛéŦ©Ë²öÞsÆêªlêz<1@†èŒJ ÆmÛ8 yž dΘˆ^0©DÌÒL+í#qäJ&‰Nr.™5¶ÏÛ[ç„E§“hM1J.Ó,£’4©&åææV[7ãÑhjj*Ñ:„ µî n]ªÒDgiwªßxÛƒ «¶.´TÈ8S*"¶Æ!pB2¶ñ1"g‚dˆbq0Að‰’‚3DJ³ÔFGDuÛ ËÉÖx4öìÙ—wŠjR‡—öLOMIÁ6ÖOon®†`‹N:×!R©$ÕÞEƒ ñ¾ŽLªf<*»NŒÁ;733k¬‘Û>:¬æfgG»÷}ð„àŠ3EýnÏ9|ŒˆÖºIÝ0ÎÆ€9ÄȲHž1¼#Š ™N2†\pùÈ9ç 7Üð𯫫«Û[IÿüÏÿü‚¼àæ›o~ÙË^¶t×]wùÇýõ_ÿõ|ä#ÛfB'Nœ¸îºëîl3Æøk¿ökoxö¿~éK_úÅ_üÅG”ûîw¿ûiO{ÚÞð†íݪ©©©s9ºsö;ò“Ÿ|ó›ß|ã7ÞxãÖÚ·¼å-¿ó;¿óð½[n¹å5¯yÍk^óšS§NÝtÓMo}ë[Ϥž½Egçì²:i<>nºé¦—¾ô¥g¾nÛƒÝtÓMg, ·œÏÎßÿýß¿öµ¯½á†~ë·~k{ÏêÚk¯}¬ö¨ÿï|ç;Ï„š¼å–[¶'HÛ]ýõý~ÿæ›oÞö¡º²²ò¢½èÌÉÒcÇŽ½ð…/|÷»ß½¼¼ Ÿÿüç_ò’—|Æ ÛŒÛÞkÎðã?þã·ß~û£¦zì¡^¯—'ÙôôTšH„¸¹¹qüø‰Ý‹»‹n–$zßÒâUÏü²,;rüèéµå6X,‘I¢tYW[›1Ƽ(Ò,WB$I‚ÖûÆØ¶•šEGÎ9ï}ž1©¦i¯Ûév‹]sÓ³ÓGŽ=d¸à"0`Ì3©«q5ñ Ñ“Bë9çJkÎ92¦´&`ÈJé4ÎjÓä²Hó!øÖÖæÆúšiÓ†èŒA€T'\pã`Â!G` HK- @Hz©ÓDK•¸‰1%G| "DTJ…À9'„PJqΕ”½N·È²ª,•ÖI–2Æ| [ƒµVj¦I§Sô:S ±èRÉ6¸´©="ЏÒĘÁSômÛ4&Q¤â„¸½‹@@"…à|ðÎÛq9YÛX ÁÕMå£ßžÅ7Æl†£!rzf×òéÕ­­aS·ÓÓ3{–öÍÏM?x$†[ƒÑÊêz§Óíö¦ççw·+ËÜ}ü·…³ßyiiéàÁƒ÷ÜsÏî¼óΫ¯¾úáëÜ{ö왟Ÿ¿ûy„ý¨-zܲzB¥ñÝ¢Óé>|¸iš{î¹çü÷NS¹‡ªªêèÑ£ßì­'I’Ë.»¬,ËïÀç·…¹¹¹ÅÅE­õ‘#G677köm±÷ÜsÏ·´Ê;»Nn;/mÛöe/{Ù-·Ü’$ɹ«ýÙïü½Ø·ædY¶oß¾<Ï?þp¯Nß»:ùÄÕùì²’R^|ñÅZëûî»ïw8A¿ß¿à‚ ªª:räÈÃcc~·Ú{ö=ªæìð½Ë9žËݵk×öJ1_H‘hkcó¡ûï?õÐÑ„ó‹ºèÀÁnVL“ñ ^]ÞÇ>ø`Kódvn¦Û+’Tk-CtÈÁ7ØŽFk ðDb ¡vfRו³L)&i§“w:Jë­áÀ:ëÉç½béÀ¾ýhƒÓJÉåæpåÄ©rc4ÝéJâà!SÉTwJ0.”Š666×V7¢‹—]|øiO½rÿÒR7/­”àu]âÁ‡v/ΫD…@Uk¾~ÿÿþÅ/ÜûÀ}ã¦$ ðÔúòúÖ†'/µLòln~wªSŸ)Ëjkšvª;•¨t2®WW7Æ£J½´wïE]tÉá‹æ¥`ƒ­õÏ}þó_½ï¾­ÑhzjjïÒž~¯;ØZߨXNF“ºÉûsÓ K{FU=.'Î{!T‘3½éºª&“ÒǘdY^tE©ÛïeEA­1Æ¥”RB0ƒsÎ{ ˆ’shªÚ{ßëvwï^X\ؽ¸{an~®©ëáx¼¹¹1 'e¹¹µY5 ã¬çLIÇY“e9ç (çRpëœ<†8—ÈXðBÞŠÁ´ ”eé}Br.cˆœK<ÅÈD ¦©­m9gˆä¼uÖrÄD(g½mL°žh¥cÖ¹Ú´ž¢Òºèu…ÐVõd4n«º“f¢›çcŒbŠœ3 Á[cœ³Áœ•R–u=Oªº1ÆD%U¦u‘fE§Z/¯¯ &£(W’#G)%$:íE¦’¦¬lk¦zS s»zYÆb Î÷zSKûö-îYjZsßýl Fssó‡B¬,Ÿ>~ìØÚÊ2稕Œ>TuÕ´LšÊz7©&i„`½~—|Î:c¼q1Á9ã2 çL)ÜÇÀ#ï½u.Ƙ$I–çКVIµk×®^§3 WOŸ®&eô!8ßÖ ¥úSý]»vÍÍÏh­Ó,A€µµÕå•åI9!€@”d!6ÆÔ­iÚ¶®[%D&“DJ!D 2Þ"gB †à¬m&9>ä:édYže33ÓB¡¤õ~0ªº×ŸÞ5¿ÕU#„ZؽxÑ…ì]Z8uêøÝw}yscµ×+®¸ü2":òÀGŽ<8M¹¸¾¹i’diª•bŒgI¶oiïþ½û¦§§“$a€‚Kgm]V)˳¼Ð:aqyeí¡£§Nœ\YYÝØ €ƒÐœ+ä22I>:*­Sd}–c¢ÿN*¥.»ì²/}éKmÛ&Iòâ¿øŸþéŸÓ:ËÙµý{±/Cñ?¤½goÑ£jÎß?H%’4!ÃÁôÚò²©c-r‘à‚Ú;B[7!„Èë÷ò= s‹K»úýŽ”¬¬Fe5 G¶!ò,$J0™ œ Ò´5”¥ÀàY\v’,äÞGg‚%ÀrRÖUÍE€\Š¤È³NÑN*$8£L°k{½¾R‰56P4ÎÔ“úÔò©=+‹»æf–wïš›ËR}ìØÑõõÕ4MúS}®D7×]phumm2³ÍõIS†§:=ÎYmjëF`€ßpòIdL[ljЙNC è½#)ÙþýK—_qÉ}KYªÇ£á¸œÚ`¡•æˆH$€€X¯pÖ))¼ÿFœŒ€cœsÄ<žXt‘ r!d2ò ™ÐZ ±} O!Iq ¥5glÛbçÑ3öCŒÀ§¥äIžëD‡Zd™C÷u=@ ¢|¤ˆŒ#¡xš%E'7ä b( hkÂd<±Æà¹Ò2F8Ëñˆ ̲™ÔZ/--=å)O¹ðÂCpj~6Ï2%Øx4„‹Jð( n­kêÖµ"éTgI>z&ZŒ!1¸œKd<pÀDk©´mÛÃ8cœÅ]ð­5¸Á”R"p®Ò„8c5@ ‚…ÐzRHŠˆˆ‚ %™Þ{è,Ë2"xïç)RDB0"ŠÎ •‚I%ÊTõ®1&R´äYš¦.Ʋn­©£•ÕÍr\QdÝ¢/ù¨iî=qüôd2\]nmŒ–—×ÃéþÔúÚx26mKR ­U–æMÝTeÓ6F A‘(ÐÆúæ×¿~oš¤EQPˆZ¨é™™ý{÷]xá^phf®'qŽëƒ½œ¸çžîüâ•eÍ"' ÀaÁÚ鉙ÖRbçå¾ÃßçdYö_ÿõ_GŽ9vìØ¥—^ ßÒÏÊ;ì°Ãßë žw:iÑ)[ç<…œs93?Ý4Í`8U°Îâö4`ºßÛµ{F*,+YŽy‘ˆNªëª1­·­7ždÖñœëF1!8·‘|$ç£N|Ýv:ÌŠÖàZWNjGFBr)U¢=ÄádÔIrÅ$G€t–h•ǬȊNƒ÷Ñ×MbÈ;E¦Ç$‰’’Ÿ>}2øpœÛ=,NOe?pÙ%Öº¦iVWWmtº“t³N¢51@ÎÇÃqš¦I§›§LMi`RkmÛ4 ŒiZS÷ú¥¥ù¹ùÊçwÍ:pP¤i¢¥ŠÁõ;Ýn‘ŽÆãq5 Œ”ÖHœ§H‚K%”dBJIT–J«N¯Ë¤Pur"C”R$J…àLÛ4Uåœ%D™¦©($ZJ¦Xåê•ÁŠ_óY–rÎxÂ5ª¨rb ë Óyš7U-„Á™¶õÞ#ÔR:çb!z>"†Þy"@@T\XcˆsÆ™à\*®8Þ‡¶'[cÌh4¬«IÝV¦±MU×U5\ß²­ŒY–gDBÎT’ô²T(©’¶ë“ɤ­j× ApôÖ–ã‰R*MÒNÞ–RVUi­ 1nû‰iÛÖ8W6UÕTi˜’šKÎcb@!F$DâJh%•N ¡mÛ¦­ ÃdS5ɵÆÔm…¬~scÝ:/ï]æmSMM§KK{ffrÁyžªn–fZõ©ÓÓÓËËËÿøÿ¸ã0s‡vØá»“8‚à(0n=•¥ŒLSÄèEÕ¸ÖzÀ466¦mZ#”Ló” ˜žîHÆ;E¡¸ÈUZgmUš¦²Î“Ê m¹ǵóÁSô”Bò@vR[o0‘ŠKÔT­”*ϲ$KŠ^OeÙæxÕ[Ÿ*]è,ƒ\&’GâDœ"„ª­VÖWN-ŸÜ·´83Ýí÷м—çe¾²²:ŽCˆišwzFØ5·k÷üjžd…H¥öMiª†ˆDÛ¦åÈŒh¤VEž§B€#gpà'uÛzã|ëÈ%24à………T%ˆbÛ6MÛ8ç‚wÁ{ò‘!×enº¢qÖy)2ŽeSž^=}ôøÑ™™~š©ééi•$½^wzzêèƒÇîºë®n§û3ýŸžÛ5Û-Ò¥=»Ëªyà¡#§–OÖU…’q-””óº®c1ÆBˆ!Ë2žucøh H”e‰wöäɉbÞ™"ÏxàÁº*•–1Ó¶ãñØ;#¦Y–¶Y&ÙÔÜLiÛ­Ír2I²\A·½ÅÔueƒçJ*›rƲ""SJ*%…d1Œ ¡¸ô g!úH„œ ÆB€ˆÈ¸àB‰\ÓÔ "Q œqŽà¢G„$QB#Úà|Ô‰”šsIÁ9DÁWmY;ò@ ƒ÷ ‘#J͑К@ÌGæQ*É™´\&…ÀÈcŽ·+/8‹"Å0À¶mgÝN"1DÎycÚ²®lp(8C4mSUe …ô‘"'äBrîAˆÁ8+¼à2aR äž"…˜Eë]$Z "B< ΄ÁÄè} ¶nëlŒ¸`\ò‰3Æ mðÞÚ„+ÅdÕZkLkŒóZ¥:ÍRëCU·ëkÆZ)ÓºªæffvÍwŠB°"—%¬×ëîÛ·$ŸLêµµáÆ`¸¹5>8뚪*Ç“77wôèÑ÷¾÷½ý×}Ž©Ï~ö³õWõáwûÛ¿ýÛ÷¿ÿýOô£9{­Þõ®wMMM="Ë{Þóž}ìcÛŸççç_ÿú×ÿðÿðd2¹í¶Ûn¹åÚ>œñ¹úê«?úÑ^tÑE<ðÀ÷m7¹ôÒKÿèþh}}ý¯xÅcÊø¸ŸÂùèäÙóžßýÝß}ÚÓžD´ººzçwþå_þå·k¹áqKãÙÏ~ö‹^ô¢+®¸¢×ë?~ü¶Ûn{ÿûß&ï'm~ôGô¯xÅ%—\R–å¿ÿû¿ÿßÿûÏ1ÏùôÁç>÷¹¯~õ«<¸ººzÛm·½ë]ïú–y¯¿þúüÁ¼é¦›î¼óÎÇšw‡ï¬÷‘1ŒÂ:o]ÌdÖíÎLõçJˆ€Šò"O² ïšî‚_H2½¹¹¾µµÞ6åÚú$øÓ«+ÃnQtóŽ`Â4¦7œ"D?7ÓEŽ©JúÝnB†„Mkœ vRºÁ©È%rB%¤³.“…Ôºjªª¬ªÑ˜mØÊo ÇÓsóyd …ÐI’déȘA9:¹¶¼¸¹gqßKs%µÞµk×ôôô}÷Üÿûø\öÙ•Yo¦“êdqaáÒK.]^[Ý7šŒF*Õi·3Õï¶MË z«ºE‚݉îäÝIU®ol„èbðJ )D[׃­a§(lkGñkÛÙ™©Ù©¾5­3íÚúZšj*Š")²n¯?LM÷{½.cjyykyus4œ0Ž‚qo][× "Ä&ªÛËcH:NÑíNª l„ISFäÀ¹`rÛ¦Z¢óž "GÁBˆ¶®«ªd€¼Çg§fvÍÏo;¶åŒcFÃ!P”Rr.(„ˆèc,ËZp•u³éé™"/¼q™s¾5mÕV¼Öi–Lr!-Æ1 §]k¼ób¢Ó蜋!yß–£Ò˜Ö•±šLO0²ºjÛ¶™žê ¤,Qyžäy¥’B ï½uÁ8+•–J'išdY|’$œ±¦®·¶6××ײLOMuìÛ»´´[pjêqUŽÖVO+GŽ}½(ºE[Gk(z>;;sáá ^xh÷â¡×‰p>´mX]m„cdÈc;ϹgÏžç?ÿùïxÇ;¾+sÎn¸á’K.Ù6ípv8çoûÛßÿþ÷_wÝuƘoŽ,úéOú¿ós>r~Ôr¿í¼ùÍo¾ôÒK?úÑ®¬¬\uÕUüàŸþô§¿æ5¯9—Ô<ÿùÏÿð‡?|fäý‰zöZ…DôСCW^yå[ßúÖí¯ZëOúÓý~ÿMozÓþôOÿtffæÿðwtþññó?ÿó×\s”òMozÓ‘#GÎ1×ù<…óÑɳç=;Ï|æ3¯¾úê¿ù›¿AÄ .¸àe/{Ù+^ñŠg=ëYƘó”áùHãÚk¯½ð ?÷¹Ïmmm=õ©O½í¶Û~è‡~èÌ<󉓼úÕ¯þã?þãO~ò“ï|ç;»Ýî _øÂ/ùËþçþ„¶÷ꫯþøÇ?þ©O}êæ›o~Ò“žôŽw¼c~~þÆo|ÄeÏyÎsn¸á!ÄûÞ÷¾3sÎsÌ»Ã÷ MkYŒdq4ªª¦Í’‚sÅ„RB÷f¦™¶º@¡\?×½™¥Ý ýÓ§Ò¬#¥b£¡¶Ö®nLN¯Ž²4-²B0n­-Ç¥kª­µµÃ‡ö.îÙ•Eš6~°a¼ŒJñ88-¤\:CVO_·®n@ N¥y~vpô4¶Ž[ÂÀl¤èh4ž8"r.”V\é4aeˆVÇ›÷x¨7;5¿° ™óó»ö/í½¯sÏÑ#G?û/ŸY\ÚÕ™ÊcýNqø¢‹Ö7VÇåøÔòI∀mÕvŠ®kÛñ¤,#Ñô”ñ!–“Q5iLC„duUæiš²i&m'íî[ÜGOOOçyj =ôPUW“ª$ÄhCl«vvj&PŒ¶©¡ÛÉSµ¹Ù2…âi"3­ÊŽæ"Q^®¹ PªDpÍQD‚(e,•\c“jèl­¦R).µî’³P{WÕœoª cà‚kÚº¬ª@^k½ZdÈÀ˜Ÿ™I³$R@ÀNVè<©êŠ)&2á¬Iš cÖ¤´âEù®I…LY"GhYíJ£Òm\§Q5 È•4Öz´@ˆœK­e’p`!DFDÎ9ïÂiLk‡Ã2˲^§8thÿî…ÝÖ¹ã'Žo “ªjEÎ2Æ’4ÕI¢›6@DƳ¬nlÖî®Ù¹9!eZäýngzº¯”\>uz}s­Ù\O†US1†‘b¯×›šžÚµ0?ʶ2>(™ ç!ÆÅôÌ0:yúÔƒGÊò´×͵Ö@¼(º³³ó»+ÆôÌœñÞ·MÅÎý%xá…~ðƒ\]]ÝÜÜüð‡?|ðàÁ3I¸õÖ[ï¹çžápxüøñ[o½õðW^yåí·ß¾²²²ººúoÿöo?ó3?s&铟üäwÜñ#?ò#‡¾ãÿcÛzó\8Ëફ®úìg?»²²rûí·ÿØýØí·ßþ¤'=i;é/xÁÇ?þñ3W^qÅŸúÔ§¶ƒžK‹óÌgøÍ äç#çG-÷ÏxÆwÜ1 N:uë­·öûýs—ÕYøÿø‡Y?ó™ÏpÎÏ%õ»Å¹×jvvöÚk¯}ï{ß{Æ‚î'ò'?¾=Ø€|àY–=ç9Ï9÷m½»îºk8~üãß³gϹ÷_ø¹Ÿû¹»ï¾{0|ìc{Þóžwûí·/,,|[´ý<ûB§Ó¹öÚkŸõ¬g=Ö±3ú£ýè¿üË¿\sÍ5çžñ|žÂùèä·QŸïºë®m œ¿>Ÿ4aYpÏ=÷pÎÏñs>Òøå_þeÎùë^÷º3¿8çNŸ>ýD·÷IOzÒg>ó™‡Ï“³,»êª«~ÍïÿþïßÿýùÈGGÞ¾(2•i¡çZJ Z__½ûî¯Þyç¿õ+_úê—¿räþ#ëk›Îù,Ëv-Ø¿ÿСCí?xpß¡ <´oï¾Å……ÙÙ¹ÞÔL1=“ÏÎwçæûRò²,O/¯ÛÉgºÅžn¾»SìêÖ»ûn¶suœ­ýžÂ>Ð/·/”Ûæª­sù}3Ý{w-ܵ³{ïs¿Þ>wïÎþ¶ézWÇÌô|'6¶U²ztâੵ“£SSãkºÖe¼’JMtF’Iš4@¥@…GôÁôÀiÒÌF×®=xýa‡rè¡«&§tšQÊ…TB)ÆEX–UQ”½n·×ëEQÕU‘çyž{ïCˆ!ƈqè"J ¥àƒwÞ!\¥”qÎUU•y·Û››ïÌw»ó½¢Wxƒ)‰"•P *L‘WUiMíœ Þï£16Ïó¼,\ð”1¡¤‚ N9£œ¸öÌÌÜ~çßûþ÷oúÞüü–[·Üÿ|§SÔuU›™Ù™¢*GGG:èàÑÑѪ®ïÛº­Ûï!b–e­ÖHšd„Ò²¬|ˆíöÈÚ5ëVMLJ®„¡ªª¢,½ ZéFÖÌÒF–dYšei¦¤âl¸¤ƒ!xkqÆßë÷ƒAA+595ù”ãŽ=ö„ã׬[›42™h*xüÌÂܯ7ßó‹;n»÷¾Í ý>B7B'2I¤R@© Þ81ƒ{ï½ûæ›ÿãÿïk¯¾úê¯ýkßþη~þ‹ŸíعÃZ32Ö>∛6sÌ1G¯ÔÏy衇þô§?½ÿþûßò–·xïßùÎwÞxãG}ô0ÀòØc=üðÃ/¹ä’­[·®]»öŸÿùŸ;?ýéü###×]wÝ/ù˳Ï>Ÿö´§mÚ´iqþòË/gŒ½îu¯[³fÍbìÓ C–/yýúõ×]wÝ/~ñ‹·¾õ­O}êS¿úÕ¯ŽŒŒ|ä#YL}îsŸ»´¨?ýÓ?m·Ûß˷²,{ÎsžóáxttôÒK/µÖžyæ™BˆÂò²Z¾ÎËc655õÇüÇ×_ýí·ß÷ßÿâCž{î¹›6mÚ+ïþÈyù÷sÌ17ÝtÓ°ESSS\pÁQGõœç11±sçÎ+®¸âg?ûÙï~ê°L_ñŠWpί¸âŠ¥ßu×]‹?‡×G}ô׿þõ}¾è™Ï|æ•W^ùµ¯}íÜsÏ=å”S>ö±­|ü>ãÏøêW¿zõÕWŸ{î¹'tÒå—_Þn·³,Ûmßÿ±p衇^}õÕ·ÜrË£ ?ãŒ3¼÷ßûÞ÷Ö¬Yó©O}jtt´ÓéÀªU«Ž=ö؇>ソùæ›÷³G\^Û—cìU¯z §}¶wŸMx\¤±qãÆW¿úÕ·ÜrË^¶ßÆÉ'Ÿ¼mÛ¶‡%Q; ½/„Xº‡vøu}ò“Ÿ¼¸[û©O}êßøÆãŽ;î¡ËûÌûþ wÔ³hÃÄè¸Ü(P673³»Ê^>7ŸÉ”ÍwF;~g¾?5•Ž !Ó4Y½zUš¨²3ÆS;gM]ÕuUW…óŽô¢êåy1èÕÏbc¬Ù‘\8ã Z¡(¬€H@tι-¤T )£œ3Æ8§œ3Ͳ,ÓiŠŒÙÚxc1çl>èwlU“(Š"ï zóÝù-Û·()¦F&4QÈ ieº™ôòþžÙ=¿ùÍo²VcÝúƒd&Õ‡mX_™(øˆs½œa„Bĺª‚·Ó{£í¶ó>"J ªkÂ(1ت @¨µu6 å"m4G䃅~wz~–"ÍF$ˆÑ_G\í]í!P‚!@Ľu6/|^†Âë1 €ÐŒ#çŒsFP„cœVF=¨B‰5Þ–eTÆ‘8Zt}w÷|wj¡=9™ŒÉ4™ŸÍÆÚ"+å g”±®¨kG©#”0 Ñø²p½¹GÝJZ##­$£BÒD(¥ÓŒUmœó! Â8—&Zk2"Ød ‘2*¤$œˆè¬³Þ""ˆ‚0BŒ#—"ISŒÈ)£Hå’ O… ‚Fê@ Œ)T°‘Æ™B ®aÌ…”S®¸ £‡ "A&˜àŒqa«­º¶öVj’L#!Áý¿ýMÚÌŽ~Ê1›Ž>ÒÔU„¸gÏn&$aÜ_WÖØ@™`\)™%I3Kˆ"K‰ªR•i}ð‚rÁÄ0¨ÕE¸0h±,+ç‚ÖœsN‚K!0ļ—צF΄¬µÎ9%Uše1Æà½Ö —ŬwÎùDg™TJHhƒÇà¼Ã£„4MÓ,sÎ`Œ@À‘D¥*^:[»È"zˆ•­)§BJ™H Œ î!:o+[WUC„€” øØß¶ã~.y³Ñ˜Þ=;W%2ª’„K¼›ëv»ƒA«Ýk6šœR¦¡±® Â8GIš¤ÍF–¦‰”‚sîêÚy+$ŸœšX»zÝš5ëÆÇ'P°R›óùÏþ~ðƒµk×.F7mß¾ý¸ãŽ^#b«Õ:ãŒ3=ôÐf³9 CššZh;vìˆ1¾ï}ïûèG?zë­·>ZZ BˆRj1Xk)uÍò%ÿÉŸüÉ~ðƒÅó<¾õ­o­Üæ\¾EKýŠ¥ÒY^Vû)ßCœtÒIßÿþ÷÷]{íµ‹7÷)«bbbâk_ûÚ~ô£‡%ÕxØÔ«®ºê‹_üâðzllìæ›oþä'?ùõ¯}…{#—ѺǥÎ'Ÿ|òUu/UŒqdddÓ¦Msssˆ8Ü“³’×xâ‰W_}õblÞ·¿ýí¥6çò:¹WÞn¸áamÎÇ íû?î¾ûîÑÑÑ¥ÄK+A³Ù<å”S†›·mÛöÛßþöŒ3ÎÚœßúÖ·v*¿h íO/<.:¹¼æ<ƒÁÅ_L™œœ|éK_zÞyçýøÇ?Þµk×>Û»¼¶ï¿4.¾øâñññ“N:éôÓOÿñ|ñÅhipÎ)†â€öþ%—\òÅ/~ñ¢‹.úÚ×¾¶iÓ¦sÎ9§ª*JÿkËÞð†Õ«WèCz yŸÀúsÝAgÐÔ­ÕŽ8býáéÜH»&»šÙìÌl§×+U¯›Ç0Í9׉NÓdld$Ñ !„è¥diª›­F«‘6šŠ‹”1ž¢Å:¸2º( Íœ‹¢µÞZO"¤IÊEÈM僉Öc]Yš¢Àžâ©nÊ#FD Ä{_VU`4áÍ~§£…”2B!”@Œ¶ªË²tÁ -‘:8 '’#§\‹Î »íþ­#cíƒ×ÜmPÆ›Y¶nõcm·_îxpº;È1‚È(1y^Xk¬\È$ÍBÎ“Š É„ˆfæçwì|pÍšµŒëƒÑ `ŒrJgBIí#.—œ Bˆ’ŠÐ ¸ÐZJmp\`£­¹Î[c j­+yÙëÛªŠ. ®²uYrJ$”PF(qÖ‡Úy¤8Dˆ> ˜â2•)g,¸`EB¹ÔžÉz ()J‚žG`€RhBBôÔcÄ*~iŠ¢úv0—C:µ[fu±zõd³©®QÆâª©vÀH(HmË~|¦0óUw0ȅƤ!ãPj͸2¶W”iD†1DÄL)•V ˆÄ3!¸”3 !xæ ­MR¶ !ø£ ÆçJ©à2¹zÕÔêÉf3dqE6'clbbâŒ3ÎxÁ ^°WœÒðâéOúõ×_ßét†Ž…Ⴑbq1û•¯|åÿú_ÿëÇ?þ±sîæ›o~Ó›Þtï½÷®ðãûô§?ý'?ùÉðzË–-‡~øÒeòeJ^»víÒ(©™™™•ñ—oÑ"–Ƶ®PVû)ßCŒýô§?]üÙívsõ øÁ¾êU¯Úg{—×öý—Æ0züŸøÄûßÿþ!—ìÝwß}@¥±°°ðHÂÚûW\qÅ!‡òæ7¿ùmo{Û¶mÛþáþáÚk¯jïðü•7¿ùÍRJ)åð%˲V«5 X&ïøDgÏì “ÓêÃùºU“$if©ç€MêC.ˆÄè»Ý^¯ÓÑ9W[k(ƒf#Y{К‡m88[×n·)%¡ cãѤ”%ÊF|ؽkOpp.¢íV›r>¨Š…¢×5… ŒãÁz꣠L¦Y³5RuŠÜôƒ5Ì)ÉEÑÏM³µ[Íf£‘e=É-DôÎÖu¯Û›››s!…©EY€‡C`„HÁ¤äRv{½;n¿C ¾áˆº¡GGGrav®»fr'¡Œ@ÚœU]yï‡K“Ji!e«Õ2Æ-,t c¡ ¥„±ÊØ^·Ïè=Œ²¹¹…$Iæçæ­uœq‚¤*ª^§[%Dœ¥IÒÌiš£YÚ(ëA]›Ú”*ÑIÆUʤ¦:…©eÞÏ«nÕÙ3ß›ŸçÉ%c®ÛíÍÍQ‰Ð‚ !µà1¤5¥‚rY9C)A)a„ O$"§œHˆP# 2Aï)‰„ÅÁú`#:J‚·Æy rEµÌ(gÖ, ¯º;f;µvÝàùޚɃ]»fÝ*‹u/¯i´š´×)æØ@ ÞÊdÝÃþ\¹ÐëÒÊó8eI0‘q!¤"¦ÑÆ]ˆHI’6’,idMÉeôÑ!¡€çòÿÛ·Y‡”Rœs$àC@ïãÿ…1fx:)A: ìŒ1R¤œs:d¯EÐIp1 ¡R© AàÈ 7Ë2"€ „r*"¼ñ@ W’2fœ³!,ôúýA¿*‹ª2S“6G@›˜8öøÖ­Yƒß±}ûwܱgz¾Û ¢5H©,Ç, ãB­uyUäeY[c£g@…„Óˆ‘ åLPF´ÖBÄH)ÑJU¥¡Œ)¥cCÊ¢Á`PUUÄ1Zç8cŒçÜ Ïm]3BF«Ñ„eU*­’T !Qã¬sÖ{ð1RJu’$Yêƒãœ{*ITš¬;hRr÷î]³³ó•©RALj¡SÁ3(‹ÂEƒ¹*Ñ€Àq*¡Æ;!eš¦ŒÑAž÷z½üÔêÉ4MÇÆÆ`÷îݵµ:͆«IHHí=B#2&œUU9Ò$ë÷f:ó«&ÇFš)¡H¯Û™™Ýã³ÆXk×­=¤ÝnƸ2›3„P–å%—\òîw¿ûa¸è¢‹î¼óÎSO=u¸º|Ê)§¼èE/ZúÀ—¾ô¥/}éK‡vØóŸÿü|àW]uÕSžò”~|ï¾ûîSO=ux]UÕ^©Ë”ÜëõšÍæâ“­Vk¯I!dñg’$ªEC<Ôí³OYí§4~Q–åâ>Ø¡$…=¬å±99•RßøÆ7&&&žùÌg>t¶|êR í¨•sS-¯uûSç¡*žuÖYW\qE]×KïoݺuH±3ÜóvÌ1Ç ³}¾1ÆØét–jøR§åu2Æ877·t޾ÔcÖöÿƱpÆgÄßóž÷,úñÒ4=å”Sn¸á†ç?ÿùËGW>æ^Ø\yÞ}LX;;ï¼ó¤“Nºš÷[»Œ¶ï§4–âšk®9ÿüóŸñŒg mÎ';ï¼óoþæo´Ö{¯•HcÚ‹ˆçŸþù矟$IUUGy¤Rêž{î€C9¤Ñh|þóŸ_<üå/yûöíëׯ_>ïøÄî»}í[¬A2#­ÆX3Õ’xWv{ eQØ<Ͻw”!B 1ÄㆰÎ: ý=é,£Ü§”DÖlE¤ZôË|¡7—Êຑ6Ò,R¶ë2)2]t»¶1ÆÊ q¾4EoF®M8³ÁS @bä„r ’ ­´ÒZ(E(µUDÀ"/x`÷®Ý3c£“´¥ çCí k ÝhLL®™œZùܱã眵þð#76Gš,;hͺcŽ:ZmÛ"(¡cðÁù€Bȸ]ˆÎ{ДH%“$åœ{ëççî½û7³ÓsRÊ|1(Rj­5’ A¹b’”$ÁøÒÔµ-­D+A((Íuª§H|]•ÁÅbPMûEÝ+¡Dð18h “Í–ŠÒšÂF"DÊ©Ä"!ëG×jžÚùÁÎÎ`03×™žJÚŠg´=ÖIJ¨4¡ŠÈL(™òvÓµ¨J*ÑP kÊrPšÒ¢G T¥ICm«H¢âiP‰Z1Ê "¥T)å¼³ÞÇè œK©N1b$àƒƒà ¥l8Œc@Á¥’’qFh“sN9½÷Þ{¥’¥¦¶ÖXSÛàa$I©dg|^›º(yTÊy0î«.F*™¤¨b¬w>U¹{væÝóœ§Þ¹N§ST%—ª™µ"†n°ÐéBûý¾÷~vv¾ª¬TJ>22ÆˡX×N B9sÞG ‘DŒ¤‘%*ÑY–f$? ¼·„ÀªU‰N‹¢DÄDëuäœkŽæECl¤iQyQ8c‘ ¡…Ôi¢’„…ÖÙ¢(’FC)Ù€!cúý¾BJ™dimê‚õA ø˺®M=?77;½§èWŠ©T¥­&¡¬!%wˆI–Z´`b„@8o‚‹ ¹`qÎ9‹Ñ3 ÍF „„à:ÝŽ© cÌy1UÙí÷c‰J´VHˆwÞVu4Ž„|4ÆÇ€J%qÐëmß¹sÍÚÉ#F›˜œ ¦§§w<°cvnvûÎ6l—‰Ë8í´Ó.¿üòÅXz¥ÔÂÂÂgœqà 7üçþç¢}µ—…¼ò^x¤ZíN>ª¼û”Àúõë‡ÇŠì³½ËkûþHc/yä‘{¹74®ºêª—¿üåû·û…/|a¯¤Úû‹Úí¯}ík˲üÿø¸çž{†Æ!N8á„K/½ôÝï~÷7޸ϼOà.¯5SM*.ÀEAI’$GÊb*/6lݲ ±W•¥C$@¥ Âb ÖJ9`ìu SmŸ›Y˜XµjíšÕc#ã”)¦TÒhDTr*¨ÖI1ÈmeòAi™'„i­­ÔoC‰u44 óʺ@7)gCwc\p|H’T0 #F À%眆#a‘NÏÌ´w…Q¢kJ3?3C¤œofM.•½ßòÛmœŠf³¥u’ˆä 5ë²²Ìææ‘‘BÐÈ¡ µ¦ŒF㬋RJeœμNGs5Ö!!ÔäØª±±1©T·Û-ó22zˆ‚PF†àªÚ˜*k(.˜RRiɆZqôÐí æwOf»½Ù^Ñ2-eªB ‚ 8ó‚ÇÀ"¡ÁGç $AF„!\* á(F‚HûÙÏ>ùä“¿þõ¯oÛ¶íC9óÌ3o»í¶½L¬;ï¼óµ¯}í«^õªŸþô§1ÆÍ›7ïųÿ°X¾äOúÓ×_ýûÞ÷¾O|âOyÊSÞøÆ7.Í{Ë-·Àûßÿþ|ä#›6mZ<©|ÑŽZ¦EËcyY­D ãããC¿®Ö:MÓáòy¯×ÒuÇç?ÿùk®¹æÂ /üÈG>299ùñ|×®]KÏ¡y̸ôÒK_øÂžwÞy'œpÂâòÁøÃátpùÔÏ}îs7ÝtÓ0¸ú´ÓN{ûÛßþ½ï}ïŽ;î8Ðs…åk5Äk^óš»ï¾{Hñ²ŸûÜçÞñŽw|úÓŸ~Ýë^·~ýú÷¾÷½7Üpà íäË.»ìË_þòë_ÿú¯|å+§œrÊË_þò•ëäE]ôï|ç’K.¹üòˇûî/mßÿ±°nݺÏ~ö³·ÜrËÊmÎg>ó™ccc×_ýâcÌÍ7ß|úé§¿á o˜››[~5a%½ðHµÚ\‰æ,­õ_üÅ_ ¿/~ñ‹×¯_?ä.Þg{—ÇþHãßÿý߯½öÚ;(ŠO<ñ£ýèÜÜÜbèì“Æµ×^{ÓM7]|ñňxÝu×5›Í¿û»¿»÷Þ{¿ò•¯ÐÞ_»ví_ýÕ_}ÿûß!¼ô¥/}Ë[Þò|`H(PÅÒ ÃøÞÍ›7ßvÛmûÌûþAj!}e»3óE¿Üx2’¥“œÇª®­ï¡È kwŽQ¦•vÖ8ï‘H®B ޹ܹ²ìv:U‘»‡Étu› ”Zé†n†VÚÏz½"1…)‹ª[–u’$Y³¡:‘ÉÅÂæ…óÄâÑ•ÆQÍ('\.BcÝ(—Jˆ¼sŽqÖh6²VÓÖ•µ"eBR*òAmô•sƒº¬ªAaL®]›q%(§”s)z~pׯîÉÒf’$kZÓn4¨X77wXg~>ï÷cðŒÓÞ ŸRë4Ë„THHÄ(Rr)’cðŽ)Eg¾ÓÌ‚q©Ôê5ëÖ­[—$ÉBg˜º Î{çiDô>:ÏHÆDΈ„À…ZBôÅ ïÍÏ÷犅þžYæ ZxBl`\‡¦°10Jyˆ¼è WH „qe#ã>ÒŒ ‘8㹜 ç¡T©¤¬«Ào6#F‹0   Ö“ Ð#ï@P@N :‚–×L! ñ>ÔÖ˜ÂæÆ ÿìöúíÕíæª¶n¥\) Ücáa˜*QFr‘Å#`„*Ö@ bôÆ“HdÂCˆ¦ªË2÷ΠƳ>„HQ& œseYB­³UU)¥¤”1bŒqÿŒˆ„R.cÌXJ‰$FL0)M‰ HÑyW»:¯Šª¬c”°¢žJH¬|YTœ3!dU×C3IFFG"bQÌS. €ÑDf.úA™sF!C¦£=Ó»¬©§wïb„z}dÝÚuZ§“ãcc­fÛ‡07;ÿ›ßlþío7w{=DÂÈ„SJ%4Qº=:âbp>–UiÀa ¦¶>Xç\Uëê¼@ŒÖº…N¯ªŒ²Ùl¦ij­­ëÚ‹12ÊêºFDJ©¬­µÖB„ Rš²vÆöûƒ¢*ûU‘WyÚÈ€€÷Î{ïêZ É8ç¨\ŒàC@L”kLðžF‚!PN8e †H)¢–ÂIlð!8çhDÎE"•`}Öù॥œÐཷ.w}ã,ã|¨¢ZjƒRZpA€ÄˆŒó‘ A‘R&W¬á¥Œö‹ÁöÛ™ˆZ‹ƒY—53Þ™éñ‰³Ï>{˜ôë_ÿzñ÷MozÓ5×\3 Ú¹sç»ßýî¥D1Æ7¾ñ‹Ü ·ß~ûË^ö²½Þû…/|áiO{Ú‡>ô¡ÉÉIBÈèèèJ‚©–/ù†n¸è¢‹>øÁ~ðƒ´Ö~ò“Ÿ|×»ÞµÔ·sÙe—½ýíoûÛßþàƒ^xá…ŸúÔ§S—oÑòX^V+‘ÆcÃ…^øêW¿zñç0ì /\Œ0|Ìr^ßüæ7Ï=÷ÜóÎ;ïïxÇÐgõ¾ðÑÆ£>,†Îº!ÌÒè¸ë®»nŸ©6lRõãÖ®¾úêÅî8 X¾VpüñÇŸp ï|ç;šwûöí/}éK¿ð…/ìÞ½~ö³Ÿ½ò•¯\á{¯¼òÊg?ûÙ—\rÉ¥—^Úét.½ôÒ¥¯X^'¯»îº·¼å-çwÞ9çœsË-·|à¸øâ‹W ½|Éÿ-caX{ÓM7-½ùï|ç´ÓN;î¸ã†'ý,ƒýé…ýÑÉ}jÎ>—œ†ô]EQÜ}÷ݯ~õ«êå{ ØiH)?ó™Ï,nƒÿÑ~tÎ9ç,~pœ4ñ¯ÿú¯/»ì²ý×åœÀÌÌÌK^ò’Ý^!Ä\0ÜhP×õ¿üË¿ìEv€ò>ÿ÷©,‘ÚWvvÏôÜôôêU£#í´ÙÔ£#­±ÑV³‘Q‚3‘€àc$„F&Î¥1'„†‹ÂïzpA‰ÖXkÕøH+keY–øàÛƒöŒž)úy‡2bŒë…(ʶw-hé¦ÖBFTeeBe±v 8†(„TI"µ¶•©kƒ¦® œ1–µšY» ëªD ‰4Œõµ±umóÀxsdt²= µ÷Uœ—\íÚ½ë׿ºgjõêF«ÙidZo8ä…ùùÁ ïƒóÑÇLm"€J¨ˆ„8ç€ÒZkÍ…‚1Á˜ U¿×ïÌw”™Tc##kVM6šV–9kfföÌÏÏ1‚3Ź Ô §J !bàŒYX:ý……ª?°yéó2QLHE8q@"CO½§Ö`Lä,QM¡RB¸Î’ŒŠf°€* DC©R#8ÄH‚Ö2&¹¢ ΃‚ÞW’a m" FNBàèeœ1Åcž$LpJ-70óÎâé÷óv¿ÌÆZ­Uc:Ë„ˆ‚ð&@m Tx®œrCVœœ—Ì;k½3id‘Œlhi„¹õN§šz‡Ÿwï}]WÞGJ龕BÎgC÷3¡”D8WÛʘ$ú 5U=è÷½÷„Q¥JeLpÁk¡¡®këc,O9Q0 ”ÚàQ!%Òëvî~0m¦€º¬÷e]?¸{[Pd~~~åÄ÷”Ò#<2MÓ;wîEÉÃ9?âˆ#„wÝu×Ãzí=ôÐÉÉÉéé饇C<.X¾äƒ:hÆ ÷ÜsÏúõëñ‹_œzê©K×¹×­[799y×]w=t†½Ï=fYPiüw¡Ùlyä‘UUÝsÏ=ûï;}\°jÕªµk×*¥¶lÙ2??ÿ?E’Zë£>:Ïó•G/õ´¬]»öž{îyØÆåurH^Z×õÙgŸ}Ùe—i­W®öË—ü?q,ìO/<¡“‹HÓôCɲlÇŽK9®~7ÒÙ¸qcQ[¶lYzúåk¯âIOz’RjóæÍÖK¹?yŸÀï9vóC1555\)¾ñ›ßåH%c£­§{ÌS=úð‡4Û©uæþûwþüçwÝrë¯f¦çãJ©²ªœñ@cŒ#"¯¼\HjŒ‹1ŒŒ4O8~ÓñdznÝê$Ѧ®Bp>øà·ß¹õ¾­ùîÂ|ÏøšÑZe­´9ÒÈÚiDש>Ó|´%šY{d,ÍÒéÝÓÓ»÷Ýõ86:‚S‰ž\3™5U]MïÙUôûýù…¼Wöε­^³6k·(ceYå½A;mþñ±Ç?õˆ'“ÚÏ>¸»33[ôó]{vE„ãO8þ9ú¬§ÿäX»z˶­?ûÅ/n»ãŽû¶ß?×éZëF«¥ÓÔ87;;C)[599>>®” >”½Á`¶‹.d:_³fõa6sô“7¬ß0:Ò.Êâ¾­[üóŸþê®_wò^c¤5¾j•Ðr¾Û)]¹nÃÔêCV©LF™`J‹*¯æwÏÍîܳ°{Á÷\9Ÿ7U£©BƘJde«ÊÄn/#¸l&„Ní1•¶">2`ÒZ¬gLj™0Æmm‚ omt^0b¬ÎPrC¢#1 œ[)EC°¥Ï{¡ì ï˜3ÔÕmÆLƒçÁô €TŠIbèVyŒ ZZféxsÕÁ«'Ö®N ¤Ô‡€!Òºo|«­úuկ˞)U‘eUkL¨¯©¤Y–h%CežýÜ9—4Ò€H(i6[išv»ÝÁ`à}Àˆ1FÆ8b”Ré$I”N´ÖiÂ)3ÎÌÌÍ–u!µ–J6Û Î¸uÖû@)‹¼PJ .¼fxgU ͬÑldJI‚1¸ZPÒH4#$Ïóé=3ƒÒd6@$L*-µ&Z«fš*!bU^Æ@ •èT A‘yÄ“N=åÔãŽ=jl$û¿3ؽ§ë-wnݺ1N­žL”0ÆLÏLïÚ½§7ȳfÓǸk÷î…n§v6FBDÃÈÔè}ð„’¼®kc)ãÍFc||œ3–E]”€@()Ë2MSBÈ ?˜_˜ Œ±öH»Õh’€¦¬MUÕÞ©$I[ .8£Li56:Ún4cÑy× в™k¶cƒNgîÁ]y§W•uªÒá¦e$ÍV£òÕ ìÕ®Ž#Dôhk‹‚)BhiË¢*’4[³fÖz¡ÓéõzÖZ¡”TŠ É9 Œ1•hJép“§28|0Æ…ˆ‚ËLgÞ;k*JQI®KR±võT’&ÝNofffÐÏ12çS’?ªïfŒñ‘X ¼÷Ëlß¾}ûöíâk¾|É<ðÀ<ÃXÓ½ðàƒ>ìÑá+iÑc–ՕƃÁð”ÅßÌÎÎ>tšûûº®o½õÖÇ–w×®]Ël~{$”R}ôÑ·ß~{]×Zë¿ÿû¿¿ñÆÕ:ËòÚþ?q,ìO/<¡“‹(ËrRî-n·;ÜCñ;k¯sn)Yúï,ïø ‘XçR 4ÕÉØÈH³Ý¢4ƒ^¯ë¼±¶ÁI!¤äu…œÊ!t8GÄÖ¹Bäœq¦ §ŒicPrlÕX’è*/£sþ uWEmL˜ž^ DPJ­¶ÛÏ«¼]gIª€"¸€ÖóH ¢Tª9ÒÎóÂW6D[ä¹s¦¬JžH¢áŒ*É´”‰f…@4)WƒÞ@ê$kkÊ­A¥ “rõÚµcIc¢=ú@²cÏîÞ½û¾Í¿­j31µjã“ofÉúCîúÝ~®Óév»žaCo$¯L…µNš4M!Ä™ÚÔuŒ^kÅ8 ÑÄF#mdi#MZ-Ÿo5¯[;¿0çv¹Ü`Ðc5ÁMMM$‰ ÑxŒÑTµ¯m0M-"Œ6’LhÍ¡"Í ß+­AÒ15>®²Q!4¥B¨Œ0øÚ» 2""H`Ô†ŒåS-S”À¥‹DPtœ)QñRÔmdQ4•µY¨™¯mÞ3ƒn0A* `à”)ÎRa¹£,Å1'Ô1Š I$ÌŠs)“û¡G’!‘ïkC‰F³1Õš”=‡VH®”¤­F«§çÝ~¯¬+©ôH{4˲!7£T Á9\ PVRqÎ0¡D+=ªF­æ ì×ÎÔu1åÍV£ÑhŒë4ݹ};¥”Sn­ÏûE¯Û/ز,m4‰Ò¼` %¨âœHÓ” »¦] œPB…P‰Ò‰”²Ñl4ÓD0œ­o5[UQEY—yäæƒe#„.ÀïÑ„!Ðh¦i¦…ä\ÈîÊ˲¬ëAž[ë8BIÆ©÷®,óÊÔ1zF !Bl¦ÍFƒRFÓ4MÓ”"DH@ŒÊX@Ä!""FŒÖ{cl"•NBô¤–RÉè!&Œ¶[--U¯×ƒˆÞ‡º®‹¢h„‰N²4#1BŒ±ªkï½ó+_¦pÑ #EB €à"ÅÀ%¥Œ ©BˆeU!B˜Êû(„R1Æ8ç”q.8¡ÔZë¼g”ŠL¦I 1 Æ)'ŽJ(‰J3Î`na¡,ŠöÈ£”q¡’ÄÖ>:ü‰oûxàHÓô¶ÛnÛ²eËöíÛ:ê(xXž•'ðžÀx¿(¡\´ˆ˜*Õi'i*„`,ft|b|t´;59Ä0­5ç8B@B8g‚¦¤‹H¡Á£µ!{¦§ïßy£¥WML` uQ:kF³Ù *M !”Ò€Áºªª ‚w.!Š@¨Ut¾ª*mj „2F9!0DƘ±6/òÔ4t–ÆûHIªX¥¯jÁYCH3It{´ÕifÍ´ÙNWŽQói‚èƒÛ3½ë–[oŸ9õÔgPΕäS“«;lýìüÜî™éÂtÒ´E€TeikC)’£Òá66J‰‹ž8@”óv0èÏÌL·ZM•p!äš5“ý²÷àôƒóƒy¼Ô‘µG²´©„¤@‘rʼ ƒ^Þ›ïÍ- æ;‘–lp ! 36Öž[–xšRšÏXÒ–þöÞ<زª:ü_kíé wxc¿h¤ TDP(D-5-bpNÊ)¢¦"F£†ÂoYŠÆ8!ш1UR Q#І`pˆiŒâìO£¨6Ý4M÷›ß»÷žaë÷Ç5ý¥D›Ö– _ûSïsï9{Ÿ³×[ûž½ö^{-%@%ÆÈ2ú Ù§ÄRB!t”„¤¤”Qp"8B䘈$’ R1Q&2Ï2¡÷Ñû0!!E¥CÑ‘™DÐÁú<#‘10#)P DTF›<3YÖít§àˆC JhE˜KIY&…™)#e·×ÕZsâG ‘Gý²9wîÜùüç?ÿHôù#áX[[;á„þð‡OMMíÛ·ïsŸûܯ .z„#áG¸¿!$ˆ)êÌd& Þªª(TYv6o’óû†Go­ áúúš!Ïs)u¤ÔB¨ày041 ‰ šÆY;jšºªF!m´VŠclêV£³\gYV”MÛ†”ˆPjƒ™ƒ³ž£1!)Ë,2eH0)$sbfôÞ×MãbèdZçYÀ€QI fÁäYp¶P ©e„è£ u&'§:3³“{÷d&7Ý^—~xËpÜÆÍ[æTf&'z[·l^Z9vמ;ë¶QJ¬÷PæE'/S5Äc )y æZš2wí»Ë‡V™—frrBåjjfjæمÁâ°®@ —BŒQr‚ Bê<+Úºuk«6Z+˜3AÝ\B„”8¹$*ËMTIsC˜)*FJ,ˆ…DÉ(ØGŠŒ‰S ‘X 10qäèD  $FtÉq2“H"‡}B”BÇ,œ„c!±É„&ö"6"yAl$D1¥dL<…Õv¹®šj8œÞ:Ùͳ(ƒmûÝY¡@â ;n›¬i2ë2§"Ït®ÜzÛ´Í`°î¬M!8ç[çZgmkRU×Îùáp8 9%­5:ç”PJk> ‚s¶m›¬SHÞF׆"A’@غ]___ZZ"ÀSJŒŒÄŒ˜P¢`]²ž|Ó ›ÑÈ(Ú05Éý.çóÌÆ"$ˆÁ'ŽZJgµ$$‰°qn¶SæÀ˜\¨l;®»¶qÎÿø–[ÚªÞsçîãŽ?nó–­ynÖ‡ëƒášóÉ9Ûï÷CðMÓ&NÎÙ¶mó¢ì÷û$¤RZi%$“ÅmSsHÀ #AðUÓ€Y ɇ mÛŽÓ¢H)³,Ë'&} 1F)eY–JkçRH‚0B)¥Öºìt¤R«kkKË˹6y–I!Š,Ï´‰!ŒšÖ·-1TÒ‚¥”&×:ÏÔÈì™ ¤”8„”SŠ!sDÌË2¦DZ¡’Zë¬S&)‘hœM'B’R*­øç²I­ RqÊš‘ åeG+AREFf’‚$áwiseeå#ùÈ‘—ÙŽpon½õÖ[o½õˆŽp„#á¿qr©à}®iêµÁºÊ(¥LJɉ3“Oö'ýw®µÖäYJ#t:åää´Éòªj„$æXÕ ’ ¢TJg$€¤Èò¬(sH €u]///¯®­¹€õ!¦¤µTJ!AŠ)&Æ„89‡˜¬uYÙ1Yf2ã}ŒÌÁ9g­hÛ£)òÞäÄòÊ¢k$ !{§%¹¦²ÉÊ<Ëò¬mG£j}8Zóa¶(³¹3›6m¸ëîÉåµIƒÐ´²²øÕ¯þû#O?õècí÷ºGo=Êz·oa¡jšµá°±Mbg´ï÷{À©©ë< Iy™¥˜Ê‰Nw²ÇöÎï],ëLõ'{:×:7½ÉîìÆÙÉ¥ ‡ÁÆ1¢È(>"‘J Ù1F0Bé"ŸÒùDщ­K>ø6Rã ‰u¿èoTå´Îº¹.!Bh<Y$†qTHÈÌ12pJ袲KɧdfBÄ”s”Z+# ‰K†M *úÚRÔoB¹ÎDTÌÈ.¥S2ˆÂd™ê”‰‡Ñ·u¨–†R3‰®¹èäB2¡&B" ðÐuep!q G‹K IÄ^¿“bÈ2틜S´!Œ½BWVVªÑ(7™ÖÚ¶ÎYë½³­]__B@‘—DDDˆ IDNÉ·Î¥l6´US›&Ï3Ž XP¾mÛÆÆ% £´’Z -Pp`ï}b¶ÖգеLÝ.&gø0Z'3!2IÂèýл¼"Ì%i„^·_Y3ÁÚ=¤¸ººlÛvmmuaaþø=è8ÖäºìdRcQäÓ3“›ææBëkƒ°°´t÷ü¢ ²¢Ð*C )$Iê–=‚c’$›ºŠÁAHÞûºªFÃQŠQI™ƒÌC1%$")ˆQdæc‚‰Tf§,eyž6M3[¬|Y’ÓSÓs³sxumucbOJ ¥„Ri)µT¹QRö)±.òœ"£”)SJ BJ´F¤D­Œ1&ø£B)©µÖÆ0§#!I)±uNk( )´ A¥ŒÑR  %ïlÓ4mccd"!ˆ˜I}Ä·öG8Âà í IDATŽp„#á R ¢ŽF»÷ìA‘br½¦RÒÀ ¥2&ϲ‚¤6ؘ@’в\#AJ½”|äÐ4Î{‡({¡2e¤6*3Ú¶6qŠ)Zk}B d@fL 1qJ)%L"a‘cLZ©N·ëªÆê£w.†à¼sÁ#QÙëÝNh-7ž[½sM©ïmll!r2fÚºzmme8\Y™ejzfrãÆÙåµ¥µÑPHlÚú?þã{e¡µ1GmÛ69Ñß²yó1ÛŽÞ½gÏÚp`ÛI˜ÌE^ä™w΢Zë€ÒzïuaHËÆµ«ƒµµ!k£zݬ“m9ú(i¤)2•iR$¤0hh™I@Ï)0ˆ¢km=jlc!²DABäZ* Éù1D QƒÈòÎŒìΖS›U>É,%Hæ”bbϘ#‚KYŽ·»ÅSD$Lœ<Û˜š˜š˜|ˆ,cf • š‚!ŽBE@—PITYR±‚v”‚o@'NœœDÐR;O‚d¦óa뺭ë•ÊäØéJ3ÙELB#¡ D 艜÷MÛŒªv~a~8ZÏ E„Y–Åp¼X—ƒá¨m[̲L£:Jȶµyž%f£ŒV "7‹$öÖ…”‰2ØP*¬”ÌTÞ/{U"ð I’JHˆÌ€Ì1ÅÇ’Ê(-…$@@TR¦9&@’’$Im²"ÏS]×¶®XgBl˜žÉ:½hÝÒÂ"!0ªá]{}ÓT.¸^¯Ø²uKYæya&&'Ž>ú¨éÉ)fžžnòNï[XÜ{×>ä cL)¦t™—³Ó3J"Z^Z\¬Å²Ò˜²”Jxë½ó¶mY&½õ£4’J*£%*P)%ŸâxŽ HŠ"Ó‰“‹AH©Éòü? x¬›&†X”e²Ì³Œ [Û:k#S!A(EJ2aB”JFï#‚Ð*Ä!aH€)$—jÅR I‰JAJ "„‚JAHDBJÀHŠ˜3&`Nºywvvv¢ßÕZ &ïÚ••%;?ïcC˜Žìçü_ýN’[·n5ÆÜu×]¿äð裎1þªØH÷ß}ð?‡²,·nÝúë†ë<ÂŽp„#ü·cŒB£µ¢¦in»ý§Ö[WMNt³LOOÍ’’ªÈ³N§H!xIDU=¢erÞ ­E¯ßñÁGuÝøÖ·®É{Ó­mê¶A"cŒÖfzzÚÚ†ƒ‘õ1YkGç|JžARJ"³жä[GDyQdy>Hã­oD1¦¦iZkó²(»ÝØZh¼­‚³­mªè,HˆÁ% !D]ŸÜòêÒÊê’™ÀØí•s›fïÚ×Úh½mj­ýè?¾ÿ}¥d–gSæ¤Z©"Ëbð0¦PDÆèS$f@n\S†ž}tá¶·“À¬“÷§'ÇC„˜I mL„@ Àœ¢m­k×V–ÖFƒQtžC ÖYcÛDdDÅ(dÞ)§ætwCÑ™AÌêÊï!$n"z†Ä µ>ZF"€­V(2¤R`_¹Ñz³Ì ²lûeÑ“*ÒÈšd¦µÐž’ Ð:‹ˆ’¡@jÅìcÝz_{H@I“0èÁWmtÐÚ˜$›†[lªìdÀ¶­ÎH©\fBD!|¤H®õ£ª.Ëø}ëœtÒIôGtúé§ÏÎÎîÚµëÊ+¯üÇüÇg?ô¡MNNþB‘øÃ7ÜpÃøxÆ —^zé£ýèápxõÕWÿíßþíØaé~åœsÎyÞóž·}ûö~¿çw^}õÕ×\sÍûÑ#ùÈ3Î8ãÔSOÍóü /¼gÜÎsÎ9畯|å=k»îºë®¹æšßà1ûØÇ^ýõ|ào¿ýößÙnrâ‰'¾ùÍo^\\¼ð ­‚¿±æ\càÜsϽ袋Ž=öØùùù«¯¾úCúÐ/­ù’K.9å”SÞþö·ë[ß:”û¾þõ¯Ä#1ž.ŸŸÿÖ·¾õÿð¿­é†ßX‡£í/{(<ñ‰O¼ð O8á„Ñhôõ¯ýïxÇ!&ã9œßÓN;íµ¯}í‰'ž8nºé¦·¿ýí«««‡Ø»…ò'rÁlܸñî»ïþÈG>rèI¡ðÿì›,˦g'm°ëëËû÷%?œèõûÝÉîdYæý~BÉ6MíÊN¦j^Z^ùj'&’B“ T¥õ+X o¹õÖN¯·qã–¹ÙYSÛ¦g7mÙ65½…°ÁËýbiii8¬R J ­ N\U§-‘·=­¤ónz&Ïs)#2¥ |âfԌֆFg™Î}Ù‹m‚ÔšÂh#•–®‰­µÕú°ÍŠ•Åå;Ížm7oÝrTo²Âŵ5©¤m”ÏNÎÌMÞzÛ™C·ß;.ÅÅÕõù»÷V£0mP¥…ZÛŒªQŠQÖd½ŸÙ4'¤@‚¶­mÛt;àþ½{ô㟘<'©f7lp.0S]5•­Pc–›NO'ßD¶)a 6´i°8u«Y)Ï"¶É…à,{  E ¥JÚ$¡HhÁœ §hú ؇P CÛ¢1…ªÕ͈$*£˜ÙE;²k·*Û¦M!uóÎdwº,úZwصݩټS¹1˜“×^ú ƒƒÆÅ&7Ut31!”£QMÞjÁ…ظ¶i$’!¬êaUUVp$Ø–yÁ¬&ÝÙÉ޴蕹’2‰1ˆºnµJJ%„d (¢B©3XÙ¶õλ:ý^§×mªÆ9Ûé”’¤³>„ P ¢·Þ'9Åǹ7±&)ÔôÌ\Ñ™ÐÆÄ˜¼÷ÎR*3ÆdE@'-µ@²m*ë£g燔,1ÖQŠFÖ&‚é,ëô'š"‰À™}°è@ItÞ&R¢"ÕÚveeéÎ;ÍD¯o[KZ«I©ŒDëƒÁÞ}{ÿã–¬×âSNNö§é ³[6nT €I3;3=35#…àɇ’·ŽS⋼Ð=DÑúè86Bç…`ä¢S¦”QŽs}¦DB%I#  ¼È´1ƒUMe} DȸD)&|UÕeV'§‡ÃQJLR"€2ZHÙº– [g]ˆR‘4eG+U–%µmØED¥ó„S@D¤dÖ+ºšt5ªÓh(ÊŒ!€2FkBŒÀb¼‰S«CS7@Ä.ÄଠÎC€MmQY”™ÉR„¦nšv´¸´?Ķ,Æùu<eyÙ‹\Œƒ$Åœþ¯Í¹eË–óÏ?ÿŠ+®øo±9ßøÆ7žp ãaÓŽâýïÿ5×\óº×½ÎZ{ïÌ¢_úÒ—~U ˜Ã‘ó}Þ÷·Î»Þõ®O<ñúë¯ß¿ÿÙgŸýñüôÓOÿó?ÿóñÙcáÀÅxÀN;í´Ë/¿ü?ç‰Í—¾ô¥‰‰‰w¾óÇsÌßüÍßLOOÿBŠùûƒ§?ýéÇüÍ7ß¼²²òð‡?üꫯ>ãŒ3Œ5§¦¦¾öµ¯µm»²²²yóæ×¼æ5÷IsÌ1çŸþ§>õ©ÖÂÿL§ÿK¹à‚ Î;ï<¥Ô;ßùΟýìg‡¼Âð›kÎÁ5ö±}ìg?ûÙ/~ñ‹ïyÏ{N>ùä+®¸bÆ oyË[~¡’Ç?þño|㥔ùÈGÑæ<묳ûØÇ~âŸ@ÄãŽ;î%/yÉ…^ø˜Ç<ÆZ{Øë-¿¹4GÛ^ö>¹è¢‹ÞýîwþóŸÿ»¿û»^¯÷ìg?ûûßÿþßÿýß߯í=õÔS¿ò•¯|ç;ß¹üòËgff^óš×<ö±=ë¬³Æ ¼ÏÞ}ÕUW=ëYÏúøÇ?þùÏ~ëÖ­OzÒ“ŽØœ¿³lš.¤’EÇ0¨BÇàÝpu¹P¢˜™V¦f:®œšQkëfiQ­®¬(“!êÁZ»¶ZGnaq`CÈËŒ|L.i 9î^\üê·¾í#>ò´GNMNôŠ"+Ål[o^ÙèC›RïýÈ9*ËŽjmu]›23ؤ¦¶eígfÊf}àš&¦&ªz@dŒ!Ö®]­c'r ëÙˆZc‚àÆ6¹ê$ë«õAlü¦‰ÙÕ¥µ•ÎäÂÚpqX©¼Ó›™Z]?öø­,¯í»ëÎý»÷LäÇl™›«ÃoÜüµ½{÷‰¼XØ?¿ÿî} ûç}JS³³³³³eYVumB!zE}Èv¶ ¾µfb2׺ßé­¯~òƒŸöŠ©æ87¨GíÐæÊ„`«¦R"a ¤@#…æ€ëÕmK!ª„ZfPRjltè4‰l‚PH, /É”Yå]j")¡!M‚ShÛzGk¶Uëƒ)0'·”ûä9Õ*:ô®H9ʪi›Õ¤Ë¢œŽõF_×5u»jª—çW\ÛÙ8`—R££@D¦”¨mV rÊ3]–yõrbÓ”À˜j¬¢6¤&ÏQ”™RF@Ê…h…Í«QYjßjßÈÔ´¾²‚ÉIK„2ÓY§€Ö®¯ ›Ö¥…T…ë!%Dö.8çV–VXR ̦,¤1¶µ.ERª?9ê¶ÄÖl­Îò¢ÛõÖi)1:/Om˜­†CÛ´$…Èd¤H$Tžw»ÌI”„¨³ÖчCbFÝnfŒÔŒ“pòŸPÈCëZB˜œœà»÷ÝR’Æ”SÝé4ëcjSXïÖ׃õŠ¥S6;;«•ñÎ/Ì/ïÚµ;…Tf¦Ì;ÖÚèB‘gM]Í/ìëvËÖÕµ«jW—ý®—ÌŠ2(4 !§À*3Yn‚¾^«"³Î%+”$!bˆóóû)ËònÞQ¨míL©C`©²¬@VEVLt#ĵÁjc[’†Tælо’ÂrâI#Œum d® CˆX”]&ÚÚ±7Ý\w "a[—RL‰¥ÔÌÜ+{1F"*³r²7増’²<‹ÛÄË2÷­ãÄJ*%¥ 19QšL“Œ«k kkÓ)Kèw{INØÔn0rŒý~÷ˆoíÿ>6oÞÜëõþå_þe}}ý—^p?YV÷yßûc&âÛßþö‘Ù?ÿó?ÿÙŸýÙ¥—^º²²/{ÙËîyñÇ?þñ©©©ÿ÷?°${ÒI'yæ™7ß|óx(ùº×½îòË/_[[»_ŸùÕ¯~õ=‡’þð‡_ö²—]|ñÅc¡ ƒ3Î8ã»ßýî+^ñŠ÷¼ç=¿´†½èE÷÷CþŽpÞyç]}õÕÏ|æ3Ï;ï¼_%í{s8šsp½ä’K~ö³Ÿ{î¹ã ¬µoxÃÞûÞ÷‡Ã5dYvÅW¼ï}ï{Õ«^õk5vuuõÿøÇÇçŸþµ×^û´§=íÚk¯=LŽ4GÛ¥ì¯âÁ~ð_ÿõ_èCzéK_:þæ­o}ëìììýÝÞ½èEˆø”§ñ‰O|Îsžó‚¼àꫯ>ÒspܱG™,Ó™ñ!./™Å¥%[ÛfØ`¤nÙ-ËܦÓ5““å†Ù‰à}Ùéûö­ìß¿ººÚh³<4L¢±6Ä"a`HL1ÑâÒê·ÿ¿ï3ˆÓñˆnw"SXö:8þ˜[šÁ°;ƒA¢ˆ21ab)tG›Œ¸ˆ>‘â„$E„P€¹Ví¨&€² ÑÇ %%Á§Ä>†Öy HPv:ëë£;öÜ515ÅL¿?1=3·ySžçÕ¨¬5›7MšBªjÿøÓwý‰aÝb¯ß‹HEY@U×Ãá0DÀ$ˆ„JEÎ)Õ£jeq©­êк‰Þ„$Y˜b8}ÿ{?p> ¢6´Ä¨¤4Ih) 8DDFfŸÆ.µ#FÂP¢B©4R`ͺ‹eW¤„ãÄÞ±E•¤LŒ1Dk}]·Ãµj}¹¬Z7ŒÑöÌ ÉqjÌÈÉ'RÃÐH °·!4×iMª®:Ž.µÌ±/Hƒ”Z+M2Q¬F#¹†BÀÄ1!AЉ‘0 P ’·!ùŠÛu/ ¿¶4ˆ¤ÄXš#&eDfT¦¤QÆ ‘½ ¤x¡Ti 33sÕ4!F%%i•)C€À,«Q5\[omË’Ñà„îOMNy‰½óÁ{kmdˆ)Ř˜#'nÛ:q@`ÐJ+©j}+¤d<ÁϨ3ÚÆG‡Ä$eQv”Ò>Enmðaue0V«kkÛ¶çEpqeyµªªÌdý^onÃ"­¬¬,,.ŒFƒb”%ð£j8ª«ÆÖY·…Ž„ÖÙ#'PRj©”TcdNÉûàS°ÁÅ@ #- Æ‘„˜8r„à1Ä%˜uʬÌ×$N.ˆà£ÀHªB«”"s’R˜L«¨9¦à½' @™c  H« e4 râÀÑ»‰³<“Z#"±$f˜X‚ !QB¡E–wRJÀcGô9%Á  @†D!bH"Ab"" ˆ’ɉýGðøãÿøÇ?>??¿¼¼ü©O}êØc½çŒõ?øÁÿøÇkkkwÞyç?øÁ_xÁŸvÚi7Þxãþýûççç¿ò•¯üÁüÁSŸÿüçwìØñ„'<áÁ~ðŽÿdì½y(¤f8û쳿úÕ¯îß¿ÿÆo|Ò“žtã7ž|òÉãSÏzÖ³>ûÙϸrûöí_üâÇÉ ¥EÇ{ìŽ;N?ýôK.¹d×®] ûØÇÆa».«û|æƒðœçs8šðÃþp,ÃWªÃ‘Æáhûá”}á _(„xÓ›ÞtàïýÝwß}··ßﯯ¯0)wíÚ¿ðcx[÷'?ùɃóc:eÑïõ´Ò(R ¦ +K£»÷,ï¼}ïO~¼s÷î»Ö†ˬ&§6uÔ¶cŽ9æ¸ãyàƒŽ9áÄm}øƒOyøƒÐÖ ';ÝB* ™€V"–÷ì¾ûûßûá®;ö,.,FµjÓ¦MÇ>à˜›7Ìmš›îôò!BÈK#•ðÞsŒ…É ­šäƒDD$DQBI ÄcUUuÝþ<Ù o­u!DNãì ‚¨®êÅ……Ñh8¬†{î¾ëg»v.¬,£ÄÉ™þÖm[>fÛÔôtXZ[kœ÷‰U½oqqï¾ý+ëëSÑíÌl˜œ™–Fû"'@ %•1&ϲìq?û O<ç‘§?¢×ë(¥˜Óh4Z[_­ªÊ‡0¶Ê$ E2º4E¯ètòN®sER‘,³lݶu“BTRwËÎäÄäìôl¿ß/Ê¢Ó)ûý^§ÓQRÅœuÎ:çœõ>ĈDRi!eŒÉÚÖycŒ)ï" JK)“ë,7EYÝRj%êö{Ó¦M'FŠL‰\DR$µÌ;Eoª?1;557=97Ó™êS]QjÈ„(•êÈDTœ4ÊRçy1ULlêOm™˜>jbjs¯·±,¦•™fBSª˜ÖÙ¤Ô=‘M¨r:ëÍæË™£ú›ŽÞô€ sýC]çܶmÛ׿þõ]»v½êU¯ !¼öµ¯ý¾ð‡.;11qã7~ûÛß~ÉK^ÂÌxÄ#¶oß~`þÃþ°â /Ü´iÓß§Ct ;xÍÇsÌ7Þø­o}뢋.:ùä“?ö±MLLüÕ_ýÕ³{ÜãîYÕãÿø~¿?þxð@Y–yÌcÞö¶·MNN¾ÿýïwÎþùJ©ãÁeuðg>8c÷°¹¹¹G>ò‘ŸûÜç¾÷½ïÙŒ ðâ‹/Þ¾}û/”=9ü¾'tÒ¿øÅq‹æææ.½ôÒO<ñ1yÌóï ²úµ^Ã'tÒh4Ú¹sç½O½à/R^uÕU÷¼ø–[n9ðq|ü‡<䓟üäÝ\õqǽèE/úÎw¾sˆãÝ1ï~÷»gfföìÙsÕUW}ãß8ÄRguÖG?úÑk¯½öâ‹/>çœsÞùÎwzÿ}ô£ý±}ìºë®»øâ‹õ¨G}øÃî÷ûeY¾¶~_ضmÛu×]÷ï|ç×u?ï¼óB_úÒ—6mÚtùå—ONNŽwÖÍÎΞrÊ)÷¾>„°cÇŽß®æü‚Æ*¥îiD{ß 'œp`òÉ'Ÿü§ú§}èCÇ\B¼ð…/€±átŸí½Ï&ܯýè7Óöƒsæ™gÞqÇ¿4ˆÚýúß¿öÚkŸóœç<á OøÂ¾@DÏzÖ³öíÛ÷•¯|åPÚûð‡?ü+_ùÊYgõÒ—¾´,˯~õ«øÀš¦9b}ýnR56¡°Îªv0h½ƒE5òwìÜ»¸²nº™. ‚Ê2?þ¸c‹brjjróæ¬Ûë «j[äªv«kõî=ûò;óù…Õ¦ñÎ'k›Ä!Aò®ß·øã[nͤ:îÇLMõóB}ôÖÁ`µi«ñÒͨ®[%3Q£;y!”DH€,¥Ìó"xßTuä”"ø¼s&åP ¥¤8Æ&ÓÆèQ]-,.H­ff7,.-Þö35;=}ÌÖÍŠN¯³yëQsGm^Z_¯jU枤æÀÐÆ`C”Ƙ±CŠ)‘ÐµŽŒ$PJ¤˜ÖÚª­ ‡KuµÜH@Šˆ!2§ÈÄŒP$”@ˆ,‘SN@„OBŠk«{½D(”ê™®š%á%ÆèBômb[¢à£w<„Ùû(1+ ÄÇéYI`@œ(ûÐŽ*T€ÈPdh­õcL(ˆ¤DIY™û}ð(II¥¥’R`ŠN a”“Úš H!³<‚ò¼!¸à'’BiJ„ËëªiªÚZ«Œ.ˬ,KkmU%ëÀ‚föDI)2Fu²ÜYÖy>4uE¥€dƒµ¶®š“”’lÓç¡PJ’ôÎ¥FÃÑÚÊJJ!+:R(BÀ²ÈŠB.¯®Ä”œ÷ bt!8ÏÁûÜäJÊr¢”¤‡Ãá]{ö )çææime½nš­[·ž|Ê øqž IDATöüÀýìŽÛ /òQ3J‰SbDÁŒH ™I ºLeBLB°­õÞ+¥¢sÁz,)IR &Á„€¢DI˜Ç½ @„ˆ ˆ8µÖ:çRJRD‰ ˜S`–RJ©ÆòÀ”€„Q²“çy‘qKè€SÊòœ„d©U–åF!•É2nÛ&A2™ŽÉ[o¥$! „À¬0&×B ”ˆ!ø¶FdÐJ"I!µ ¥’:×…–½÷1?T›óÍo~³sîq{Ü`0ÏßïÚµë/xÁØzù§ú§{NÌ///_wÝuÛ·oO·ŸrÊ)SSS_|ñ·¿ýíñìþ=kþèG? çž{®1æ×ÍŸyðš/ºè¢ÂSŸúÔÑhôÑ~tffæÅ/~ñ!Ö|ðÝsyíxÄxýÞ÷¾÷Pduðg>8·ÜrË-·ÜrüñÇ¿óïܱcǽˎøK›y8r>ø}_ýêW‡žò”§Œ]ƒÁUW]uöÙgßtÓM÷)«Cça{ØsŸûÜK/½´®ë{Ÿ}ñ‹_ü¯ÿú¯÷Œ2==ýÍo~³ßïïØ±ãsŸûÜÞð†ñ—ÿ5#†ï~÷»[·n™™ùÄ'>ñò—¿üÐcÜqÇý~?ÆxÁ¼ìe/{éK_zˆ{ºþâ/þbçÎÏzÖ³RJŸùÌgŽ;=íi‡Ø_ÿú×ßqÇÏ|æ3SJŸþô§;î¸óÏ?ÿ—.&ÿºÚ~ÿõ…ûä÷ÿ÷¿öµ¯ ƒo¼QJùÔ§>u¬ögžyæu×]÷KyU5^Žþmiν5ö§?ýé©§žzÏi8‹ˆ>ô¡]vÙe·ß~ûo`snܸq/jÆ £Ñè™Ï|æ7¿ùÍCiïÁ¹_ûÑo¬ígË–-{öìùUæèý÷ß¿îºëžûÜç^sÍ5 “““;wî<çœsîÜû í››{Ѓtýõ×âŸH)½ímo{ò“Ÿü„'<áˆõõ»ÉÊʲ®jRëbk½ºÛÑÁÇÕõÁÏvï–¹ Û¦˜úýþ©[G‘ôló–½É‰Q=PFY×MoªÛèOí]ZX\ µÕ•ºi ²”Þ†[þㇸSäeiŒ)¦§§¶lÙ<ªË+K‹ËKËk¢nlN1uò¼ßëEG–s­³Œ<&!„2:/Jë<» SJ) E–«HJ !Åc{ýQ]¬µŒ°>4;›^§{üŽ›íOD„‰™‰é 3ht圬“g cäÀ´T9Ù6ÄèƒOœ 3³$¥jëÚ6>EÐÊ 3#””‘¥*¥B’ )°”2Ër"ˆœ@áŽ}!1ÿ<À-Ä=ø˜‚DJR1’TR%ç ˆì¯Z;´vb è1 Hˆ 81SJÀ(%DÄÀÎY—ªš–dÂÈ)Äá@À¼†œ6 —Ou¤ ‘9"ynk N#fRª˜‘Æ„DcJÌ”8EHQ2#‚àdmŒÖsd‚ˆœ÷œŒZ¡.* RI‚Pd]ƒ…@%0¤HÑ“¯} "À!¥”¢B€c$'%ÈÜ蜴$fHbˉüPmÎ'?ùÉ_þò—7oÞ|ÀOl÷îÝ}èCÇÇÌÜëõÎ;ï¼mÛ¶u»Ý±êÜÜÜØB»óÎ;SJù—ùŽw¼ã»ßýî¯Ö1ãã”Ò=C×¼æ3Î8ãË_þòWþ 7Üpè6çÁ[tÏuÅ{‡Ò9¸¬SÿyÔ£uÓM7Ø“výõ×øò>euˆÌÌÌ\{íµ_ýêWïí3<GŽ#”þÂjOJibbbûöíKKK?w9‡ÞûÔºCá²Ë.›žž~Ô£õ´§=íæ›o¾ì²Ë¥Ô'>ñ‰+¯¼r|<55µcÇŽ÷¾÷½Ÿüä'e/Ùi§vÝu×ðÛüìg?{O›óà:ù e?ÿùÏÿR›ó7ÐöÃï ?úÑ&''ï,êPèv»çœsÎxcówÜqÛm·wÞyc›ó†n¸w¸cøÏ$쇯9ÑØ÷½ï}W^yå»Þõ®k¯½vûöí¯xÅ+š¦¡ÿÜàðÊW¾rãÆo}ë[³>2/»ì2DܰaóŸýì7¾ñ7ß|óÝwß}Ÿí=¸¶ÿV¤ñ[×öƒ#¥üU>÷ëÿè£~Ík^3??Ýu×MMM=ÿùÏùË_~ÑE+?x{•RgŸ}öÙgŸ=Þ‘þÅ/~ñꫯ>÷Üso¼ñÆ#Øï wïß'u¦uÞéögf{Jh‰2¸°¶¶ŽÄ‹Ã•6úªnêÊ..‡·¼Z­,Îxô©6N1¢ÔôDvm0EÞí÷;{¹0zuy¹mZ` ‡ ûvu:>þ¸·­Ûé¢é¹™ÙÁìÌÒôò`ed+XZKLµF¬«É\wË" Ö:p[bDÂûÀ³EJ™ÉBîFuÝڃϴaNJg&ˤV>lH>aZ¬þðÖ[¶o?ñ¨G=ªßáèçwÞuÇoý 6ž‰F64Î Šn§ÌK]$DÁû#i¥Ê"ï•Ý<ˇ‹ƒà’@¥¥µÞû‡èZç†ÕÀŒTÆ™gØi”Þ;m dŸDB (%¡ÒR¡Ž(‚•”D%@ÊH"$P@"¦ÈÎÇÖù&ø:…À¶M " *@ H(•ĈÎYoG)Õ„ RôªèEå›zieQ=w7çy!3c´Î’ªöÜ ÕŠI¾PÔ“Y–$QDB!FÀ1bŠr¼Îéœ6#'’I¥DQ D™*'»RŸØ…àƒsÞq’¡èv;R+}tJGDàBŒÞ‡Ö¶£Qµ²¾æ¼;9êzm0DD䬵®B# Á;›BH1zÛJƶ­ï0°Ö"Ïó²Ì9¥j4HÑ­®,CH)D ´QJKA‚„);mÓÄ •4J)Dá}`€²ì…˜yXæ—;½ÎdoBÓŸšD-‡uÝ:'’ðµmÚFIÕ4õ`}] #¥Œ‘÷ï_ê²(”½^Ïä%$ ƒ)ÔöS#“ ±[îÚµûÿgï̓/½Šúÿî>˳Üå³Í|fË ‰€øÕHŠ TðM E„”R”²– AÅ äKA€J" Bi%ˆø5$€¢(hiÈYÉ6™}>ë]žíœÓÝ¿?njj* “!!€2¯¿îö<÷ž¾ý,}ºÏ»76&!DÂÔÕëEž-..Ì-÷·-.YÚ°²²«nÚqŒQ“Q+,©K±I]]ê|ዲp™/|¡Š)$P$2¬ÒÅÎgN;‰!¦.±@‰(¥¢ ¡*'N*lElT0Ä Y‘gÖDNQbÑï“5‰sBÄ s;ÈJãYƒÆD#mœcÙ+¼w‘c—:6½¢Úum[Wó¦oƒ "ÄëjŠ Ež>‘®é'O&Ïò2/3—RŠšÔ÷'§!dŒÙ²eËóŸÿü_þå_~PÒìÁ3žñŒk¯½vccc–X˜M;çŽMî¾â¯ø³?û³¯ýë1Ư~õ«oxÃn¿ýö“<ù>ãÏøÆ7¾1{|÷ÝwŸuÖYÇOŸ`Ï;wî<¾JêèÑ£'Æ?ñˆŽq|]ëIÚê1ZãGÅÅÅãE2677cŒÍ <ÔV'I¿ßÿÇüǺ®_ð‚ó™×\s͉7$¢mÛ¶/ìy¼·ŸØ'gÛ®®®{ýøÇÅÛ¿/Ç‚ˆ<Š ä—~é—¼÷ˆ8ë´wïÞ_üÅ_ôÞ‡ˆ(Ïó‡nr,ä~Œžsýä'?¹gÏž7¾ñ¿ÿû¿ï½÷þöoÿö¾ð…Ùèfý9ÞøÆ7ÎtÊg'œ^¯7g)â“qžË/¿|öøýïÿ]wÝõÎw¾ó•¯|å#Ž÷ÄÞþØ­ñ}÷ö“È­?l`9óöÇïßÿÀ>°uëÖsÎ9g–Ù¾æškþáþá«_ý꬧ԉÇ[UÕêêê1 ´Ï~ö³ŸúÔ§f«O`?Ž 5mKÆ ç§ï9½,û¸žÖk«…q‡SYÒ-]+ãq³9šþ÷ß¼±9¹÷þûŸtÎgœuÚiOØ6·0Ηy9È‹~^ôÃÁââü¾{¸¿ÜXÛ¨§ŠJŠ¡ë:´²ººuÛÂt!Ë}Ñ/‹^é󌑙…•»¶Ö6‘1BšõKK˜, ZÌó\D¶,eE9OÚ¶­¦Ó¹á°ì bÓ¬uÍÆÆFFØï D„9²$îºvZW£Q^–m×Ý~Çí_ý×~Ê9gïÞ¾Ý~nËÂî3θ÷àŽÅ—•}1]TEë|¯×‹)5MÓ45'&"ƒ`"Ò„µÒ*.|i‡6–eUÆ£ Uíº6qŠÜ¹Ìf¹És_”yN^‘}n{EÙÆ6I”$¢Â)IJ7Æ4*$ÚµµÇjÑzc-Yä XÐbq J  ¬Ìš¢„66§Î ¢`PR €$Š@„$HJ¤† ¢‚UhÛ)×4ÝH%ëgy|îă¡ÎsÐЉ¨F˜XÕe¾ 4¬¢hÔ‹ˆ†É"*BnÛ` §5ªA*ò¹u>$­§MÂHÎoÑPbnÚZ&R cò¼4ÆôûƒÌ¹^Q¬¯®Gãj2i›&¥T}$Дb˜„º©Û»¶@oJ‘Ð51ö¡,‹……ynÛvZMØ> ¡#d2É'ãI]W)FADP @!¤ÄeQö‡ÃR`QQÃ`3Æ *1§ªj°µ¤)YY1ÆÄí±(о¢pD0VÁZkEÏû T!Ëò¥Å-Mۆح®¯9gúýrÿÁ½ß¾õ4XäE^æ;–– "UuCdëº%MªQ¡ÌÊå-[Tàm$ÑÇ[re^zÍÀZÔÈ)pLÀdÐ9g­M‰Ñ sF"b,ùÜ!¡ªŒF#‘$Ê @@@.ó1¥Ø´€)¢³>Ï¢pfM>(½jÇ©×ïÁ¦©%tÖÐâüB- ˆ ú̃’,ùÜ¥GcaõYp-s_xJ1Ä."¤®›LƱ öÒTæzZ)‹%ãŒõÎe>ó.ƒ¤›æäòœÌ\×õå—_~ñÅ?ìÞ÷¾÷Ý|óÍÏ}îsg³ËçŸþ‹_üâã?ð©O}êSŸúÔŸøÄ .¸àíoûg>ó™§=íi'yî½õÖ[ŸûÜçÎ?t}Ë ö<ƒÁ±O‡ÃÝdÌê¤gEñ=hÆCÓ>h«ÇhAêº>¶vfIçÜC›µ<º$g–e÷w·eË–g=ëY{ ‡Ã½èEŸüä'Û¶=þõ{î¹g&W3[KùÔ§>uä|_¼îäùüç?ÿŽw¼ãç~îçN&æ|³Øïd Edccãx?^¹äÄ>)"«««Çߣ7Õ“ïÕÛˆÇÂóŸÿ|yë[ßz,W–åùçŸÝu×]pÁ'®®|ŒžsUÕw¼ãïxÇ;Š¢hšæœsÎɲì¶Ûn›¥ÈúýþÇ?þñã‹K¯¾úê½{÷ž~úéßëð766n¾ùæg>ó™³Tó#ÖÖžÀÛ£5oDn¾ùæ_ÿõ_ÏóüAç„“±Æcﳞõ¬¯|å+ÇJ©¯»î:U}Îsžó°}Œ4Þ½{÷ 7M“R:þ¼zŠ+²¼È-õý­Ë‹;woöûÀ<OœçŽGf°k\×M#1ÒÜ}ÇÒòRQ” ZöÌ6ô Wz;,‹#‡Ž9td5Å&Åîðáƒ÷ÞsÏüB÷é;Ðds óÛ¶o[ßÜ<²²š=›`ÄZRUà.ÔãI†,tÀê)ï÷¬s½^Iƶ]èBhÛv:úgLf}¯×K]SMFˆT7Ê‹Üe æE¦0¨Ûê¦[¾uã·ovÖHLÆ»¥å­§í9ãà¡Ã!JRM¢!&Ÿ ëœgkÜ Yæ¼SfeN¡nêi›Q¿ÈzsÃ9‘0-2kÀy“å>&Rç}QädP•‘,‘AeQUUNÛ.†è ƒ‚Êšb×Ôb|4˜‚PA•¼‘A Á@D`D%"M- +²‚(‚ªQ@UQP@éZC jD%┢(©’‹Þ’%g¤Ìí|/#§(-„i‰‰%RŠ¨Ì€IÕ[gŒDaaE4Æ(zD2†Xš.ƺ%‹ÈbÉf>Ë‹Òå9…XÕMÇ!rRP!”Ä)Å ÂÖbÙ/³ÌÏÏÍïܹcqa>…xèÀýû=HÐu]ÕLµ‰ƒHŠÌ!†(Ì’(FffžN&Î9(ÊÒ9×ëõÚ¶%CÌÜ´M]W†(Ôµ6t]S7˜ç¹! !†SE`EpYÖëm!Ää2naqÉ9g3Û„&˪""Cƒ¹!ÓÆÐÄEÑØáp™IÀ¢‰16¡›N+QðÞeΪI”¿sÏ]‘Ãd:Z˜Ÿ1=éì³÷ì~‚wÎyë¼çw¶ÌsoŒSOëÕ#«Èg…!»´°…ФÈm쪶©Ú:HTRkQÆØÖ‘£1ˆÐ:—gE¯ìÙétRèee¯×#CmÛ4]ËœŒEDTVæHÎ+"*¨€°*0 Z›e蜠T®º`¼1y>è•ÆP'1@²Î;—ÙÌå½¢è÷BìxAÌY‘ØÕUlqÖ:rM ‰ ‘’FbÐ(,SŠ][Ok5H J€yž÷z¥%ÓÈødkk¿ñoüÂ/ü">ìÊ´³Î:몫®:VÎtþùç?ìNî¹çž+®¸b0¼ë]ï2Æ_þ4™LŽ×,9žñxüˆZ»ç;ï¼óÜsÏ=ö™ãWRÍ.ùÞûùùùÙ}á1=ÛïiDÂV'cÇØùQó­o}ë¼óÎ#¢Y®`v§û}éòj­ý›¿ù›'?ùÉÏ~ö³¿› ÏË^ö²²,¯ºêª½þ¯ÿú¯o}ë[·mÛväȘ­ŒzP¹ï 8¯;Î9眥8Nžg?ûÙ37>™ß~ûíçwÞñ™«“÷É›nºéxÿ>zûc?^øÂ®¬¬œ¼”«1æÂ /¼êª«ŽÕÒgY¶¾¾þüç?ÿºë®û·û·cñÕƒ"ä“÷œïö«NÆcÅu¯yÍkêºþçþg¸í¶ÛfÎŒsÏ=÷Š+®¸øâ‹¿ô¥/= Ï1Æœ~úé³-8Þ{ûc±Æãçí'æ3ŸùÌË_þòßüÍßüÄ'>ñ ·×<oß¾ýØÓååeDünÒ»ï׿þõ™zÐì\ñ¤'=ÉZ{òMeOñ¿ŒI]õ=ãŒ/,Y5^ûy9?W ‡Þ—8Ma}4™LCSËtýê„ÙÙãÊê¤nîm¯¬n>áŒÓöœ~ÚâÒÂÖ­%"tMܶ´´kyùÀ¾Ã÷ô …X7£”¢p7Ø/7uh 1«q¾×ÖTJ™sª«zõБ^ ’Ù™ ןzt>ÏMÈç]×tÓÉ„—¶:2ÎZ m3™NbŒÆX²Ö*JŒ±ª¦.óYž-nY+‘¨®*u䀩m+c]^äeoˆ„U5^[_‹©«ªñ´/.,ôz}$ì÷ûœä®»î:räˆ÷Ùp0ŸbôËÜ;kLž†¨ë‚  s~nn~ÇŽXµõÚæF'±m‚$µ–ˆÐ¨¨3«<0ëAHÞ{罈¶];»ƒJ)CŒQU³HÚ.uÑ¡ ­µYî\¦Ö0!c º É—¹-Цk1i™•®ÈÕyêõz䌀Ià¶K­s6÷UR×p#¤ë&Ô‡ ‰5)*Æ.I$M]§gõâchZ )˼³6Å()IªNMûÐ áñY޶mgÂï~÷»¿ô¥/}ä#y÷»ß}äÈ‘³Ï>ûÅ/~ñ×¾öµY]з¾õ­½èEõWuÿý÷?ïyÏ{ík_{ü>ŸóœçüüÏÿüßþíßÞ{ï½{öìyá _xà 7<(ĺùæ›_óš×¼ò•¯üÿø¹óÎ;Ôsâa9ñž?üá_{íµüÇ|Ùe—=íiO{ýë_ü¶×_=¼ímo{Ï{Þó“?ù“¯{ÝëG`D'æÄ¶:k<:–––fyÝ<Ï˲œ¥GF£ÑL®ó±ØùÄ|üãÿüç?饗¾ç=ïY^^~ÿûßðàÁãûÐö–·¼åÃþðïþîïž~úéôGtÝu×}_îhOÌg?ûÙ/|á 7ÝtSUUçwÞ{ßûÞÕÕÕãË/¼ð²,gâ™\pÁÊÊÊwÜ1 Ñ?ö±}ùË_ž„_xá…o~ó›ÿéŸþ馛n:™ï½òÊ+¯¾úêßû½ßûô§?}þùç¿üå/?yŸ|ßûÞwÍ5×\~ùåW]uÕl ê÷ËÛû±°k×®¿üË¿¼þúëO>žyÖ³žµ¸¸xíµ×{¥ëº¯~õ«Ï{Þó^÷º×­®®žx6ád<ç»ýª{ìÎ;õWõ_þå_˜ù¥/}é›Þô¦·¿ýí³çUU_ >KyÝyç7ÜpÃIŽ:Ïó_ù•_™~ã7~ãôÓOŸi?âxOÌc±Æcôöl{b¾ð…/|ùË_þÀ> ª_üâƒÁE]tûí·úÓŸ~\ÿýÏ}îsoyË[Þð†7\}õÕóóóüàUõXZõÄãýøÇ?þÆ7¾ñÃþðÅ_ì½ÿЇ>4"Û§øÑŠ9«†Qmæ&Õtc¼AÈ…3ÃA¿ì-—ƒ^ÍÜÄ4™v£Ízeetdn#tªbš.ŽF£ª®îß{tcc<Õ!ðgéö[†ÃÞ _.ôqXö3o·›G®ì8ÄîèÑ#IÂþý÷ © Œ§ÓûO&µÏŠÁ`>£œ²hBŠ]×N»ÉhÜJÄÒkîrê)‹±VEÀ:ë½m]hê†@U5„™Û®#2 ‰Qš¶±­ÏÚÆç~8?×Tõ}ûî?pøÀâüœõŽU¬uEÑ“¦êBPUkŒ5†».4Ó©¤DþEìå¾0†sÝLcÝF–2+%åIººªCˆdÄF“ÞÛlå’µ‘K"±AÕBPAPcÌ,d›‰îªˆs6ETT@Q’Ì(‡ì ‚XƒyFyŽY.3>!€ ) €2€"(¨F…¹SíXŒ £Šu À€Z2„Ö€Ád)Yà -s ¡q’,‰ZDg,¡å$¡‹ †I”AÕc‘Á2–.‹,˜T‡¦«&S+!GEkÉ ± )/2Ÿ9$Pà”Ú¶›ŒÇ««™±ÆE‘R,û½-[·æy>™LbŒÓzšR c­5’àX°ÄQ$&e )‘‰†ç2krÒ3+(ÆÀÞ˜,ËŠ,ϲÂ;ÀeYlnŽ˜Ú˜#K`žÔ•÷™³ÞY—e¢ì ³Ì{ïÑ@Vd ¬œ$%N<™NUuZUm׆Ó,N9¥zZ…ÜåÞ<Ð8TDD”PcŒãñºh®kƒÁ¶mÛœ÷yQ®¯mþ÷õßvÅ}ÃÞðùÏ~V$¶oß¾‹/¾øø 1yýë_LãÆo|ÙË^ö ïýÄ'>ñô§?ýÏÿüÏgsà '³ˆëÄ{¾îºëÞ÷¾÷½óï|ç;ßBøà?ø‡ø‡Ççv®¼òÊ7¿ùÍo~ó›8p饗~èC:öî‰GtbNl«“±Æ£ãÒK/}Õ«^uìé¬ìÒK/=Vaø¨í|bþþïÿþOþäO.¹ä’·¼å-³œÕ ^ð‚ï‹Êÿ,Y7S‚9Æ\plÓÏüÌÏœ{î¹ððÐm÷îÝûÒ—¾ôŸøÄ¡C‡à?ÿó?_ñŠWüî¼÷ùÈGŽ-ýý÷ÿ÷×¾öµÇù£ýè±æ™W^yå,ä›™îŒ3Î˜É Ïæ&?÷¹Ïs¡Gä¯ÿú¯Ÿóœç\~ùåW\qÅÆÆÆW\q¼YNì“_üâßô¦7]rÉ%¯}ík¯¿þú·¿ýíøÀN²úÄ{þ¡ ³ÂÚ/ùËÇ¿xÍ5×\xá…?ýÓ?=ëôs‹çœØcsïz×»f“mÛþßÿû$|õ§œfò]UUÝzë­¯zÕ«šå{<Æãè±xû ¶=1ªúk¿ökW^yåG?úQk-=zô%/yÉã=Þ?ýÓ?ŸŸ¿ì²ËfªÎ‡~ùË_~l*áÄã½í¶Û.ºè¢¿ø‹¿˜Í­®®^tÑEß“Á)þ7¡€Ó¦‘u8rt… uu-)Åúe¹´¸eÑç6/Bâñhº¶¾¹±1ÝÜœŽ6«ÊX 1mnV++ë++›«kë‡>ó¬=Oñ‰UUÝwß}Ò<{ÄñfYöä'?n¹å–ïéŸâGœ“\Ï¿mÛ¶ÙLñ×þñÿ9»¼ei8(ûY1?èÍõsƒáÖåíÅü:¿¸¸8·0ÔÑæÊÑõƒ‡Wê:nnÖ{ï;<Ú¬67G]×á^ßïØ¹ô³ç=õ¼óÎݳ봲èOÆÕ}ï»wß 7Üxß}÷¯­­'Nd0i"‹ÆZEcó…¥m[¶.—¾Ði=]]ÝX]YÙXÝäÐútP¨ÌòùÞâŽm§yyXTG›£éæh~8¿8?ßµÕÞ½÷9x ›L}VôúCç3@@ã²^áò|07œ›Ÿ+û}T=rðÀ“žxæÓêÿ, çW¯}çŽûP`u}mßþ}“é¤(‹;·»,kê Uc×ÕÕt×öçœõ¤¥ù…¥……Üe›këßøÆû–;«¦Û²uiyÇ´z×ÝwŒëqÑ+ÐR88m÷iý¹¾±R ÈE™õRšT´Tôz–\; ׸¡–M—LH”’„dÅg©è§Þ\è/òÜV,J>W_×=S!¨ÓjzäÈæ¡›GÔ£Õ®7¤Ñ X@Te$ d2¤¢¬‚J 6 € h0ÏŠ¥áŽÝÛÎïbÌzåÜ–¥r84EfŠL Š!›;Wx›;ë-Y$‹Ê’¢uèœqv&ݤ¤‚ (Œ)ź U§Íxumº±¡MиíbÝIà2ï$KÞYoȤ(]Û1 !Y2†H••…9ˆ¤™¸±³½ø³ßÓySDf©¿‡’Rúno›?Þ»wïãq6?ñž÷ïß¿ÿ~xX)Žé½ÊSžrã7¶m›çùoýÖo}éK_úžæYNìíÿ…ÇÉsbŒÇ‹iÿOáq²ÆcôöGdsss¶†â9ÞÉdòÝêáq¼]×=bþ?D–ºª­u¶k¹ÉÓæÚ”»}±é|ÖË ÛvŸvÞ3ÎõY†&"Å3ÎÚ¶¸Ü«ª°±^õ‡ÅÁýk‡ØÑæd:OF­¡ÑÆJ›:SÕ­±–œ–ƒü´=;¦u9ÅÇ“±¨8ëBhSb2C%‰ ²ÒÛÁº¦Î›i‘yۤЄª©²^©Æ²óx4–Ì›ù¹…õµµ°9 ]ª]bB“•Æ qÖ©BUÕ]™wÌ|äðáo‘YÎICX”eä4™ŽH«z 50'k,äÞsZ޺姞ò“sýþá‡ÛªÖ[n¿³šŽÚºXXšÎ £&ç"$–ñ´2ΡBòž ¡· äÞFb%cÉzBkÔ ‹„DªˆÖ8KÑ€%IÚ2×]B`g’b‘۞ɘDº>§EÀ„Àcj,w§.j2Eƒ$0†À*V0€Ö–¥-³²,ÊÂõ2W8 í4Õk“:‰Q˜¨jâI]F™ËE8$N*–¬ACè¼Ó\qé"´¼O–-(bæ­#K,,ôIéBŒ‘mJlT´ªª•••»q5ݵkg¿ß[ܲxö9gï:¼¾¾Ùu‘Lu Ìœµy–/,,äEѶmŒÑ1Æ8çD$¥ª„dÈÀ,!i­eѵ ëͤª»ÑÙ²,\–%‘”R )tÀÌ *Dä½Í Ÿg¹µTù¶¥Eƒ"bl»¶ëqn8'ãqÕ´Æ A2H@ Â"Ñ‚&U6Æ»™(&s"²DB$Š£Ñ¨ë"*f™'éd´²zdÛ¶­{ž°´kÂh}c4·m»oÿÞ#GoYÞJÎ BžgE‘·)÷eVä¹ rJ¡m§Œ‘1€À’Rz  MÛ¤”Ô8Ë11ó¬ Ø€UFL¢†e¦/YRˆ®,D8¦‰ !D$c,kÑÌBmQP%QR! ,]ÔI—Æu7®d³Å‰rÃÕ‰wj“tqÔs6s  Ä˜aNÎXc Y"Taaa*@À‚²§Nî§8Å9eYÞpà wß}÷Þ½{gi–‡ÕY9Å)NqŠSü˜›ŸÇ©€¦cCaPÎy¤­6ÃúÆúøî#彇ªi½²ræÒr¿7ç‹bÇüB9¿0X\šÎ ‹¢0Hyæ£ÉxÜLã¾ûû¦Ûž”—™s¶7è÷CbjÛNTªz ¤EQEî³< 6M¬&ãÅvZå„]5×Ó¢5¦È²¤¬)„BÝŒW׬-‡ržˆŠ…|P–AE Y—÷š4¶!E1ÎYïE ÅcÕ²ì!™ÍѨ­oÜŽm»·/ïØÅqnapðÐÑx³éæè­‹±#Õ¹Á€Pªé8ÅP–Ŷåm…ËVWV§U=­¦÷Ý¿÷ÈáƒI»~¿•»€Ð»œÈZãœ3,(šBMÆjJxTLI1jTR“YTBAeFç<¨ (8èQ2ê06\%‚ˆ–UUUW "å6ŸéĦ֡LE:AQP`€$À ÁY2 **‚d½7Îgƒ²7ß[Ú2·sÛÒÂ0ÏH$vÒµ&FËIb¤¨–D’°è¬8—‘#FU@ECˆÖw”©²5„4±ÄšSD4b¤–»¦éÚ6ÆÀ)!0hªªbP Œ1%æ£GîÛ·o}}mǎ툸¶±ž8Í4bµ™÷™µ™ ý®mZeͳÜZ“¬aB Ä,s)ù<Ï ‰¡«ªªª¦)FkÑzbŒ>s‰Ù9—EÑëgy™'Óét:aÀ™=‘ ¨¤˜B'›ë«Î‹¨)¥SbJª* ãªnBGÆ*e!@GÖi‚B¯—+xŽ^57† mÛ”Ržç„&F ¡K)²5Þ;×ïõ—·nÙ³{×òö­eé %iënËâÂx4Y]]][[›LÆ“ÉØ¾n›¶­Ä*2ŸybŒÌœ’Š""!⬋ÎìÄIA­µ†Lõ1U…‰Ê²Ì³2€Xï­wd @–eÞ"z²¹µÞ’ëÈçÎ{g"jJ™iBÅšBŠuËMW­ªq;©¥ Ø)µDj0£BäQ$%RÐùÇ(æ¼çž{.ºè¢Ç’º<Å)þW²¹¹ù?ñçž{îâââ¡C‡®½öÚG'´{ŠSœâ§xìDf@R€ÐÅÌçYÞ[^Þúpà°ª¬­n|óú›®Ú}úÖ3ÎÚÙë—;NÛ‘ù¬,©ßZk3cú½ÌY””676ï»{øÒ.m]²YÞï BÄ-GVÊ~OAcŠý^9??\\Zr>Oª#GVGã U‘£…‚ ³e¯7S"B©$Æ&VMµ9.Ì[2† ‹8gŠÁ\lC×¶)EQͲ½P5’•ÉzD£UU‹ªÏ¼ª¶ÚôòU9¦6rÄдu®W”y‚8mÇU7()FM,’¼±JRµSXÕ;¿sÇ–ÅÅ"Ï—víÞ5§ÓqUެmnìØsچ룑 ZŸ{_X—KšX!¥» –%¤–œ!%MÈj,‰Q›$óVbÔÁ4&:“24%ìŠ\ÀæÆc/ó {æ’¬í=orŒØ%Ël;B††(!JJŠ …ѣư¨“uå ÷E^ Š­ÛæwíZÞµsi80F¡k¤i1F“g½V‘”Y¸ëX#329c¬E$T’¤5D‰UQ% Ä„AM ¬dlžÖ£D DC„D €y^æY!]W¡µS8tøPÛ5̲¾¾Š>ˆÃaè‘Ëó’Èôòw±©jN‘ÈAÝ4U]±ˆ³ÆY3?7g­!¢Ót2îª:¦bSl»¦î*²¸¹¹Y7õ™†“ÈÆÆ†0³°ƒ*аĦbî 1¤@bH!‹%“eFNmLIˆY0vAEÙÌz‡UR D’bšœ+‹¼°Æ†.rÒ<ó…óªC$4†L a2Ú míYYæ¼wÂZf.ô·n™ŸöË"?rôèx4Š][Wã®­$E%PŽ]ÛN«¶ëf!±ª¢ó™ÈP¶d¬µ*ÊÞ{ïA´®jDÌË¢ÈËV“ñ-**«4Ö1³ºa0FkÄñVìLŒËæ ‰cbNmJÓ6L«4më•ñd}”êΊµà@ˆ”!ç{&²FáÄ@då"RÃf/‹v¦Œ$¢À¬b¼ù1Š9××ׯ¾úêS³Sœâ¡ÜqÇwÜqÇ);œâ§8ÅÉt* >Ëm¯XX\ؾcûî]§oMUwQí¸ªG£qsçdc´b»¸´´°¸ÅÚŒƒbÏžíž\æ,ÇÐTÓz:©&õþ}¿}KaK:óÌ'n[Þ™—ƒ$š˜›¶›VUÛ¶‹ós ó;¶/“± ²¶ª Ô$ë-2²R,ŠÂy'*]èê¶NmÇ]Hm€$d!2wÒ©•YS"ã\Vöúuݤ˜"Yc1,›`¬Í² ‰b‰¬cŒ5€±ëV×WFÕˆ2T0ª¤JªÈI¢5ÖzS¬Ç“ét»ÖYk­ý??õS‹K Û·/7m5™nr:NÉë}žŒÉˆœ¤$‰…É!2+Zµ–mê ¤ZaU%ÄY •5n*!DeÌ ëòˆlLæÑçÆzBÎØHf@œØÔOóT’í™Ôz-ÅNÚV[∠V@4ÞÖúÄ"Jy^,, |‘Ï/ ·m_ܾ<œXÒ–»Ú†ŽkdŒŒ€@j‰Ô€A+) ‡’53Ý"0Ê ‘8BÜ wÔE¥ ”áòB¨É(€©DCd1Æ  a¯×w™oÛ¶m:笵¥ªN§UL1¥Ô¶­wYæòóÞ:T™N6:ð;oü„´s~nèEoA9wÎ[ÙܰèСõÍõº“ŠAõDù,øN1¤Yh—‚ˆÎ9ãœ"t]×vª¢Cç\QdÈ¤ÄÆrdœA:ËW"qHЍDh-x.#ïÈ{c&RôÆÏ4­4rj#OÛ0®ã¤IU›¦ÁŽ­µŽAQ•f“uçÐd V *¶ %C ¢@¨BªL2sÕ¤(FÍ©ÚÚSœâ§8Å)NqŠºŒµY‘Í ‡{öœ¶{Ϯۗ)±¤æèÑ#“ºIâ#·Õ´)™áp©,æwíÙÑë—Ôs ósÞzžN'ÕtÒ5íˆ*0pï}{Ŧ6ÄĆÙ>ººº¶±±1ªªFDTÅ9[™1&Ϭ·àŒ8£–ÔZÊË¢,ËŒhÒï{g…¹ëÚº­jIS=™6U…Ö€jˆ!†¨I¬±YQ³I¸®ê®n% ’!20k A¨ ÌJ„±‹v¹åR´iÛ(ºwß}“z±ik†„F“F%™%|ÐPLqT$H »ëc <í)O]^^Dä˜Z“Ùû˜6:ç-Ycœ†ÀY e™cœ±d¤$‡YáÊ^%wÔŽ¥–Ô%òêŒ5±“Z˜$8MÓX·`ЗBª.ZƒÎ#&V[Ø­»·5M¯žm5ŠÍšŠƒ¥˜HDT"§”¸W”ιYgÔ~¿¿´e‹s´}ÇÖŹAf¤­Ö¹ÛÐdÊF‰cAÄYE´ÎëbŠ!u¢  œbL11(PbEHÁ°)¨3NˆµÈ²Ü9˜)ß²(³°¨ "!CƪbJbªªZUE„ÀgÎZ—Rí8iŒ)FnÛØÔÇ$¡³ˆ½^Ùëõ°jêÉds2™Æ”œ³‰£Št]×…º.ň ÔŽ4ÆÂ{8Î*`€cJÂhŒ07]‡Îç2kHDRlÛn:­«Zó¢,}Vä9$Q–Ø0ÞzïÁQ`B$+¤à¬Ï²¬È¬p›B[UfŽ‘³¼´Ö9ëE v\ImŒQƒ&÷™sÆY³¾¶úõ¯ÿÛ¸Åy×Î- ‹„&tŒëy/φ½>0p]Mzy^e™7f¡ß3ÖÆ®­¦¦CU$""Umš†@E@Á›çyæ<4M‹‚ Р"u&+5ŽlfóÜå¥ÏJ›eÆDdaÖ$‚ uÛŒ'ݸê&Mšv±j¸ !ÇL¬¢‹Æ  °&Fß´Öd=Ÿõ]–Y´'t³|;…$2“ÑM µëºS1çÿT¬µ»wïβlÿþýÀܳg37m¤Çï{Oñ£C¯×Û½{÷÷*×yŠSœâ§ø¡ƒDh)¦®‹­Hh»Ñdj3DëbÙGã´^kšEÈŽžþË?_ðàÆÿ÷ÌŸ=ûœ3æâ–­è-ÎÏç;v,tM…*GÜú´©«®¹ïþŒV5ŸŒÃÑÃ+‡Ž¬Nªš¬)³ád:7«é\Ù˭Ѳôý.s­Ó(ÁJ6?˜_^XXjÚaYzïÉ"lÔ“ÍÍÑ´k£êÖ;²²P€ÙÚ<™e6¬õ>+Š^S´©‰©kƒõ>·ŽSÚX]mnzïD¸õYj:H¢œV×VÊá »£[X˜w™¯›éÆdcu}Å =Pˆ]”›Ø5Ó*/ŠõÑæ7oºquu­×+N[^γÖ¡Ë:ºí;÷L«}î Odf­1XR’SL`!)ˆÏ²²—÷†}‹¥Åœ8§äZ&¤à#cÁª ¢‘cà ΚÜZÕ`X’Þ-‹$&2Ù²oý0ÄA[÷ºfë WS‰qD*ØŽIú½Â{')Á`Ø›Ÿpê–·öI;ÙlGÚL{H¹u ‚%tMŠhU• ‘1Þ:BTMª ‘c91fŽ2"‡`ŒrÏ÷¡4ê­2–()³ªôÆÌÊTSŒ]ÛµmÛýÿì½y˜nUu'¼Ö^{8ç¼ï[UoÕ/ÃU®‚‚`"SôI•ÛúœB|ãD4qèt£!Ú±ÑhÚ mL°ÑÆæJ«*± xAB.jE1  ¢L¸Ü¡n ïp†=¬õýñ&õU‹’‚t¾/üžúã¼çìi­½ö©½ÎZ{­Æ[‹F“ÖZ„™ÑhÓ*Z)¤¨(¢‰‰‰©©É={¦{½ iˆQ˜%„ПŸue”T•Ù‡>FCˆ´5YnšfØ4Í(°°(DÒ³ï3‡Q¡³Vk“DRJŽt+Ëç{ó)D‡™ÉTæ %D 1@S7¾1sccvÇ“81 ZácŒ" Â,!††‚µ %‰¤º®«ª®ê¦=Öõ> )2ÚäYîœóuƒ€"bi·ráð³;ïØµ{×ÝwÿâˆÃŸwÔ‘/8pÿý²v&Œ’$ø()NNŒq ±iú½¹º*Cô“ããÖ¹âpX×>úH“¢”RÕÔýA¯n樔afŸ|ŒÉjS–UÔ±iÑZ)Bí´v./²¢Ó6­¬èbU‚D$¨’@ù‰§½uŠÃ†a8×ÌÎù~%u¤À’xÏŠÕ(]j€¤”ÀÈŠ¨+tWÙ1ë:DŽ…RÄÀ 4i£ŒCŒ yæÀ£qnÑyΣ>úì³Ïþà?¸œ¤ÛO:žýìgçyþËÂý=GàÌ3Ïüë¿þëv» ¯zÕ«þæoþfñÓ‹/¾xnn|å“Îç¥û}ÒqÒI'y晇vØøøøŽ;¶nÝzÉ%—ˆÈè©Rê×ý×9昼àyžŸuÖY‹cBžtÒIïxÇ;·A¸YR IDATvÙe—]rÉ%OõÔ,=f ¢·¾õ­¯yÍkÖ­[·sçÎ/}éK‹S¿®Y³æÃþðqÇ×ï÷·nÝúWõW‹ë.'Ÿ|òå—_þ¬g=ë¿øÅ¿Ûeòœç<çÜsÏÝ»wïYgõ+U|³°‰]I¿ï}ï{:ê(‘Ý»wßtÓMÿûÿï'ësÓ"“ïÿû8∿üË¿¼é¦›Fw.¼ðÂn·ûˆb]tÑW\±œ•ò¸ø­ßú­³Î:ëC 7ÞxãÇ>ö±e&ãY ½§œrÊ»ßýîg<ã»wïÞºuë…^¸PwizW6žÆ¿/“43 ‡%0×uÕ4e]9ÐŒâNAã…qV 9Ä4T?»ëe(rzîs6ÒynÛyqЦ¦Æ»Ö®»çîïÝ»§?3ÝŸ{ð-åƒùjßôìôžé~¯äyÞÒškïwîÙEZ•ƒá`8Ì\±~íºU«×“Ëm^¬Y³nÿµëë²Ü½óá¼Ýb„¡¯kà!"ª$…Q)£Í°)÷Íͣ¼Õò•¥òkô°n7!E—9ëSðU@,s¹u¤”ÑÚfÁÙá ñM;%H!”ê,+¥´Ë‘–~¯7?3oi<ÏÎõ a†ýùÁA›~üŒ-¯X³fUÑié:¤Æó=>PÖQƒ’˜fggZíÂæJ0§ÀæE«£æ(¤ £VYËÆŽ•¡ŽMÃ!yŽ)D6Z9m•µ‰hè½/KUd­Vk‰ƒ&Á¼uãÆv,e„ÊiâÄ–x|"Ó]‹<ÆMë!ø€,ˆ@!„"Ï´V!x)ЬÈt¿ßøÁ¾È‚w*‘Qº‰Þ{pD™É#)ƒŒ)q“&æØ„&A2F[§ Y P•~P–M&¨Œ$Q,˜abF…Fk—eE«ƒ¬«áÀ àH''­- jR1Åàëš$É¡eà™}3ÁûrXZë ™¼h!¨óÃàŠäÖÊa]UÜ4‰9ĈšHëQþÐÐxk­Vd´‘0§bRD6/òV U‚”8…ï˺A@LL È ±h-ZFÏðOç sE]–¾ >¤( ƒäLÞ*\žyNXVUí@$‰VÊXe¬îÍT(LD @¥”RbA…Ì\–¥ˆhR­<7¤bhƒPd¤tßÏïzø3ïÆŽ;~ÕÔª,sš9íL»ÓÉÛ¶"Ø7»wzßßTUn¬³Ö£Q ‹0X4„&yö«¹Ù~jDrØ€¤”Ä@5¬™b^ø@RŒ‰¬ETÆè<Ë\æšÔ´ZNg µÀ Ð(…J@’èç÷Ì–óåüôì`ß\6š1SVƒ’ÀB ªŠÂ‚ÖY¥3@­)Ë:k¢š`(XY@ƒ¨Ik% D!è”°lX[c i„¨Ø'Q!ÿWçܸqãé§Ÿ~Áü_Ñ9?ðrÈ!£mÓÓXDôÙÏ~ö’K.9ûì³GÎ(píµ×þ²0+áóãöû¤ã•¯|åæÍ›¯¿þú™™™#묳^ô¢5M³B>)2ù’—¼äø€ÖúK_ú҂ΙRZœ¾ò™Ï|æÑGý™Ï|f9+åqñîw¿û“ŸüäÕW_ý?þÇÿ{Ýë^wË-·|þóŸJé=ù䓯¼òÊk®¹æSŸúÔá‡~Á¬Y³æCúÐrè]Z6žÆ¿78׎)p ¾áé]Ó«Šö˜ÉШj8h·Üd»ðcuéCB À‹$ ³½¹Ù¹¹¦uÀ3!¶³–[e!¥™é݃ÚÌV|=;,ïgƒ$aÕ¯QÈem$S§Úìë÷†ƒAS5ÖdãíñÙÙºªö¬Y¿6ËZuUV¡ÎÚ­¢;^ÌwÛ«WM =:Å0ôM¯,\î çëP•eU–DÚ™Ìᘪ² UIJt«ÅŒÑ:´@E‘;焹_•Ñ{èd-§l¬C®MÙkjœizX|ƒ1NA û ¥’gÃìW|kýêÕ'žx|wrj“`d©ªú¡‡šôú½9“¹¢Ó.ZãH\Å ’6m ƹXa¶Š¬á$‘‹Z§ S“*-©Õ*0J Á7¬!y uS ‚´Ê˜Ü¢Ñ11¦IŒªŽ‚ÞÇÄÌD!jBƒH[­”07M0ôb˜€õ>S¶•Qhšªĺ&`À103ùYƒÁ€Ì‚€¤‰4yö!6 ’ú'ÿcÁ8…˜¸VŠ (ŒPjbT޲<Ï‹¢ñž)Yב±ôJ¸,ã°ôÌŠÈ€Ô¾®Q(N’GaM‘›ºöU¥”2Ö”Píãç²<Ï%"¨Q~­WOu‘yP´çöìŸ)…à1+r[XMÚå(Ú*@áA9뜱Zë¸×h£­Í|ôÞ×IØZƒˆ UË (3ŽÄÅ:yŸ˜Б-´å¦­öxI†Þ[´D*Ó˜N +ŽY„:h­Š,Ϭ›ïÍ…Èœ’RŠHG‘þpHdŒ5"ÀŒ6ID“ §Ð*²îÄj›zÏ®=?Ø{þ‡÷Ö½êØcŽÛtàz,ÿ§P´JµW­žëXmH‘™žkMhbJ¬ÉI¾ fÜÄÄ©”X‰¦\‘1ÚåY޾©€bcdfИ„3Wh«¬ÍI(V±Q•±Úf:Ëu¢À¬ÓEá{Ÿ*Íp¦?»cg=_Jóš1‘í ÊÉ2b“À› )óº­(W*×¶­²ÕÆ¢@MDšŒL8)m´m) Jp”(â‰ÈD®RôˆúißÚÿïaÆ cccßúÖ·æçç³ÀS¤¥Õ‘¹I¼gf>¦†S*²V»3©”Û»{Nx¾ßìÞµËff×®‡Ç'ºUÝÌ úLd‹Yg].Á«„ÒD bQGL9Uuã›ÐjµX„%¥è™}U»Ì9FD¥Ðe6Ë\UÖƒá øà4uÚmglS5US—ƒ*y–¨$*Ià½ojÖ €¢C±Ô¨$¦ÜùýÜôŒgnŸèNL°ÿþýÁpÇxïwîÙÕ@èN!Ä&4>5Îe¢mPF2“Êi[y.Õ\U&G›+É(ú(ŠP '¥ !`[Å‚Ø:N ÌŒ1qÔ!øªÊ¬‹)†Y8 ŠR Qi«¬á¥îkJ @£b¥‘H3)  § œb¬bÐHJˆ€(‰cäˆ,€45IH±1mçf÷ìÞ3³{z0;Ø»súØã}ΡϙZÕÕF‰€6fl¬³fíš7dYnM6ìÏÔ¥ô«²¬QéÜæF[ƒ&†šë„^¹"#팶™kY£9o@fl¨ë¦© FB•Ù¬•w´1ÀÌÎkUÒ(DYaœ#?l|Y×se¹¯?Ø3æi¾¤„ÔˆŠ`­¡&i@%ä¢Òa”^V‰ZFi;fÜ„q“M0 4‚™…ApŒ¤ˆ,Æ”"'P2Š™‹(J *¥µSË nÞ¼ù«_ýêîÝ»÷íÛ÷o|ãÏxÆb›Òç>÷¹;î¸cnnnÇŽŸûÜçñþè£Þ¶mÛ®]»vïÞý½ï}ï·û·]}õÕÛ·oÿÍßü̓>xû?cä½¹,Ñ2œxâ‰ÿðÿ°k×®mÛ¶½ô¥/ݶmÛá‡>zôÚ×¾öÊ+¯\(yØa‡]sÍ5£ä„Ë¡èÏxÆöíÛ_øÂ¾ÿýï¿ï¾ûöìÙó•¯|e´–æÕãŽy ¼þõ¯ß¾}ûhù¡}hÄ«N8a¡À>®?)|~Ü~?þøíÛ·ÏÎÎ>ôÐCŸûÜç&&&–Ï«%ðËäwÜAD cöÞÿûßÿ·v^qé1Ÿyæ™wÞyç/ÛF¿â¯Ø±cÇh³ _þò—‹¢xÉK^²|³ÞOúÓ¹¹¹+¯¼rãÆË_¿ðêW¿ú¶Ûn›½âŠ+^õªWmÛ¶mýúõOŠ´¯p-t:W¾ò•/zÑ‹~Õ‰Øo¿ý~í×~íòË/ÿû¿ÿû-[¶,¿âJfa%»ÂÙ_ŒŸþô§#¬\žW>ªÿò_þËÏþóo~ó›K”YµjÕ+_ùÊ/~ñ‹ ž¨K¯”¥ñÆ7¾‘ˆ>øÁ.Ü !ìܹó©¦÷ðÿîºëdàoÿöo‹¢8ñÄ—Cï¿Í·ÙÓø¿ÖDι¢Uc¢$AiµÖmÜpà37mØoÃ~ûoܰqíš5SkVOmܰvÿýÖ¯]=•;7 î¹ï¾Ûn¿ý'·Ý~ÛwÞq×Ï~~ÏÝ;ÞÙëÏý’Õyžµ5é¦.Sò­–ïv²Å("¨•Î\Öj·²"#£”F“[8A¨C ‘(C¦pyN6í©‰ªòº :x¬Köbo.õç°P]QSaUò ßÌΖ33Ã}ÓÃééjn& X׃ŽAÇ@Ác]‡þ œmæ{R¦ŒCÒ NBä8±1†Èh²DZ)fNœ˜™……ÓèPY$¤Øø¦jª"#€B‰)…½ÁÇ9øXW>„|! 1Æ:§µVJ¡fN)!bQäív;ϲJÇ‚JkÃÌå°œ†ÎÚ<ð¹‡>÷ˆ#Ž8ä9‡´yóæÍ›8ð€÷[·vÝÄD·( ­ ‚9çZEQ-ëœR*¥Ô4MU5Þ{ ­IkT *…Æhk-)BARdµkí±ÎøØØøØØøÄx·Ûìv'[EÑnµ;N»Ý)ZíV§“…ÒZ„Xk"RZQ–9ç,)E*"ÒDÜt@µBA‚)¦ÑÑÔ¦ªÊá §D2kZyfHõæænýÇ[¯ý»¿»æÛwÓM7ß}Ïý3³sÌ2ŠKÛëlÜoãû8¹jU·;il¦”!N¢É´‹v»hµóV'oåm§Ó†Q€HgY^ä…Ë2ë2c6ŽŒy,¢s®(ò,Ïœ5™ÓF«,³ív^dbÝTý²·o~ßÃÓÓ;÷„²’&€O"p„Ð*Ê@e¢249Ú6ê6ÙŽÍ»Y6iíBÁ‰PŒ#Q…š}•$*%Z I_7Õ ¬‡Ul"$€„Q‰qº­)_®óÀ¼ñÆï»ï¾w½ë]1ÆÿôŸþÓ·¿ýíç>÷¹#Ë#Ž8bóæÍçŸþ=÷ܳaÆ÷¿ÿýÏþó_øÂŽêNLLlÛ¶í‡?üá›ßüf9ꨣ;ì°…ð]tuÖYëׯ_ð}Z¦KØÒ-oÚ´iÛ¶m7ÝtÓ»ßýîÃ?ü+_ùÊÄÄÄG?úÑ…§/~ñ‹7õ’—¼d|||ôsiŠ Õj½èE/úÈG>Òív?ûÙÏzïO?ýtcLJii^-=æ¥1r[»ví¯ÿú¯_uÕUÿøÿ÷ÝwßBÏ9çœÃ;ìuWÂç¥û=ôÐC¯¹æšEk×®ýð‡?üœç<çE/zÑÂvj ^-ÿðAôð?úÑ–¹wᓟüäªU«xà‹/¾øûßÿþ¿ò¾áÑc>òÈ#¿÷½ïp oyË[Z­Ö?üÃ?üõ_ÿuUU œ¼í¶Ûª®ŸûÜç~ýë_ܾN8á„/ùË_ûÚ×Î9眓N:éãÿøò×ïqÇ÷•¯|å²Ë.;çœsŽ=öØ‹.ºh||¼Õj­\ÚW¾<ðÀË.»ìG?úѯê¾eË–ãµ×^»~ýúÏ|æ3ÝnwvvV¯^}ÄG<º|Œqûöí+œ…•Hì“Õ/½ño€‘âô¸ô>¥£:üðÃÿèþèùÏþÒ ðÞð­õÅ_¼pg镲4Ž?þø{ï½÷1ƒ¨=¥³oŒY¬4ŽÞ®‡rÈ Õ%è}Oã_")EšÈ8#‚DíÌøTwrÕ¤#=¾zJH›vÑ–uJ䊄€‚UÓpÕTsU%’òž›™Ÿiåæ{3ûz³ï…—k—™¢0Y‘;O |*ð$¢S2!¨A‹V>¹j‚}ú³3Ó<ô`bYµn i[7MÝxÔš¬s¤ h•˜‡U)¥víBç.ã+Ÿlf3çÊj0̲˜‚Ä€ÚXc¬Ö!fŽ1úƇ™™}UÝ´Š–µÆæv8T¾òÁéøR]×  ´RHpJì=‹„‚pˆ1 ˆRJkm­uYÆÁYjeE–eZkCf<ë(!ùr8öõ°ŒÂäŒÍ9#$$E¨”Be›¨P9£ YÇÌ:M6FN)%fBÐDDH •2ÎÄ:†à94œ¢(‘[1ðÉ93RÏcô>¸#Ý óýÞC?ïÐÃ9ôðç È|¯'Ý©Ucc“I ÛízÁÙ²ª"C…Ônµ'ǻ܊U+ÏJß$‚"H‰,*0€ ³d”Ê]MŒ“¥ÍmÞrÆj¥DkmŒÒ }í›A5œëÏíÝ=Ýß;ÛҌε6ˆD7¬š$‘1²$Cʹí(ݱv<³Fµ1ÙØpjÄTŠ8BV†rc¬p’”Fn 4°J¬Œ‹Q–«sž{î¹Þû¿øÅ½^®»îºûî»ï oxÃH{ù?ÿçÿ,þŒ½oß¾Ë.»ì°Ã}n?âˆ#&''Ï9çœþð‡£¯¿‹[þò—¿ §œrŠsîWÍŸ¹tËï~÷»cŒ/ù˃Á—¿üåU«V½éMoZfËKS´øsõQG5Ú@úÓŸ^¯–óÒ¸í¶Ûn»í¶Í›7üãß¾}û£ëŽø˜d®„ÏK÷ûž÷¼'Æø²—½läBÖëõ.¾øâO<ñºë®{\^-7ß|óþûï¿jÕªK/½ôÿð—ÏãÞ{ïO)½æ5¯yÛÛÞö–·¼åWŠA²ü²1¯]»öÙÏ~öå—_~饗2óG>ò‘SO=õ7ó7GO§¦¦~ðƒŒoß¾ýª«®zßûÞ7º¹œÿóþÏ÷ÜsÏk_ûZfþæ7¿yÐAvÚiË\¿ï}ï{ï½÷Þ3Î8ƒ™ÿæoþæ ƒ:ýôÓÓ8ó«JûS·ÿá?ü‡n¸¡×ëmÛ¶Mkýò—¿|$öÇüe—]öèòÃápd\É,¬DbWØïºuëFñ¢Ö¬Y3 Î8ãŒüàË¡÷©•Rê /<ï¼ó~ñ‹_,­s¾éMoú»¿û»Å1~–^)KcãÆ<ðÀ/SGŸºÙ¿ë®»^ð‚,þ Žô˜ô>§±™3¨1Åu¨+Ÿ)kŠîxkj"TõÚ6ŒMu‹é½wzßÌlÙT,Ðr®;ÙÂÁp1Åà«ÔÄAˆ’ºãcñn» »föT1µÚ®hµW¯™Z»z2ϳþ°ÏÁÏræÚ€Dê2ö{e6•MNu[ÎÎì™n†eSÖ{gg¦Þ˜H+Òµ°2Úe™vR¬Rh· Ua\;G­¹ œbBfEŠH¥€„V€%†X–Õp8 )¶;mãô ìÞÝëõ•ÒY–E®µ‘ÞGM„ÖÕ¤cŒ3DRˆÞ{…©öÍìüüM?üaˆé˜ãŽ›Z½ê­ß¸áÀÙ!ˆÈätD‘A¿RЙљqÎ!‹Ä”|ðM#J1³±Ö䮤²áÄ„UåU`V€6³ì“0 Œ²† Ò¨™  6ND”R¤H@{D` «0CãÄPRœˆÐh­4±œ’VJ3€ ’( ¤}壟Ëó6" '!¥4)CZY$2>D_PJ‘F2ÆjÊ0˜”ˆc3J¶Dãí®vÆ:—Ù<€€¾b_ûÁ`0,‡ŠP[JJé@À,D¤1Öj²Z˜”"ES2F›Ìe)IâÚ7<ø ´ò\GÂöÄxTRúºô5J"vy–å™Ë2@Pš´ÑÌCÔumBMÖY` DÑ‚X×u9?Т‹VÑjµœq)…V«µqÿõ“ã!ú¹™™þìüî]»ªºV†l‘ÙÜ¡¥ÊWMhA!" 7uÛY²"sÔd Ü07)5Á³ hÂà-­I[“eÙ0Te«ZƒäThvžaH„â}ÕIJmmLáîï—ƒ=³{§çööª~wª‹È6skÖ¯ëLäyÑëõÒ½;w‡&!è±±îdw2wY#U§È2»*NýºCÚñµgÔÚi V£Õ¹5UY2J“šBeÖ9²Ê§š‚@£€1B*{ƒáì`03(熡Œ1o”CÔ¤ ‰Q5ëH ¨$†Lž¹nÖšBÝ1Ô6ÔFv±z´²Š 0A@ ̉›Ä‰‚F«µ%,J±’(‚À A'ë–}žóÔSOýÎw¾³aÆ 6ŒîÜÿýÏþóÿÙDÆÆÆ¶lÙràv:‘êÚµkGÚŽ;˜ùOÿôO?ö±Ý|óÍ¿jX DtÎ-¸®-]³tËÇsÌw¾ó…|W\qÅòuÎ¥)ZlW|t(¥yµBnüıÇ{Ýu×N¸üòËn>.¯–ƒóÎ;ojjêØc=í´Ó®¿þúóÎ;o9µ.½ôÒ/~ñ‹£ëÉÉÉíÛ·úÓŸþú׿¾ÌshKHÝJÆlŒ9ñÄO<ñÄÑ9®k®¹fëÖ­§œrʶmÛF*fž˜˜8ì°Ã¦§§EDD–ã„ G}ôe—]¶à×wå•W.Ö9—–ÉGÔ½úê«Sç|Ò¾òµpûí·w»ÝÅÁW–ƒN§sÒI'6ß{ï½?ÿùÏ·lÙ2Ò9¯¸âŠÇT4ÕÌÂJ$v…ýöûýóÎ;׬Yóº×½îøÀõ×_¿sçÎÇ¥wii_ɨÞñŽw¬[·î/þâ/×,9Š0ü›á+eih­™ÅS:ûçŸþ¿øÅO|â_ûÚ×;ì°·¿ýíUU)¥–CïÓx‹Ñne÷M!ÔM¨÷Íã®Ù½{çgÛ“cE§Ú·ó\¹Ìdyž{§§çæzÌ@Èd­N[ŒJGy;±µ«× &âÜûu´ÎZk¬¥ñ‰¢Ûívê– «zv¾òAb@£R.E)ËÒiie”ånbb"ø( ß($‚>Ī®,9kÓ&¥IY­¡&„~3L>Œ·;ÚÙ¬ÈÙ×±‚X7Cꃤ‘c YC™5E‘E梕)Cúœë÷¤ÝÊ;í¶³Eæ2UJ_ûÄlÈ8ãRJÌcd¥lž)”aU'–ûv<°oWêþž IDATv¾lü)§žºnÃúÙAorjªN¡WöÐ(Ÿb“|h<’R!RSUm£X$Ä*Åà=º"w­¦v Ø &F k@Ñ×MRˆL–i­0¤Ä))P¤r !ƺNU…œŒ±™6ZI#‰E$E‚ pCIšºáÈFVì}Pª‘Q-Cš5IbN râCÅJh¥@I Mæ”å”¶†”2¤ ¢øä!)•0ÔMS}]û¦QZ`Ý„0ŠL¤µ&MRDR¤I)€jX†¤…PÕUÓø5S«;Y.1ÕUŃjØ«†Õ`~P–1EQD½/cŠ©ñMŠI)–"(•gYJ\ÕUä e‘R¡ŒU]-ä´ÓÊXk'ºëÖ¯[µf*{vî*ƒ:x“ÛÖx;kµe¿öµ±Æ9ClªF+bËLÉW~Ø”ƒ!€"¥A˜)"M–DIB6¤­³ÚPŠ¡7?ç‡Ã\›‚(5 ÆØÊÝÔäXw¬=;3[VÃV»c­«êá]?ÿÙî}»îºç®g¼y¢;¾zíš 6(m:݉qÝ-Zí¸¬½1¶]t W ¤h5u “gŒ¼¯7癕ÑQd +Œ!ú$ˆuÚY“aa¶…E‹IÙû2#5ÔC›ºì•Ã}ƒr¦^3Ù¬CÊ[ÐÌPŘ"„¨c²`r¢ÜæÛ·ùÙŽÔJ€Z”D¥™PH KdE@˜•ˆ"Æ”˜K”˜E)e Y…†Y!,Oç$¢U«VmÙ²åå/ù#ü”F/|á ¯ºêªÙÙÙ‘aaôÁس`nú½ßû½~ðƒ×_}aûöíüÇ|çw.óåû¾ð†n]ß}÷Ý›7o^lÈZ¢å 6,ö’Ú³gÏòßøKS´€Å~­ËäÕ ¹ño“““7ÞxãÂϹ¹¹£-æÕ21ò@ûÔ§>õgög£X”·ß~ûãÖZ¹wffæcûØÅ_|ì±Ç~ë[ßZ¡Ô­dÌÃápzzz!pÈ7¾ñ­[·ŽÎ4ŽÔ†v»}ÿý÷xà³³³­V ”ù¥ Jk×®]èr±´/-“£ºÓÓÓ ÷_¯DÚŸ”µÀÌO „Ò)§œb­EÄQÆ ûï¿ÿ¥/}©µÖ{¯”ʲìÑUTî'< +”Øö;Ï?ÿüÑõ'?ùÉ_üâúÐ‡ÞøÆ7>.½KKûÕ(ãÈ;ßùNk­µvô mµZccc#£÷Þüæ7ÏÏÏ?Âü¸ôJY333©Xޤý©›ý‹/¾ø€xç;ßùž÷¼çÞ{ïýýßÿýË/¿üÑÒû˜ô>§ñ/^­ Rô¡©E¡ ôÊêg÷ÜÃçªáA›ž¡;y«39ÑjwV­Z5ùðø=÷Þ?=7;;3 VëvK9•·º†È*=Ñêt;ãM¯ !…•"cŒRXVùù9ë (r™kµ[­V«ª“H#,Á§˜Ø£)…ˆ¨È —åcccE«Ýj·UU7eY¥”Æ&Æs¿Î×CCU–ÐÓ”úA)Q Œ.ÚEŠM3ÔÁs4Z©ÌeÖY£MŒ‘9ZgÖYž!ó²BäÑ YPJIb5J ‚J"A4DV D“Rˆ °OI!# §¤I)R(}bf£ )Bò.Ï"sô^‹'‘(1$FP¤±% Dæäc„E"ˆ×™ÖÖšÜj£Àû>¡NA†½²?WúªvÆ@ Œb‘aY£°3&sŽŒŽÌ‰Ai2ÆhcUöu€)DTŠRLY–í·ÿþëW¯!„¦n&wîÌ;­*ø{¸çà bg|,ÏsùgsÕÔœØZk´vZÇÄò”ªÔ–È’Íl–9kLC!4¾êU>†ªª¬v­VÞjµ:ÎäDW)t¤û{f$¥þ\o¦7GVwëîØdì{‰Yµ ! ,¨•"@ŽÉ×M9,‡ý¡ÖÖX…QRBБPeœ±™ÕVö>6uS'ßäJi%¬DHS·ÛY·nu0œíQ|ðýj87˜ƒÄÉUÝA]!é¼=>¹:²@(•-k²Ìe BD‘VæºÝ‰Nw,G sƒ~à˜DE)VuÑRa­ "¡ÉÍ ’„Ô “µ*sF$6æ?3ߟé׳Õpß ž«)€#M¨(8Å”Ø$ÑB…-¦´nébܶÆëæ1¤0$Å ÈŠ£ €$V(šÈ’EK !’Nuˆ^QH€“¡Î´"­lDŒ1-KçL)•eyþùçŸ}öÙYàŸøÄ­·ÞzòÉ'¾.ŸtÒI¯~õ«غuëÖ­[ŸùÌgžzê©þç~饗>ïyÏ[æË÷öÛo?ùä“G×>ϳDËóóóNg¡äØØØ#6ˆ¸ð3Ïó_‰¢möy\^­ÿQ–åÂ9Ø'1NÖ²òÜ*ßüæ7Ï=÷ÜãŽ;n9;øG`¤G-?6ÕÒR÷„Ç|ÿý÷/ÞòVUc\àÞ=÷Ü3 ±3:x衇޳Çí…™gggKøâ0NKË$3OOO/Þ£?"Ô–öÿ‹kaË–-ÌüÞ÷¾wÁŽWÅI'tõÕWŸzê©K{W>áYX¡Ä>‰ýÎÎÎÞzë­Ç{ìÈÔü¸¾µKHûÕÐn·¿ð…/,vhÿÒ—¾tÿý÷oÚ´iñkùŒ3θøâ‹ëº^\}镲4n½õÖßþíßβìm.‡+™9÷ÜsÏ=÷Ü<Ï«ª:øàƒswÜqÇâ2¿ŒÞ§ñ4þ…,±ÄY˜H+r‚²gf¶¾ó®é~f0ÜoÆõkh2ïäEV¸Ì)Š!KÏLÏÕå ×`ž®hµ':ãE'#[Η>ÄÆû:›Xúýú¡ä˪îtÆ@én·[{°Y«ß+ççæcðeYŠŒíA@´ËÚãã¨u«èt»ÝV«J¥”pÃ~ûÃÁ»v>4½{Ofꦪ‰DçΜ ±œQ¤ ‚BibôÁé´ÚÚhQ0ôëà‘ˬ"UÕuU´Óy‘“V,,ÌÁ71Iî 7á WXcËAU75 *MÆ­uS—©âÊŽqn~n×Þ½û­+M‘µ;ÕkÖT¡é×ÃéÙ™fØo’×)*""_Õ¸ê»a1L1•ÕÐ{OŠ @Q&–$¨”@ ˆ@Lƒ€)ƒÀBŠ1€€B¥ARŠ€Êj† ¢ˆ)!22Hb™‰’0³RHDÚh¥”ÆS@$¥•&LJ!ƒ"mµ„„ DPDpä¾$ˆ‚¨ˆ”uPS"«mfÈ¥SâcâÈARó½P5 #‹0 ¡Sj‚DF@À‘8 *¢Æ×1%­40€@Óøé}Ó÷Ýwßøø¸5zõÔd1Öêúî|ÙowDaj±Á)BAAÀ&øªiR,Œ*7Æ"@ !%F†¬6fIÈÝjµTR‘EB1Æ“°Xk;¶3zïƒwÇ'öä{fççR’Äk¤’£ÓÖh£X%cØÇ’Ñ€¨X8¦”@ÈYEJ“y–Y ‡eU '­È‘RSŠ^)ã¬nµó¢Èfý&4¢I”"MJÓ®é=Óšr9SŒuÈåuðu~zÇíó½~ÑjwÇ'×®]W­8x‰F«ñN1591lÊÜšÂÈI„Á8‡ÚÔ1ŠVÆ:e” “%e5€NÚè,×FAð)VÍp¶ßÛ3û1ô)#0愈ÁK…ä·íÕB-å:¨ÇZV‹ (‘ ¢D@@Å A¡Œ–³KͰr¨B¬G¨Û GãȘåúÖÞpà /~ñ‹ñ1Ï&mÞ¼ù¢‹.Zpg:餓~٦곟ýl§Óùð‡?LD‹ÝŸúýþâ˜%‹Ñëõ7ÖÅc¶|×]wyä‘ eŸ´)!ÖÚ‰‰‰Ñwè…x¶¿EO€WËáÆS‡%øü„ñ“Ÿüäè£VJl£îS‘åõàƒ~„sùøßø‘H,³ür¤î Œùúë¯ÅDÝyÖ³ž¥µ^Hùï|ç½ï}ïÚµkwïÞ £ÓkpQþe¸óÎ;>úèÅ–«åËä-·Ü²XŸDi_ùZèv»§Ÿ~úÞ½{—|úëëË^ö²‹.ºhÁ—Þ9733³eË–«¯¾ú{ßûÞ‚~õ yù³°ÌQýJ»’Ù46mÚ433KïÒÒþ„¹qÇwŒ^#y䑟ýìgÏ>ûìoûÛ‹ëþÎïüNQ]tÑ#ú]z¥,K/½ôÌ3Ï|ýë_ÿ?ÿçÿ|Ä£Ùéío}ë[˲üû¿ÿûåÐû4žÆ¿´s*EÊ EMʲZu¸÷ó|UÕ16S“YkÜæE‘¯_»ÆXVóÌÞ½e¯jJéYS­(Ò„X7^³Üù4ÒÝ„“¯ËaU7«V§©UkVM­Êòö ßjÂÙ}ÓÃá`ß¾ÕíŽwÚ”Ù•õ±òÁs*›FÛ*ZÝÎx·ÛÝo¿óýž241A3³»7(•Ä–&YÒ*¤XÕ¥m·´Ñ6s6Ï}UÇ8%RJkò)TåЧèZ-"¢/ëaS•“S“®È˜%Ošª&úªÎVçëÖ¬±ÆÍ÷ú(8=³¯¬«È J)­iÑšEQiS×õ?øþXw⨣ÖÖ¡,Ïy×Mí£OÂ#¥AkR‚5i† 3סIÂB(I<Ç „Gˆ2ÊÁ"a@…J)… ""Ì€ H!"ˆpH ¬X bRJXD’¤¢0¥Ä¢P£BBæ0:$©‰HXêÆûР"­HX˜Y‘E *¢"282Ž6>4>¤£J ¢(DCÊ)P ht”"g3a¨R•BĤšºf€”bQ6Ëò–޶a@a@PÆjŒ)¤cT¤ÁÏÌÚ’Ò ‰ãÌÌÌ 7¨ªrfßÞößorr²ªª~Ù×ά^»ºòUY•ÂÀ€‚ŠH|Œ<CÆ RŠ•rÎe™ÓZ3³O YYk“M¨@+Jœ†Ãa¯ß+Ë2¥¤”ʲ|íšµëׯŸŸV¥!³ „º!£Sˆ¬ (%*6Á×Mh$@PÌ ‚€ PÒÆhklæ´Ó¡ªzƒ¹²,@MJŪa9 Æ»cÖÙ¼È\f4)ÔH†€4hRýºÜ77ëZY¯,wíÝ;ÛÜþ³;|“îúù=USwÆ&V¯^³aÆNf‚f8|•9ËÑ7u™bC„Va‰lfµ(Ï„ÐXKµÕdÉ8¥­±™R(¾®B]ùaU͇3}jH'¥Ñ*-*/$1#i“)Û;aŠ)V…¨‚¡ˆ)#0`”ˆ@%,1)”(")QÄÌÁÇAä¹óM˜õa VSaíXÊ×󨸵¿ñ¿±ØÊQ×õ(°ÇG>ò‘oûÛŸûÜç>ò‘ìÞ½ûÙÏ~ö«_ýêï~÷»#OÅŸüä'gœqÆÿú_ÿkÇŽ§vÚÛßþöÅmžxâ‰Çü׿þõ{ï½÷€8ýôÓüã?BźõÖ[ßúÖ·¾ño¼ñÆ™ù®»îzDÖÇÄÒ-_pÁW]uÕŸþéŸ~êSŸzÞóž÷GôG‹ëþèG?€?û³?ûèG?zØa‡-äm_У– hi,Í«åpã‰ajjjd×Ͳ¬(Š‘1a~~~®s%|^_øÂ¾ùÍoþå_þåG?úÑ5kÖ|ò“ŸÜ¹sçâ<4OßøÆ7.¿üò[n¹e8}ôÑûØÇ¦§§;Ǿìe/+ŠbˆòÔSOÝ»wïÏ~ö³‘ºûùÏþšk®9W¿ìe/ûÿñ?^{íµ·ÜrËS½WXzÌ_øÂÞùÎw^pÁgŸ}¶µö3ŸùL¯×[‰ùùÏþOþäO.¸à‚³Î:kÓ¦Mï{ßû®¾úêeêÉõWõ¥/}éÿð/¹ä’“N:éÌ3Ï\¾L~âŸøÖ·¾uþùç_tÑE£SˆO–´¯|-lܸñ /üÑ~´|ó„N˜œœ¼êª«î4M³}ûöÓN;íïxÇôôôÒ_–3 ¿lT+”Ø'<û£UÿŠW¼bôxÍk^³iÓ¦QìâÇ¥wi}êt× uÝ<þÄã—._žÎg‰WήHˆ,b)ëª ÃµÝ݇ÿÇÿˆœÏž;›•ír¾X¤”ŒAVM̪9rå<©‘$3$ç‘03 ‚ ˆA5$ „•3LÁ¢!DB£„†È¨¤œRJÎÐ,!çÌ)«Šª¨€‚"‹‚²e5F€E ¢QaænrΣQc¬•Ì"Bγ¬˜U³ˆf£¸J•2ÄÔÇ”U3’pŽD‰@­!pd Ô ¤¬¬$Ñ:g²á,)…8tÝr>b$W(rÎÕõˆ9UŽ‘ÑY‡D$ §œpeü’5%IÛwÓnšR:œðö·¿}uêóŸÿüs¿¸?õS?õ‡ø‡« ¢K—.ýìÏþìóã©Dä'ò'ŸS’øÜç>÷ƒ?øƒ_rß|ä#¯}íkåW~egg766^È&®›—üàƒþú¯ÿú{ßûÞ÷¾÷½1ÆßüÍßü™Ÿù™çûvî¿ÿþw½ë]ïz×»®\¹ò¾÷½ï·~ë·ž;{óÝœ›÷Õ éÇûÞ÷¾·½ímÏ}\ѽï}ï{.ÂðE÷óÍù£?ú£Ÿû¹Ÿ»ï¾ûÞýîw¯|Vßû½ßûRâQŸÃ{ÿÀ<·öÓŸþô;ÞñŽçWøÃþðs‰(ï¿ÿþ•ù´ªÆùóçWR½«˜·?øƒ?xn8¾ªÜ¼Î>úè[Þò–ßþíß^Ù„ûûûoyË[žÛ{yáÂ…øøÈG>ríÚ5xøá‡äG~äÞ÷÷ÿ÷¿íÛ¾íƒüà‡>ô¡étú¡}è§ú§_àœüä'?ùÎw¾ó¾ûî{Ç;Þñ™Ï|æ=ïyÏoüÆo¼ÀXè›—ü5yVµþçþüƒú§ú]ßõ]¯zÕ«V™~nÂK…—2c_Ê}W¦æJ¾«mÛüÇ|ÛÛÞöO½|/‚—X«›óßø¯~õ«Ÿ?QŸï&½É“rsTõû¾ïûî¿ÿþøÃÖZ¸qãÆ›Þô¦¯v{s¿üË¿¼ †áýïÿ—ݤ½7ŸÇüg£k;¢²,÷Æe9©&£-„ýé»}øââpÖž¹oÍ“¢ZLaÙ*”6tc9ë‹ÄûÔ»[¶OŸÞ9Ihæ}KÖÄn\ß?:8ZÆåÑtó'cïº÷®o8}ïÁÁÂpxpõà†öGm ²}æ”-¤Ôg‡v¹\Ãà½ÇõxÔÇ~ÙµY¹º¶[Xkjç Á0ô]ß“5[Û'æGÿŸ¼|jckSfóiQ–Î9Væ˜ÅnÚ]¹zqkcâíùº*Å•-M7ôJ`Kïë,ƒöC樊ª(B$XXBÌ9ƉР‘Á•?P2ç,lɱBFD4Þ¡¬Rq°* ’€ÄÂCTPqÞbfUñeéUSæ’!ã¼³…SHD†r†$Ù°µ®°…‰)£cUYrÈ)RcÉxRK®tE]:ï ¡ú°±¾ÞÔ„Bûnˆ1†":g¬…”3²@Ì9÷}P2Öï½QBE- Ÿ3#¢÷Þ¢éefD\.—€b VU±¹¹ ¾ôãµI7ô‡‡Î¹ª¬A‹¢ÇÖ9ï½ê*y ‹0gQe ­Ç16Åxt8k\ík&F¥²ômÛ>õÔS}è66×+ï+*­s'NœèC¿l[W¸(yccÎ" À‰›IcI¦‡So¬s>`lÛÞS6q6ƒµE]g­÷“µ54°˜M§Ó, †@43«±Ö¹˜3 †²râ„ÖllmF¡>_Õ•oR«QÙZÓ]ÃrÙ-K¢ÞºsÊœ«ªØÞÞºýöÛ6›* _ gHGSa)F¥oêÜ£ñˆ»Å’«²R`ÎÑXòÞ[‡ŠœXºÂÛlL·hwº£…2¬¤0¦°žSž'.œsΠѩں\­R1Ô,&Få$•µV(÷&öhmΡ´¢’“r}ÒÁ¢ßmûÝ6ì…´ÏÜ"J£ì@üÑôºÛ_s“M<88xárüDtÏ=÷Ôu}éÒ¥/ùù·ÖÞu×]ιGyäŸõÚÝvÛm;;;»»»ÿêñ7/ù–[n9þü£>zûí·ÿíßþíë_ÿúç¯sŸ={vggç‘Gù§ÿ°¿l‹^t_}U{ãkÅx<¾çž{ú¾ôÑG_ºïô9꺾õÖ[›¦¹xñâó5r^ÛÛÛgΜ)ŠâÉ'Ÿ<88ø7ëŠ/[ç¢(^þò—À#<òO³À—eùŠW¼b¹\¾p×ó=-gΜyôÑGÿÙxΛÏÉ•xé0 oûÛï¿ÿþ²,_ø´¿yÉÿŸ…= /eƾÄÑÿ:ì—ÈÍŸ”/ËúúúwÜѶí“O>ù}ýE·×9w÷ÝwEñøã‰‡ó˜ÿ̼@ ‚“'O®VŠþËÿ×8¯„®®}U–£Ñúö‰fm’Uwn\Ú½d@ÖËòôxíŽS§ÿÛ]wß~ö¬µ4ï×g‡—÷žº~å`¾Ç‰Íæhý¿Þõ ¯¼÷^r9Næ—žºòÌS—žyæÒþþaY•'NžØ9}â¶—ÝvæÜɲò×®\{ô‘/|ñ OÍöç´¢©|5iŠªоËÅbzpØ/[oì-§Nÿ߯û¿n=w ^ß½öè{üé/^Ý»‘I&;ë~£‰Ц”̰v°,¦GG‡–Œ3ÖŽ9Ï V¯M굑ó.¦Ô‡¡5uY[²Œ7ÎÏCŽC´H÷Þuï7Ó·Ü{ï˳Èçþás_xü‹O?ýôîîõùraˆšª4!„¾ïbŠh «¦ÜÚÚ¯MŒ39g_fåæäÜ·ÝÁÁ¯­o=f²9ɘУXRðζРaâÑ ‹¤½À Ä)ÆDRA"´Æ¢"€ªgacŒ1ÏJX+( ‚*‹®RN2+¨ÂÿVAkÉ®r˜«ÒÊ%GFEXŒ5r0=¨ë²**£Ä1§˜5«A»Ò(J¢ó2Ç.ǢΘқÊSe«5W¯UÖ9"Kh5éx4‘̱GóÝ«×.^¼Øv½õÞ”¥) [•TW̹2™C !G¶ÞïÈ‚òJ3IÔ’-\éÈ kìú4°‚VM¹ybc{ûÄJ9¥®çü0 ‡‡ÓéQñàà Æä¼w…ÏÌ!„aˆ†Cˆ¢l­ñµ'K)Å®k»e–a>Ô¶š4“ÂÆ Ô£òì­gΞ=³sbûÖ“·¤!ìì]¹r¥}YWzñÒ…Ì9¥¤ªÆ¸¾í÷AD‡nX.–ÆY1€Î ©+‹µ­õ°½— IDATñúÄU¾(}ˆÃüh:ŸNûÅ"wƒW¬ÐNÊzs<ö€gÎìllŒËº˜ÎO]¸r8k›¨P4#Sø3zÓŒêõ­Íñd¤ª‹År>›ç$€Ö˜j{ëä{åùïßþÿ¼üŽ[ 2$œâp8Ý{ôñGÿîþáÉË (üh”€Ö6·Gãµ££Åál& U] f¡¸vb4Ùª–€˜%En‡ýK»7.^[Þ˜Û¥:ž”8ñ²ïÁ•™6üä–ñÖy[Ÿ ¹¨A½$ÈžŒå®Ç”¡â!@eMARQ H)æ£.ÞX×ÚáZâ)@G(ª˜¤…=˜ª‰ýŠÞ›"ò%ŠÏ‘sþ—N=·~|áÂ…¯ÆÛüæ%_¾|ùòåËð|áŠç¸råÊ?›:ü…´èE÷ÕWµ7¾V,‹U–ÅååÞ®{Ñ¢¾{{{/âOÿ¿AC7ñ¶ ÃðÙÏ~öÅÝúêÕ«+퓯hNzï_ñŠW|îsŸ†¡,Ë·¾õ­ŸúÔ§¾¢u–›ÏöÏ‹…—2c_âèöÆKäæOÊ—åèèhµ‡â߬½)¥ç‹¥sÌ‹ÃyoœS"g-!ªˆ²¢¢#S¸ê䩳1¹moN1æõºÙ\_ßÚ\«Gu;GäÑmŠŠÔ!>öä“õ¸9wËödÜT¾ð`‡6\¹t]g“SˆíryõÊÅy»¿6iTac}rû­·–³ÃÝÙrycXöbH ¹¢°¾(m2£±¥Ïùúþ^ÕÔMS‹ˆ³¶°¾vEÔl 03/rQGVlF…,JÖe1ªˆÆ CH„„ˆ„„qCî ¨©×x_1ÄE»¼rýêáÑaÕTÆš“;Û˶/f‹åÑ{@B $kw"¢¬Sjû,9gs†Œ³8æ¡CÊ¢ÈI–‹Œ#¶6àU@}á××ÖØƒpƒ2ô‘cT™EQ4dQ˜-  "¢ª¨(¨€* ˆ²¨ˆZ"\-ï®ÌK]™Â" "*¢ ˆh e%HÙ9K„Ì9ƒ**¢÷ÎYãœß€ ç,q̉%å,¬„ ª`LFH¨%ƒdPD%’”‡ÐkŒÀØ0¤¥°®t~}}ƒTõàà  1 ç2b努¨HYA §Ô ­)l5jœwÌ9¤°ÚBËÀÙ ±hŒ1¦rZV¥±.¤ÌÜ"¢5¾*šµqYØrÔL‹(v]¿ Í%MLlˆ½õ"-"¨*(Ue包½sÎÜ»¾ëSWMêµÍõq W®_³dÚ¡7¥ßÞ˜ìœ:™…CNóù¬ïûbŠ13+`ÎI²fQ0V‰ŠºT‹ŠPÖeÓ4uÓ°rÛ¶óùÑÐw«IÊ" $‚˜ 1DQˆ†tHI!cÁ%k¼q¥m&“f<²Î !daABPMiX,§‡7ŽŽŸ®½ud­+Dz¾qb{¼±îöo@BkLY–kë)gëLÈ’ ³EáÉkˆQ•5GÉ‘% 28t•/+rFI’’S{_Ž\1(˜­¢%µ¨€¢Y$A É ’#,™sÌÌ9ª`ˆyÖ‡ý>LSZ°vDA®Ò¨ˆpfR†¸°Ç/÷cŽùON]×÷w÷ä“O^¸paåVúguVŽ9æ˜cŽù7 ¨|ÎL†Q2‡~è—mUÕeÓŒ›q]¬¡›Ó^8œÌ—W÷öoÏF“Æ—nT×ãñ²[ç¬ûG3$ccÊWv¯×OV,Ý]çoÝ\Û4;'.¯XB]·˜ëac«É1ÌŽygOŸÚqP„yÕÍ´[´Ë–QKVc-9ë›Z9&±t0Ÿ­/æÆ ,ËjksË:»è–]bY”‹Ø“¢ZIš ˆœ¯Ç“0PEë-B °é•,j¤pÎKHœ%Q ئ”²,]Qtý0ïÚƒÙ´ÃÖxkûÔNÌi6;\̇¾ 1®dT‘"0BJUHTEDU‡a¨ª ãœSL¨.jUE1}—2,…ØFƒ…¢ð1ÆÒRÕTFÎCb²(Y"gc •Á¬6!ªç „hˆ8ñJëÁ" KN™EÑ’(°(€kÐ@äœ9|vs¨!2¨  ,’RUƒ”c–,Ì¢ªdÆ”ÃБóè]&PKˆ„ j¬‚4ªÊ9IÄ‚9ÃbÞ mÚX[m'kõd4ªêz<Ìfó¶íSN ª(4†,‘%4DDˆŒ° …5„¬9ç Lå˪¨­s…+(§¼ZÉv¦÷¶(‹’ ç;´¥/ $£ ¢!t ŠœsfbdaV,¼B5#  e‘,9æÜ§´wpàëBDNm´@‹vI·NnŸ¿óŽãÞô0©dÑrÌŒd›Ñ(1g¶Î[_€A,  CÕ¨®›º,‹! U½u–¼Äœ»H€Š6¢J4dÉ€‚˜E‡”»0ueœ$faTTðUe}s\,—mÛŠˆ1–ЄbìæóƒÇŸxt\Ù—Ý~nk} •ÌÚæ‰µ­íf÷Äh‹ŒA@ÎÑ"6U™sPï+q®©*ç¬b& BrËaÖ/‡ÔgHj yc¼1(š2+ˆ16NBˆ©@*K¢BÕ£Z`!ALY9h4·ºRõ%KJ’™³°BΆ8ëÃ4ñŒu`" e•┘BÿŸÈæ|ê©§Þò–·¼×å1Çü‡äèèèÞ{ï}õ«_½¹¹yíÚµ?û³?{qâÀÇsÌ1Ǽt¼·¢QEDó‡v›¦ôea]$[”Ø4IúÛÅþlvmo4®ÖalÈLšÑ‰µ`ÉIâÙ20‹"¶ÃpñêUKys܌˨ gï±*mÛw‹ù]>ÃÛu5A„“ˆxWŒGõx\÷}ÓÆn1t,’“úºC«°P°&LÛåt9/›’êQ³£'G“ÑÞþaÿú0Ä¢öŸ¯¯¯ßzî–ç$Ç¾ÄæDS°(¢(ªH ©ë¢/²µm òθʕMß÷û‹ùÅk×ê¦ ‚¦.'U=”½3¾]öÃpÐF@FÜ?8,ÏlX«& ”ó°±Þ¤¸¹»Çóv1;JW/_®ªrcc}L)×¥?±¹6tíláb4!æA{KY%‹R=\Ì«½Æ™õɤ7¾,‹eÑ Ÿ¹.Äv¾ì†Ö—3Æ%–•uÖö]? }†”bY­ÕM£Ê‚ŠªÊI@Ð'¤€RRëÝÐõ—¯_ý»çÞ»·Oœåý½í­­²pœ¢"! D$@ãŒ+¼uNDe%QÓ÷}Žpe¾•Eã}Ź7¨…÷eãë‘êÂ{Í 9ô•Í9Š$‰)‰p¶ •,Ù")€¬r˜ ¢s! (+¬TkYETUq•Sž¹]¹ U„Y3f@Y‰ePÊYѬ|×Y4«dU²®¬c]?„Ãétztd'“‰56çìU•Câkׯ\¼ðô»³ùì®;ïMÆ]Œ`´¶^‚QJ¹,˺ªTtɬ¤k“q5.#…dRÐA™U•w݃ EGŽ _:cPE5«fUÍ"@ÎRI¶4ªÆš â(’3e1"ÈYR¯©•¸ˆá(†¥p¡gf…ÕZ "Kʃ€Q1,,œ…³ä¤"€ ÄÇÖsÌ1ÇsÌ1Ç|õ Δþö3Ïn¾¾»{}w÷›^ójïý—\6Y‡4,Û6ÅhÈ>û?Ç¡]F´\ÕŠNÁ"¹¤x¸˜_Ú½¾¹>ÞÙÚ¼eíÔúd¢‰¯ïV )_ÔãQìû½Ógžº¸^wNlŸ:¹é­nn6E W¯ó¢íŸxüÉ£éâλî>súLUŽ8äÒZsrs1›vÝØ[?BàgWÁï 4”RšO§ùê•,|û¹[NÜñÎG"R–UMÒr(ÈZëŒuhŒ³Îû¢¨}LI$‰ ’%k8I 9p–,aHHä½7Ö™Ì<Äà¼Gg³Êƒ½Ç¾øø•k×67Ö½·“Éhssm}m¼»kû•UÀk¬”¶ou)[[[aÚÅÒ’-œO!îïî[ç¯_¿΀ƒz½h¨v®ðÞ#QŒ!ÇdÓ‡0Ä3 gÊà€2äÄȬdŒ®,;e`è½GaafQE \Ùº ’sB!"X)åœW— ³5†”eà> ý*sIQÎùÂT”"sRŽ™CÊCNj,9Û…!„Î×ÞQ²æ  ÊYûv™S݌֬wH$ÂËn9„ˆHk“ñ­çΜØ9qöìé;;Æ}—óN,g0¦¢ä”2ä¤)HRçu.ÆØµmìƒQªËÆ—¾.J«”c8…œXXYbˆÌV¾¨|Y[[":c¨š„XªJ’4HjS< ýÁfD Ä ‰9±Š€Š*Kbdᜀª¨Q!ÉĘ“J¡c›ókLÓ4çÎûJe_›››'NœøºÃüYçcŽ9æ˜cŽùgyúég¾äÈSO?sï=wÉÁ­µÝ½>¥a¢u!1GÎg"C΢ªJÆxŸ˜µËƒÙÑb±˜ÍfšsSU;›[Ý]–)* ±âôp~x0½åÌé{î¾}4Y+X‡,÷0£í–ÃÞõÃI½¹µYYgظµ5’,u‘F!/ã°}Ë ¼·…gá~¹ðu™8ÏûvÖµk)ÄÅе¡O9If`öÆ’±ªšbL,I¡Kº¡kЦ†œ¡ëû<ŽQ9s–Y¸”ªYíôS1€‚$„)Æk»×?ÿÈÿ\ŸŒFuU•ÕæúÆöÖ‰ ååaÙç” ŠrÞk™sßõ9Eç ¦!ÔeƒþYIkL×bM½VyW™¡ë2Ë¥0G`91Yoû.Å$*àÀª‹¦”¢”l/‰s "P%I1€ŠŠ¨¬¼”Š +M$ƒˆ`5Æ ‚ˆrΠlÒÀ[ë¼sfÕ‡CìˆrJ,Hä½õ~\”.§6Æ!Å(‰Q3!@VÎʈ@ ¤Â9…¾ï(Á ëC× *Ð<þÄ“ÎÑ}å+ÿË+^>™¬å¤}9ò‹*J8°ä˜’¦ YÉ!‚p2Æ8kDT„ˆhµµUDCˆœ2§,Y‚‰aˆC ˜4΍êºO&uUê‘qnè•KWö ©s¤¤Qªª@qÐÁZ‡H®pÖ8e ƒ`Ѹb´6ªG5ÅÍhÈÄæËÅãO|ñ™KÏ„V›i³è*Ë ¨ª+˜IˆŒ%kÑ«öaàS MU7Mc çË¢UÎ ¢š’@d…!¥>FÛ g6Ö&°¸\a‹²Õλ®G³ùkLQÀÌÖšº.ËÒ-ÓóR؛Ύæ³k7n¼ì©§wNŸëÖ67Ö­QC®,KÎÀ2Ȣ«ÍÃ(Ĭ)æ”rèbßî‚fH`¬%¬SN‰AÀ  5ÞùÒ8HÂ@€I À dÉ’{Žm óf)-œWcQ1!¬ÊœsÌ93‚aÌYqF®nµ°BÏ 6ç(éÿgs¾ìe/ûÅ_üÅ×¼æ5mÛ~âŸøµ_ûµ¯Èºûªúû¿ÿûõ×ôW©dcÌÿø¿ño‹ny´˜­·“QU9諸)deA5Þ³Q²Ä˜rê»63 zoI!«¦˜D‘²ˆónècbvÂFUTY%ó I9Íó/>ñÄ/;ÿ²Ûo«GÕxmÜŒ–ŒÆ( ¨‚":k ï1}@ÙZ3;šÖ{ç}ኲ¨ÊJXp9D%*œsÖÆ!õ‹…) ¨¬u„ª×÷ÚyKLUQ–EaÑ RJiˆ!² kŠ!§èŒµdQ@Y‘•V[4W:@HDÆ£ Ì̉Iˆ9sÊI™W#"ŠhRf‘œ“ªksžSfUU@$‡ˆDÎVdÑYS:SXÖ, $ ¬ÂR7Oœ0ÆfÁÈçœYTEbŠG³Ù… —êªZ›L&ã5ãÜöö6‘‹I‡a¸téÂ´íº¶ïú.J+9YM€7&ÆX±_ö)$欒Ék0Éjgä”WþÞ†Ù|hŒ1œ¸*«íó·ß~öÜ-ëë!öíü`O4£EW8´$Ì‹¾¦–¶jêqáKPDÍŠ ¸½ª¢BY”, ²dÓ(eÑõÝ$hšÚ9/¬1Æ”2³@Y—£µ±’†0ôý‡¡öeY× êŒµÖ)KV†Šü¬:ïLam%'ŽH®ª©¬|Ù +È;[xDŠ1ƘÈZHݲS榩…ÐNÖÇí²ÍÊ °h»§/^šuáÜ¢½åÖ[÷®pãÑèì¹3·ž=‡áhzØ®¢î122P6€c }?ôçD¤–ˆ”P UX……Y€ŒWE Bë€ì*…¬!%‹Æ*‰Eà,9¥”bÌC–Þ Hf–¤š „A@Aœ5€@U4éjr‘"ZÑÿcsžxîܹïüÎïü··9¿"677ÿæoþf†ÃÃÃ3gμûÝïþšäù÷2¾Ç-:æ˜cŽ9æëUý²G`{\ëÖHÊ$G‹>N¬’™†TB–’¤œ©¬ª¦(5 ÝÁn»è¦û•jœ.¼©fó8ßï»Yî¡'1cÏ9 ¸˜d¹ìæ³YÃæ¨™T> ýþÞÁÕꀗ)ÒA7Ì#O—ÝÆ¸×îìÎö­§O6uux4ã¿þ›Ë7."ÄÐ-Û…­­×u ) Yò¢]L-mÖM¹™Ö$ÇœbN1tƒ­ ZÅ’¦œcHq˜¬¯kHU™QÅ qÆ*š(1iV4e]  &aÁ:kÅ[PPfnÛåå+—¿øÔe]4U¡Þ¸Q¹¾³™ ª2(zo5qÚå‚s*‹‚Sb¢u¶$ÚÙÙYÛ\?<8²}Ÿ8[d‰Ép’ÄÂÖYDUá¬ä¬5eQ5M]¨º˜Ï†e8X$dÉ1IbKΕEQc-¡±†sR )* ¢áÌ™U”œµ+‘ÉŠ$†" ²Xçh`†ÉTUU›BЩ&da£X¢E `‰<¢‹Ö;àA2³’qU3^ë†Â¬]ö‹˜‚#bŒÃÁÁÁжû{û)æs·œ««ú–[o¹ã®;CH)¦ºtÊœ#}ðd˜Œq"°XtD€„Î’5¦©+gŒuàK0äm$ìB Ý2sTîÒ€ÝI dMuSÜrîômçÎu}WxŒÃ¼]ÎgË6µD†VÂLŒÙ;‡€)Åœ3( !P•ù|S 9…ïÜJžª,JTµfMròΚÉ›ºéC˜Íç2(*‘!_ùѸ6†úÞ…Á8β˜-­±®,½/TDÇ㵜²Ö5¬²¬΋¡„ ÈÌ«ñ¨¨j%d fåœSˆQË¢ª‹z1_"6d³ÎÆfËeÈ Æ±êÀÐÅ<_vCm·¬šb4ªœ%k±Z‰DÕSp‰ â IÌÙZ¨ —½é9÷“E˜ U UQ5£f@k½«+rVUM V½1¨CR°d*rå’Øc†€šT’pfÑ̘˜Õ:Uò²m•E2BFL"Q$d ÿÇæ|ç;ß¹³³sÏ=÷¬nGGG¿ð ¿ðþ÷¿ÿ?ªÐëw|Çw¼ùÍoþáþáßû½ßû÷Rçù|þº×½î³Ÿýì;ÞñŽ|àÇ¿ßÇsÌ1ÇóŒqée},¨KɽB4"’z5Œ) KÆg}aÈPè,'î-tYâѲ•aЂÊq©„‘»0,ãPƒ1Íg‹Ùáttr«v¾°N8÷}·ì»6a‰2€Æå†˜çKS7õ?wÛÎö0yôÉGGc_¶¦ qèZ_Vämá}ôžÓâÐ÷­ÊÚ¤©‰¹Ï ´ìRC¤‚Ê’¢$¡IS ªI¬!klac2 8RÑ,YAÑ ¯‚3sΙ9ïOŸxú©¢ô'¶6—ËyFm®uY0‡0pŽDF8ÇaH! çXxW•eŒq¾˜'Îe]žŸå|e×ÖÇãQM¥K¤E…3#ðÚXrŸ¢m;r=‰…E-™>õ³ål¶˜ÆØU•­ë‰5·Îgûû»ÓéA×õ†¬A# )眲fõuY7 !¦œsJÊ‚ *’RìÃ0¤° Yöeá]á‹Q3Z¯@U•*"©¨Êª.‡<°¡ñT6" *)xç±1¦¾ëGó¾,ÊJYˆÜÉ“†™­±d K†ADŒLHLå±@U%$åÌ,Ékª¦*B†ØÔµ÷¾, $ìúa:›w!¦$"Æ×Åhm£SÎ!„”BJaÚÙ|º¶6ã‘r¦d¼Ï1d@LF-)hII¬EcÀ:rdD(+`LŠ¢$¬œDøÐC}û·û=÷ÜóÐÿf4­ÎÞ~ûí<ðÀ£>ztttñâÅx`{{û¹2ßüæ7?øàƒ¯yÍk>ýéOþÕ_ýÕ+^ñŠçÎÞ¼dø¦oú¦O~ò“ׯ_ßÝÝýë¿þëïÿþïïôú¡ú¾ðâ ΗÒ"xãßøùÏþèèèOþäOžëÃBŒñá‡~);?ÿ¥ZݤEù—ù=ßó=Ï/çƒüà¯þê¯>÷ñÎ;ïüøÇ?¾»»{ppð‰O|âüùó/°>_v|oRç}ß³gÏ>ôÐCïyÏ{ö÷÷?õ©O}÷w÷… >ÿùÏ?¿ðoýÖo}衇¦Óé•+Wxàõõõç—p“Y÷BZôâæœ?þ¡‡ú–où–ŸÿùŸæ™gnܸñ±}Ìóe{ãË–|Ì1ÇsÌ× EYŒÆ“õõõõñd\G¾®÷B”93…§QUÖpÎÊPu]+ "*;‚͵ñ-'wΜ8Q›ºn~4o»¾Âl6ŸNº¶ú~†¶mŽŽ‹EÛu‹®[v]7 }Hí0Lg—.]¾¶{­ídum½išÒYch¥ªÂlŒ1H**Ì*\83jšºª1„`qÖ *HÉB(S»˜'oÐÎ)¦²2$K1ŘC–ŒÖ;ï="¦˜B!Æcq¾X\¾rå±Çü‰Ç¯\»ºèÚ¬b½/J_”…÷žŒQ–”2 "sQãñx4!áÑìèÂ¥‹×¯_GR_X猪„¾ï–mRœƒH‹`EQDAV±¾Dä«Â7•­<6[HV“…l1¤=ð"íü`9ŸöíS ]EÐÝÐ"ø¦yùˆ¦A[ø…ˆ(jŒ‰ÎFÅHTŒA0Ά¶•àØvHÅã&2ýE¦—©¤»«ººª©á©ç¹Ãö´Ö÷ÇmK>x)JJÀ?žß7çž}ÎÞgí½Î>g½÷Z[››d(æØu«Åb¾\ÎW«å0 ýªã0ßß_Ìç"%å4Œ0ÖMÝNš¦©'³6Å8ߟï]¼Ø­VªêœGæ"ZЍ9_µÓéÆÖæÎ‘CG9rôÈÆæ†­œk[·¦jlÓTMÃÎ(*2øÊµm  !Ķmïj›v­ÅÖØº®1 ºÂÆ0¬ú0jšÉÖÖŠJÎ9Åã¸\.ºµª{ëÏÎ!2ˆ rˆ¡ë»åj©ªl1lõUÝ6mÛNêª2Æ ’"¬Cö¤Xâ˜Ç! C†<ô©sã<±—bâ(ããXR,9k.ZA E! ¥ E`Œ A4]OßIb–ÌìçDÄ[n¹å oxÃ¥.ü¤ˆ¬įyÅ+^ñK¿ôKüÇüêW¿z6›½à/xúÓŸ~úôiø“?ùfþ¡ú¡cÇŽ½îu¯[BXo<íiO»ùæ›_óš×<øàƒÇÿ…_ø…§?ýéÏ|æ3ש×_ý×ý׿îu¯ûƒ?øƒq_ùÊWÞ}÷Ý_ýÕ_½N½|Λ››ÿðÿðÞ÷¾÷û¾ïûTõÖ[o}êSŸúÆ7¾ñJúô¯ùš¯y×»Þõu_÷ußÿýßß¶í¿þë¿ÞyçÃ0\ɹW#Ñ×}Ý×½þõ¯ãßøò—¿ü9ÏyÎoüÆo|ÉcÌü¹®ê2íííyïððÍo~óúà#GŽüàþàþè®ÿÞpà ÷Þ{ï‰'~â'~"çü3?ó3o}ë[¿ò+¿2Æøy/éòí{ùkþ‚Ë­ëúÙÏ~öÉ“'ò'òOÿôOo¼ñÆþáþ•_ù•—¿üå/yÉKà)OyÊÛÞö¶µ^=zô•¯|哟üäg?ûÙëIP—׺Ï+ѬWÐ¶í³ŸýìW½êU[[[wÜqGŒñ…/|¡µ¶”rùÚø¼9pÀð?„bØÙÉÔ¹í\VQ t !ƒ@ÑTF âkS;pef[µÍl{{{gZm¶þø¡£9éîÅÕ©s»§Î_ØÛ]¤åŠ’j$#ŠýRAìBìú1„”“€BÓ4³Í ¶µˆZÃÀªRÊj¹œÏ››MÕ6¾¶d •A¡¤ÌL„È ë wj {דּˆrH4ÄE›~‰¡húqåÔ¹\¤dAÄœs”’TÈ㵕äˆH•¯Û¦­|€aY ŠªŠ„Ο?ŸSÜÛÛmš:圳ž={¶®'k«r2©±h?,ûnÙ÷=6m‹Ä¥³iÛ)‡1ž?¾Èæ‘C‡ÙrÜM«Å\Â蛘$çb­ñ&…‘I!fÌ+%Ç@©žLÔA³ö#Ù¤Œä W“*ÇŒ€hY-É Â gͤ]♩òÞ;o­)Ä䬂ˆ@˜bJE$–œUI AÙÞØð•G–H%7ñ®ñà8cQAˆ¥Dë|[·u«C?†~\-WËÅòâŽÅþ¼ïG(hŒSÔØ<­ê:§ ¥ìïíí_Üú~s: Ýph{릟Ð/»ÂîîÅ®ëDÕzWD$¥åþ~IcŠ}êCWR‰ÑšMZ©u±Z,öWcˆ`­›NÑZk±Î:I‰1ý0œ~ä‘i[=zxggÇûúرãüã=s®ëºÊWâDAÉ0µM=Ž}?ˆª(3oˆDÕ¡o¶ÚbƒäR2,—–‡Œˆ)%ëì8ŽÄµítR· 1`7ïrÉ EKŽq¾Øß™/÷766¦Ó©¨v«Õ8ŽÖÚÉdÒ¶ 2Õ“v³ª:kkç«ÊXϹ$µÞ³qËÅj¹\´õ¤ª+C\Rn&m=©‰‘™Ø8ï}۶ιÒgUAUU ¢iÕ8"ê‡A´ bÝT„4™´¾áP:‰¨L–Yˆ“$-YÊrË«LMLª1 ’c£ä ¢I$ EBÑDP€@…@I‘I…©Ê³-ÈB €ë 5¥à:§ŠÀ:ò+(‰T4Š&á?üÖN&çÜþþþvy¥¬V«õßãÇÿüÏÿüwÜñ#?ò#ë=ögvɹËë_ÿzøÆoüFïýgÇÀ|ó›ß|Ï=÷\ú»»»û¦7½é©O}êG>ò‘õcÌÏþìϾõ­oïýþá?~üÌ™3Ÿ7ç§=íiÛÛÛ/ùËßûÞ÷Àßþíß^yŸ~ôèÑ'=éIoyË[Þð†7ˆÈ«^õªÛo¿ý¾á®äÜ«‘ègög|ðÁ¿øÅ"rÏ=÷ÜtÓMÏ{Þó¾4±Ë\Õå%ºûî»û·{gggww^ô¢‰È¥/¿ò+¿c|îsŸ»X,àíoû‰'¾û»¿û’Åu.ß¾—¿æ«)î¼óÎ{ï½÷¯xÅßÿýßÿíßþí­·Þú‚¼`ôS?õS9çoú¦oZ.—°X,þüÏÿü¶Ûn{ûÛßþyµîóJt5zµæÐ¡C·ÞzëÚ˜üÝßýÝ+i…+Ìù€8à€/;§/ì>|„½ŸN6¦ÓH¡@¢È ”¸šï¦14Õ†ç ‡1.»0&©&ÓÇ]ÍÍ×][r9wþ‚i™¼*¦\BóùqR^týîÞ|9†aµR*ûó9'$ÛTµ2rRÉXBEi9ß™ïÍK.«e—BF4H H*b„¨ä4ß¿xú›ú!öãgN_ÜÛÍX˜©€¨ "c¼±1—4t«tâD‡C‡vŽ=j¬[­úétãºë®ûÔ§ÎÃc, (¥ C¿¹¹©¨ÃЇˆÐûÊyÇÌ„XPD‹·®¶(¬ÍÆ"YŠ÷Þa<}úôΑ#D´®-ËV}ôÌ|o¿©ëº®RÌD”Eúqdk릱ÞÛʯơ[-º0Ô}íœ#ä¶žÛ"%„RÇ#yg›i;M›z2©&Ù€bŒYRÛÖMSUu…D1ŽaAÕ±Umm=M›ÚcªºjšŠHBˆcEe’ÚI;DBKàAj&4ƧÖ×.ǪžLWvU(+U—3æI3i‚"Œ@ˆHˆ q&Sȃb$ƒl ”,©0ùÊÍ$o’CJYÂÚkÊ:ˆlVȪt;P <–¸Ò£Zsi4 ÖÑf/!"—¦í=÷¹ÏµÖ~†‹q¯¤÷TÕÙlöüç?ÿ†n˜N§ëI}Gýô÷Ýw¾óëu`ŒcÇŽ­íŠËóðËÈÏÿüÏÿú¯ÿúûßÿþ+MZc­½í¶Ûn»í¶uÑo{ÛÛîºë®oüÆoü‡ø‡/ªDÏxÆ3Þô¦7]ªê¿û»¿û’Ùœ—¹ªËKô—ù—¿ó;¿ó¾ðµ¯}-|û·û?þã?^¸paÕí·ßþŽw¼ãøñãÇ_ï9yòäÓŸþô/ö5_e¹óù|ý»ÞX,Óétô¬g=ëíoûÚà€·¼å-—v^¥Ö]½^Àë^÷ºÏ˽|m\aÎpÀ|Ù9;_`ÓXW)¢·®ñ¾Ôj²q\tãú…&ÁfÓX#€Ë>œ¿¸ÜÙš$µÊV&›|L”3`‰!Ë<ÔR€¢èjŒ]HquÕÎÚéÆd¶1Ý™,h±ŒÓ¦i¼ÃóØÕÞæw/\ÜÛÛôÌÙÅr•c&`Cl‰Sˆ#+hÉi²œÏksˆ))Ö­Õ¬k/®$\âcf•µ•÷ìÜXÒ˜¢”œ eÉȈKÊ!“,1çTBŠE2 ¨j.9ç CZÇ-$àcÇŽ!qÎ1„1Ä()!ÄsÎë`$ªc"*€XU•ª¦\V]wòÔ©Í™÷~2™cX-–)g$ô•·H9—Ø‘¬©ä¬!DmÚÆnøDZ¤DͲ%–ذc²–íP‚Ž”$Æb £åB”RN˜‹QjóD@ê¸X,˜ ƒIÆJ)HkG@ ¤¨lŒ1u­D.Ìš©dQa̬Jª¨jÔ(ÀÚn*%w]ãØó|¾œ/‡~Ô,–­s©h‰%j48:c_WÆí]ÜýðÿþesÝã®{ò-·lmÌíl‘´m¯9zÍl2ù¤1çÏ_Æ\ŽUURë­Q(ªH-*£wUÝÔóÕ*ÇBP‘‚`œw•cmÌãþ|~áü9wîÜÑ#G–«þÐáÈfcºqó7;ã/î]Æa C×w)EßÔu]+"8ç™5æX¤(ffï+ï<¦ƒ kËÛz#©ï1“Éd ÁY'EbÊC? €5Æ{OD€Ä1§œ³¨ ¡£©[Ö!SIR4G2ƳhÎ)Ä!æ‘-N§-;¦ŽVËîü¹‹º¹±ÁÄabeKޤH6ì,*‘µ¶iL3ÙØÜÚjÚIW}Ç­¥Tr‘ÜY&64Ÿ¡bK%Ñzf-³2[ÃÎ5®ie íJŠj½q ‚ÖR±¤Â”“bŒYÑ 1‘%t–|åR[⬤UŽ]@Š$ªRÊØœ%£ª”RrQ!QRŸö©¬`AÊŒsv]§ªkÿc—hšæÒk÷Ñ£GàÔ©S_@ïùÌg>óÿñ÷ööÞóž÷,‹õÚ6kí¥B—Ì×uò驗ᡇúžïùž_þå_~÷»ßRú—ù—û±»ÿþû¯äÜ®ë.\¸pÉžùë¿þë»îºk½Nï‹'=zôÓÍž;wîKö»L=_^¢óçÏÿÓ?ýÓ‹_üâ×¾öµ×_ý³žõ¬ïøŽï¸ôµâСCÏþó?céï×rÁÏuÍW_®>ö‰T.móØí°½½}ï½÷^:r?¥tiÌÿj´î*õj͉'>cÏç­+Ìù€8à€/;œß H“º…¢1Dµ„`ŒõµÍI¬¡ ¨&E@ƱÈÅevoqa¾<:nnÎìd³Ì1…Å~5uÖXæ,:Ætq±<ñÈ™í­é¤IŠ¡ÀsÕ4YÙZ¦¶ö›“sÌiù³çCLg=7t0ÄÙ"{ïQEs(„@ª¤`ȘÊ;"\ Cm6LH   R æ’‡P²¨XCuå¬6 IKI¹d6hE%K‰%ÚbE¬wëPŸÿåC DÊI ˆo< y  "L¹„!XËL¦Y.º¢Å{·ÔíïÏÏ]8hØ>|ø03ƒêØõ1F6† I("%(±¬­"XUÑXb )&)ÄEH‰ rí›&ŽI3õ# 3Æz眪Š"1ŠRbF©P=ƒaQA6ECˆ…™ÉSɬĖ]Ý4M]„€ID‹AA"$Q$@`c Q)’bN©¤´ cì»>Ž»ù*…dÙºÖ{W9ëJ.1¤Ó:‰kDbkÝþþÞûß÷þ뮽NsyêW>ykkëÈ‘íIÛ:t¨©ko݉'/îîî/æjˆS"¥HÊ%9Ë *1±Ö8kTØfîªê¦©ª*Æ8 CìÇ~µZ-–»»»ûó¹õ~çð‘Ùt†`JÒåbUU•¨¬úÕ¹sg—ËyÝ6¢¢¨mÛzï|í4„0 }LIT‘qÖ:PQUX,ã8V¾"æºiœsÖZ 1.W])mon;gUTíÚ]ðèA0ÄÈã¸^T,*Æxã5Ç@€ ”uÔW$Ì9íïï-æ«Ó§ÏN§³ÊWZ$ÆÀLÆšªñ“YÛ6u{gìt2‹Ûš3MgÛ;‡µMKD1Ř²ТSÌ¥d)‹åjÕUU •Ú$F@@PRAÍÑ´V3Bѵ‡`` C`@ I†{óóÖÆõ<à€8à¿‘½¡Oçw'õà”J(9eÉ¥(¡¨Qºj*1•\bVQ–$2ÆO]œŸ:{aëPküæ¤æzRµ­oÛ8c@˜T³HÒÉÓÖMuÍÑÃóÅro±š¯:rÎZk-£!µ¨ÄH†!‡nÕÅbÌ!$bbABT°ÄmUDM.–̤ ’SÒœEJL±ëVä 1±a@)%%È"±H,©„@ÆZg}Å̆ …"EA5)å\bLÑ‹Š€ÀÌÎû’³Šªh.‚HˆT²$)PH)åb(¥¬g“¦”ŒqHëq@X›DcCH¾ÊÌœsÃs\v}ÕtuU±3–ˆ˜dÌhŒQ²ˆ$ESu¡Œ!«BŽ!¥TDXs PpÆ){SMe,9³©ñ^Š0 :6†s.b)ÀÖØÚYo …¬0"¡apT4) ©\5­}]Å0sÌB† [Ad"6F¡‰C7†1Ý0CNÅ‘-©v~RYëœóŒc$ D ¢Æ˜ª®C д“ãþ|ñ¾÷½ks³mëìt2ÙÜœÔuµþvoŒ9å ˆdDLÙ«–¢9çÈŒÎÕÌVJb6U]5¦®À°ÆUuU{D\.—iH̹”½½ý”òÖöÎão¼ykëpS·+î¦Óé‘#‡­s÷.ªf$CcÀrÞÕM¥lÙ8SDP²2Pëœ÷ã8¦œ‹Š![7¯*…±‹…ˆ\sôèÆl"Rú¾+"ŒÄ†,Q!Bb"ÈHDÎYç­÷•_ÏÂ-š$‹"ÃÆ"[rή_õ}b¨s^,æ!DP™NZë*_y6<ŒC·X†1Ö¾šM¤Ï66f³YÛ6¾rŠJD¥”"ETcJ©E 1Ç0ö}¬Zç&F@ŠBAV²ˆ¹²¶VI†T$•”“1$Þ²ûB%©ŽV),!­ØM”²-(Åk+K¢”[SzƒÍFaÌY0g‘ šT‘”‘P×v®µÔÔÿ+å]ïz×í·ß^UÕzXéÙÏ~6¼ãïX§¾ûÝï€oþæoþøÇ?þ¹zÉårÙ¶ígï¿ùæ›ÿäOþdý²»~ßý¯ö¿Ÿ+çK<øàƒwÜqÇt:}å+_É̗ʺ ï~÷»×ÞƒÖ¶ÄŸøDcÌ}hëÂîóJtÏ=÷ Ãð¢½èÛ¿ýÛßô¦7õ})é=ïyÏsŸû\Dü?Æûoißÿ#W_îçâÃþð3žñ "ZO~Ö³žµÞyåZ÷…It5zuùÚ¸ú{ð€8à€/ì–CÈY½ QBAÉR´(Ù€µ¦Ê%kŒ¹d "‡qÈÃr-Më«Ö±Ók¯ÙtÖú¶žNÛÙ¬©¼1I1$"k÷Ý'zx5 !¥ýe—EEµñ•wΑ*‚:F@íÆ!Žê¼G²UÝ´Í´ʘTr‘”¤ˆ!ôlÅ:,Qrû~Ÿ@R^.ã0¤”SÌ€` £ˆHrÈ @³Æ! vpUcÛÚ±evEs‰)ùÊ+B.¹<†‚rZ¿ñ{¯¢c7„qL)11¦RÄø ™ÖNMÑX[9'"aKÎ¥¬çH±Àa 1e6¦HI¹XçDµërÖOک悈¨PJX,³± ¥’s)9E c’RJ9§õÌ©TJ)¢¢ÞUÄ&I"ÇFl ’U„A Zc,9g¸´ "ÎùªòÎÙc ‘˜¹fï½1K!EKäX-”T†8æÙ2›Š­A&Õœ³HÑÓj¾X­ú±RH’5ñÆ;ã½óÎ9fE‰õJĪbŒ%c¸”"R5ÍLE=wîþÐt6õµÂão˜NZߘÃ[ëO¢¹ºýù110±!ªT ªº6Æ)€¯ªÌ*-`lFT"cªŒã°X,4•I3©ê¦nÂj±ØÝÝû÷ÜØ:„`¶gÛ!Äë®»ÎZãO»åjî+sÆ¡»˜bØW½%ÊúزU¶@Œ¥¨ªŠŠ N&Ó"e½H—‰Û¶­ë6¥ã8A&Íôø‘cÞ³J©Œ1“h®œEPek|]×M#ª“ت1`L©h®ëª)’‰ÁX;¢õÊIæÙtbŒ )¦’µÖY$({û{ýb¾Úßc´~’K)EE­3M[g‹¦˜†\’¢¦(c¥H.²ê•q §u²©¤d¢RqŽaZ -«ƒ†RÆœ–dAÑ€·†ú>ZÑ ±Ä^ªÄÖ˜‚ELTÀXª²ÓÍ ´ fà˜Õ1ÙŒ\AQÀ€FÕ„ $FÉ""9•¯mý§ÍyÇw|Û·}ÛwÞù‹¿ø‹×\sÍ«_ýêûï¿ÿmo{Û:õ#ùÈ›ßüæW¼âçÏŸË[ÞÒ¶íí·ßþ‰O|â’Q úЇ~à~à{¿÷{ï½÷^ùÄ'>±~eÿð‡?ü­ßú­ögöðÃ?ïyÏûáþáÿj÷û¹r¾í¶Û¾ök¿ö¯þê¯zè¡ë¯¿þ…/|á>ð+18àþè~üÇüþà^ö²—9ç~ï÷~o±XüÕ_ýÕÚ$_°D¿ÿû¿ÿñ/}éKï¾ûîç<ç9ßùßù_ªŠoú¦ojšæiO{Ü~ûíçÏŸÿøÇ?þÙæÐ`e]^¢®ëþæoþæ'ò'o¸á†Ÿû¹Ÿûô¤W½êUo}ë[ÿðÿðU¯zÕÙ³gŸô¤'½èE/zç;ßù÷ÿ÷WÙ¾—çê˽ŒnÜsÏ=¿ök¿öêW¿úÈ‘#¿õ[ä"†ü IDAT¿uæÌ™¿û»¿[§^‰Ö}a]^]¾6®þ<à€8àKƒ©j-@€È&$*%e(Yáð¡cŒ¸?¿rBƒÓ©­òÞ…n¾X­úN@«Ömšnlm5ƒˆT“jckãÌê\?vllS»>Æ“gÝïVЏèF[5µs³é”‘såÌlRO¼[hÞ¿p6å‚dÛIµUÙÕ2Ηã†b0£³6ç šHÕ„’Rè´Æ¶u›‰œõ)eP0@•õRe±ëá[…$TÔ€óF½É¥€*Š(13 ‘’³æT‘€˜K)«®ó¾vƆaŒ) Â5Ç®±ÞU•3DUU9k­uã0Žã(b½÷)•cˆ‰˜¬sÖÚ¾ïWË®jª¢šKA€Ö×ksÅ01ª®Kë! É¡Œ91³uU£jQæŠëyªÞW 0›L¬m‚÷‹ÅrÇ,eŒ!†cdd}ݺvÖ¨Šˆ"AÁ,$h¡H&‹Îzk}JI©(ˆ²dHXD Š2g릮›‰J."B!¶K )öcìÇbbJ¥©&uÕTU2Æ QD $k­q6–„–5KŠ™§›ÖÙswÿõÿ½WQð¦›o®¼«›êšãGe2Ôã}÷Ý·X.UÅ×ÞWÞXk½õÎ!#¡x¨Ô € E‰ØZBŒ1ô}—ÇHŠMÕÔu *óÕòÿþÉù|õð‰S¿îñ(ð_ñ¤YÎ  ´MuøðVˆáÌ£§—Ëùî…Ýùr^Tˆ©ˆ„œR΄|hë°€ŠHI9#Ñ‘kŽ–«¦ž´Sgl)¥”BØÝÝí—]Û´‡womlnL›ISçœW«Õ²[.óTCSTUR1ÀDb.’‹ª‚Y¯ÿL‰”½wMëU‹hÆq¹Xõ]W{ŸrCc0å(š‹øqè/î^Xìîå”}ç‹qãr5Š[ömU¹& a ¡hf¦œsß÷]Ó‡!­–+UªcŒŠF¬¤j\3i@(6²‹ «Ð¥†®ÖÒXC†Á l4  Išˆæ¸vÖ; “Æœ5ÔªbogTY±&‡9Ô%6™ë”kJ¾ä>K ªª"„È-#2šÊrãg;Ûÿ¿qΗ¾ô¥¿ñ¿ñ=ßó=ð±}ì…/|á§¿Içw~çwÞ¹'OžüŒ˜üÇ|ë­·þê¯þê‘#Gqkkkí÷Ç~ìÇî¹çžûî»N:õ²—½ì3|}^>WÎ"ò£?ú£¿ú«¿º>ìƒüà:ÖÅ•pß}÷}×w}×wÞ¹¶ú.\¸ð]ßõ]W¸ºòj$zýë_Ûm·½æ5¯¹ãŽ;öööî¸ãŽŸù™Ÿ¹òªxík_{)¤çïÿþïÀoþæoþôOÿôU>á®D¢»ï¾û%/yɹsç.}‰XóÏÿüÏ/~ñ‹û·ûû¾ïû.}¡øt/©_pû^ž«/÷sñæ7¿ùå/ù/þâ/®+öÁü–où–Kqt®Dë¾0‰®F¯._WpÀð¥!ÆL€‚Àd@ m[_×Ë8<º·;†ôÈ#盺­Úf»µ€YQ'Æ{×lmí } }ÿþ<ØÎ&Ç®½a{ç0q=ŒØìö®õͤjSI¢©”Ê»R0dEBç+$ÚÙ>4mšÊ03¥”ú¡÷® 9B®ë‰÷sC¦¤<¬ºåb))¹ŠëÚf¥$EDf“‰%ò¾R E×k†å8™N­51Ž9'¶Ö²³\‰–0,Ç”² ,@Ù°7¢%‹äT˜¨­P°Æ*hL)";k,ü‡’#*眯œsDÜ+kÌÎÎÎÑ£G óÞî.ÁcS}U¨(ЬÛ ¢1íl* Æ:çªË",+¶•¯½µÎ²Š–PúqHE\í@¬\Ì—ª‘PêÊÕM­E‡®Ë¹x眵 eèú€ÙÔUÅÄë31f@@Äz…X×µªÆ˜TI©ìÍwÇ1N'ÓÍj“Xbß&çŒwh ɸêû±[¿“¤”–‹eÓ4uSkÇ.¦xáüÙ‹çvû~,©”T cD­ TÄZ笋1hH1K&ƒiÌ ZrQD"oiÞ-«¥ûßûP¡Œ_ùON%ãákדf2›zïþémo=wþ\7ô‹n…„×^÷¸ªmC ÎUì(-³%Ê*¤iêv:+¹<ôÀ‰ý½ý¶ª *ïSNm;DZ†‡Nœ˜ïͯ=~;Û C·Zc¾òÉOÞ9´uæSgÆ8<|úáqìJNC«åª °³¾ª›¦%¢Ó§ÉýÊÖU5TM½ì–“¦EbEu•¯ë& áäC'ú®ßÚØ¾þÚëo¼ñÆ[nºÉ nmΘèâÞÅSœ»NsÑ”jç‘)ç,1‘AÇ–³ˆ":ërÎ j‰‘€׳ɻ~Õ-WÝj¥¢Ö¸0öiŒ Þ»ªÚÚšŠ¦Tr\-°¿·Cfã­³d Pc ‹…‹l8 ã0Df‘¾T £Y*¥¡PrV„ÂÅW¦2N£æ>˜”£.æ’¢ek™Ú´)­‚€bÉ:BêœF²$µ@ †üÔRÒЄkki«F4¾—ûËÅnêÆ£D–ˆšD ½Á£°º‰÷o+ãk;ٚͶ6pww÷’shÛö+¾â+º®û\>Q¶¶¶nºé¦ù|þÀ\ÉÐÍcíŒyâŸh­ýèG?z…ãWÎ 7ÜpäÈ‘³gÏ>üðÃÿÕs½÷ë¤ýèGSJÿ…ÏW'ÑÚ¿è}÷Ý÷é«¿ÌV¯N""ºå–[š¦9uêÔ—Ò1Ò¯ÜétzË-· Ãpß}÷}¶ª_Ö}YZá‹zpÀð¹øØÇ>¶Þø×÷ÜûÙ©_û¬ÿ{½±vÖøk¿ök÷ïŸb"VðB”dkcc¶±1HztïâAR3Ì&Ƹó*ŒD­ê ïF-áÚc[_õ”›ŸüÄë¶gu†‡xøþ?ùï'>õȧöúØpåmŒ)å< £1vc¶qõ×îln°hún>¿xîQI)uU³µ}Øûöäç}ôÂþþrÙuã86mÓμ5¨s ²9›nooÚ9´?_üû‰‡Nž9JnÛ‰¯\)E¥ÔÞMÚ6…$%ýsrM½}ô¨mÛUçã$ÅvVO¦ "Êz!›@ǾµÈt2mëVŠô«ArñÎ[c‘ªÚû¶2Ö´u³¹±±³³³1›u«ÕéS<|òäb¾@DH)…rÉÌlŒ) c‡8Zg+ï@RödšªšÔuSUÖÚ0ÄýùåØÑ#Ói{øÐöOxüöÎÆé3§?ðÁ¼óÝïºÿ㿸¿?„Ðõ=O¼«¤èÙ3æ8ÖÓI»¹ÑLš¶m7fUíëªvÎÀþÅý‡?{êÌroŽB¹P.j\½±µsèÈ‘CGO6&lØX iìúUŒÁZ»±±Y×H©¶GŽílìTàÆ„ËbFrŠlŠ€FšŸ[ÎÏìùb—çsŸã”¡R´b7«cž_ìq f´“Toûïvn»•¡)Ù–LT¢”!™ ”!` ©[®–{«n†e.ƒH͹Ä"I@Ða*‘´[Íd»mf~2­¶wf–É|Fß×uÝûÞ÷¾Ët{{{ë°„ÿ%rÎë1–/'Ož_öOºñÚí©™Îf‡¶¹ Eöæ¢j¬%ñ””KÈrc®ªZT˜‰QÇ\º®C2„USÏ6·wBpM³?›F)XŠ„a‡¹¬r`£Æ!†›frͱãu3Ù_®æËnw/ #ˆ*¨ª¢3™œõÔ°+ C…šŠŠÍJ@†"+kIe5†~1WUgLåùI·lÌfÆ0sõ„oœL§‡Žn&íç‰)¥’‹…¯\× 1}è “q,ƒ@Š)§T9wìèÑIݶUƒ 1Æ#€cÑ8C†’äO>øïçÎ=zóMOxܵ×>rxs6aèΞýÔÞÞÞ8Ž9g=[ç*o­#ä8Ö9ëL34mÓ´M;iÚi[×Þ:—cÞßßß=¿Û« !,æó‹çw/nížnj_ùÃÛ;ÎoŒH†nµZ„qT‘a.îíwýè|UÕ ƒÂlc*Ö[ca *1Æ*X6¨ªBÆ8¨ÉXÛLê¦iŒ1C”B.™˜­ó‘ñuS;g “Y7èÚs)…ÙˆhN9¥\ °1 ë(® ˆ(L HŒ ¦veVç®—Ñè¨""³8­ ϼE@‚Ô¥EžŸM\ñD­¦ªX.ª38PaETµ¦ª!¶ÔL‡ÊÓ"QUKÎ1¦1æ`+B×Ðt«žl9ßrUóÖ´’¾7ûpÀpÀÿ( µÆxâ 9Y®ºPò8„”ˆ)óˆªÙ2x¶È Bމ‘³R.pq?ÅBh붪*k½÷µHQT-R$ç‚„ÄdÙ²a( ŠˆÖDfELR´ ©œ/U–2Ž!Q6ÖXS9o=C¢ª9EY{~2FW«¾®ç¼aƒŠ"B*%¦EÀ:cÍ%ŽãÐ÷=²advÎ{f–}7Æ‹eŠÉcXTµd¢”EEס; UÌ1¥”ÑYkŒEÄS(Ä̆‰xÂ\ÕMÛ4“¶ÝØØ8~ì¸ó¶[u{ó‹Ì˜SG*ÄÆZ‡9)BD €Æ˜ÊWýª{ßûÞK€Ó¦ù¿¾ê©³É¬3×_û8XGÿþØ}€`­ÝßßfkÕ°ñÖ`Ã0RÊØ÷Ù×¶©kï\Û´Uß/VýjÑR4—(»{»§yøÐ¡­pÍ5l¨:"˜M§‡©ªvµÊEÙ Š!¡‚wÿ{wò[[–¥‡}5»;ç6ì_Mfdd©Ê² ¨Ë2`A(ØëõÌólX³‚% ’ª¤’T™/â½ÇÇævçœÝ­µ<¸‘ ž ˆÁýœ\×Y{_pÑ )«q³Ýl®6ãzˆ1NÇyžN§c«Åçˆ{k‡ýΚ !¡X^Ddï6ÛUJÃõÍÝ»w_æZÒ0<ïv§é³ Ò¹Ò±wÎ;çRJØb 1éU›,ó2§¼”ÚuLBÎûw9Å’ Î’óEOjdÀçâ.½JÓn"µÖ*Ò¥‹©9bB¦sG¦Im-gCvÀäÙv+fâ<ŽÛh}eµ@)¥õ¼(©2j'gÉ¡wH ŠÒ–£.ˆ‰ÉQÇ8 8`ç{¢MѨ\1 $ójHÁ1€Jg60«w‚0ƒ¹×co§ =,õ3çÿòÿûçïÒäwqqqqqqqñ_^èb"¹Ö²„ãœÛóî°Ì1Ñ>Â8ZmÖ­y‡É¹Í:ÕN/Çb]‹aËür:eÑJðîöŠˆ_Ý]#h‡÷Ÿžö§YpÎ{çœ'‡”[Ý?{.žøf³7«Z³ªA†ûWoÙû$]ó’ó<=ö’sG4C3Âççç>~ûí··W×WëÍvÊ2yÇ)FdìÚÔ¤kkSÑÂèW­ÕÇçÇ8ŽÃfM¢}ɺLNÅɱ;·NHÞ™¨ŠˆåRœÓ&­k‡'8¥!1sǾß>|øðgöó›»ýnÿñãǧ§'3UÕó9RbrÞ!×Þzk̃÷Ž ›ôã2!àv5«ddÚ—b]¥7B`hØ»‰ÉùPkëŠj€ ­VB—ÒÈ@*&M[É­4éuY%΋œŽ¹öFŽwÞf#Uí%çR:BêÒEŒ‰©JUUÇ@މˆÙ! ;db­õŽÐ,€!yBîµ/03áj5¢ÁõÕupN¤Ô¼äSðež[ÉÒ*©h)­µvµÞp@Ö«Ír8ý«¿ù›r8͇ãÿô?þ‚GÄ!¸/ßÞלó¼Dïv‡“ô&Ò\p]z5ñ>0ò¼ä—ÝË~ÿ"­Ÿv‡Ûëë7¯ß^_ÝŒÃjHIM{@3DŽ®Z2éíwßý~·{úûÿ·ïÞ¾N)¦˜‡¼}óæþŸ^ö‡Si]:ôíöš}rãfµ¾Úl6kçÜ´L§ù8¦ãé0ç…SLØ¡”<)s‰>‚šš¹ªÊj=”:¦cÓ›·ïÒj5¬Ÿö‡ãõõõj-fã°Z­Ó0ÆcÆa†¼kWê,¥ç.ÕTútœB¼ž<“ÑiZÇãét"Äq\…‚Ùy&BŒ!F&ž¦c©Y¥ÕRjùù;2BÐ*u΋g¶رçžÈ X“*Hê#†(XG™jƒEÈ{“ˆB(dÐ6DÝ’‡IË“èL)"¢U½t–fÕn„ $€dJ`ÚÅr ¸ƒÔ™¤`Í('“ë2Bõ&ƒÒeÏyqqqqqqqñKñúú:×r˜¦S9é]™Çq]êD“ÖÚ¬’FóÄ”xHˆ‘È;o2ºÜó$Uaµ¾rÉ—þÝû‡M_¯7w«ÕíõuZmjÇ/UÍ€ÄLÁÒ0ÞÞÞI)Ï¥æ9Ó_©5·V~üøáæûï˜âf³ùöÛoU@´?>¶Þ«™©*zï—%??ï¾ü¢ 1¬RÜŒãé ‘È“4ì½Î¹¡w~Âv»:ͳöVó<®†UJ×›íT³6gR{±EM[k)Evüÿb‹¨ˆ,y>qŒÑÀ|ðÂω¬§yyÙ½¤ÆqÇq·Û©"'ä?¾™™™‚ €#—bíìY¤·Þ›ó´Z­¶1¸àã4祔Ҥ5h½ÕÞ—ZÁ;VU•fç8Ÿi^˜£6L1­ÆÍêvÕZŸOÓ~¿Û^æSfO¥ôÖQÕ¡9UÎY¦eŸ†Á{'¢­‰t@fU¬]Ki¥–4`ðqFDdb&§ªÌBĽwUE"&‚!‘sjŠD†H„CHLžY—Ón÷üøùj»º¹Ú¾{sw:¿ÿþû7?|:µu-R{kË<×yAÑ!DF\Ça¼öï¿ÿá_ýËYs.óòWÿì¯67bä»›Ûü§6Žã?}0é&ò²ßuP5…Þ¥µVrÉó’ç%OÓÊ´¤a$çkk­+:cäàJ¯Á± ®çüüò¤Rj›‡8¼}ó6ÅáËw+vA WãÇÏO»R{®å£Iç€ìyÜŒëëMZ¥¹.»—ÃišJÎsž-)8W[é­öÖ `š¦çýÞÅÈÁæSŒcºº¹»º½yzzš–Å|ˆä¬7E$v>Ääc@D0µRrÉ !¥jìh.x9È|εÚn¯¼÷óéô²þñÓû§Ï-7çÂÆõúzµÚ†´ò€¢]IávÕj9?ÙÑ&Ú¬‹—bªÉgÌÀ%ö‰»Óš <(A3#å€>ÕÞ"ªA­m媯VQ&êк….ˆC ¤ÞØaïÝT:tDaVÔÆP I>¨æS°¬RŸQ‡-‘°)w¸Ìœ¿_¼º_Jñ.Ôý®œ‹L?®Ó:K#˜$rè#SBcG€QÇÃ,Žˆb æÒ¾ûñÁ^ýÙ·¯®6d:ÑvŽDÁQ ¯®¯ï^½jK®KAHãæúº·öüüðüòòŸÿázƒo¿ùí8Œ_~ùek Z/òð¹‰6U ¬¥"B)YDcLÞ5M)•RZk1Ä”†2×?}h¹¥˜J®ˆDç• sŽ˜ˆHU¥wi­×fN{÷"¾ö.*]Eµ‹´õzMžÉU‡ˆpžPÍ‘|0ç„A­­×*Ò[U€c^ÊzµYo®îïß0»Óqb‘ݸZŸ¦c)ʉÑyïc„Ò‹ˆ©ªžÿÁ4U³j¥ôRz-§q¥ÞyfGˆÐºÔR‰é|Úˆ} 1šêùê‘#ßKéαTê%ÿ¡ÕòúÍ«¯¾ú"8Ÿbt„戌Ézïµ,Ó)O‹#nëŠ c6« ˆÌW×OŸ?ÿûû·Vú—÷oÿë?ÿo†õœ»Ùnƒ j&Ò{cçŽËi*³š )Éjí‰<ÀjÆ1ãb…ÖjmâÉ|\­®¶¸LÖZë½¶b½K¯f²ÆàüõõmJ#3¨Úù˜+½kµÖ*DÈÌ!„aÒ0T­"½õšËÒz )\o®¸Sƒîv"ršg|y´ýtVi{½Ù^ooï_yïº23ô.ªbÆb&ª1Æ”RÁ¤ûÃ~9—œs«É¥˜bˆ)¤"!-KÙï÷§ãÔ›ä’u.µt3f\HDD̈ *DDÞyÇÔZ€Þ¥7©Ò¨2¸XYÀ@ѱ/‘@z(F¿½Z·WENÖpZ–¥êAs“å*1S%¬02³éT²Ôc`’¥Š9ÀP̘S€!qëµKFìž,°4âæ|ƒºÔÓæ“GP}ËÔs„žZïý2s^\\\\\\\ürl6ëÕfÁOfûRsïb×+È6®¹iï³j–Ò5³®7Ãõzsw·A»eúiwš*Y¡b½4¨ªó4q IDATÇÒòñ»T[þâõoÖãj^úœ—ÒZS0ø¬Oƒ-çýþpšæä‚ŸANóépxþþý¹Ô”Ò›ûw1¹7o^õVާ—R¦Ót÷†Óy‰‹fhlZnL‚7χÝþ÷µ|øéý§Ÿ~º¹½i­îž_¦ã £ h8Ï ò˜S;žŽëqõêænÇÃj||°ýn÷»ø‡¿þë¿fæßþ£?Yo7)çè[Çc v1Oöüy*S+µ·F1zPy3Žãf³^¯×ÞÇ\*MˆÎ9D¬µôÖ¦ýa™OR ƒi÷Þ¡'~Þ=àv«# rˆ1^߸†Ö;~~,@ ¦]¤µF…NÇÓþewœNµ4Çñöö­©uÓ¦ lLÝtÊ‹íqiy,EG.xCPÆ0Ž«ÍZŠÌ@ˆŽ¬öSB¢Þ¥äùááñååi½Z™‚ª²ãaXm·Áû¢'S©µÎӜ祵FÈì{—ÞÅLÍ@ÅT- €:&DBCiµÖ\«H'0ÇÒTÔ ´;n1:AŒÏXȱK£k Í‹‰”ˆÁ£‚ †È Л,,A ¶^0ûA{VÊ€Å`© W«M–yÉG€ÊÞØ Beè‘Í[^œ’Hu­poƒÃ Es®àe漸¸¸¸¸¸¸øÅ)ºÄù7àûÓs®GCF&C ÑY«ž]A[zÉM×qS _¿{»½Z=Ÿvãç' ;{Y–©V1¡X;žžÿõô]ÙMo_ߣ¨x‡ ½æR‹™RŽZÞkÍÇÝór:%î®îçû¢ó~$>NûÖêÛ7oÆqØ®·×·+ƒ7Ÿß»ÝáœK©½/‹öN“¶O/°¼yµVs.ä©5iÒCðH\›äe©¥ôRê¼è¦šÙù¡* :ï™=A7Uì(h¨`ª­63°Óþ€€Î9ëbÀçêN‘>•Š„1"ŒÑDª¨fç…'ƒÎ"µ7ì¤`Z{'$œó’—%²'Àè¼ù(Ü º5U+à™Q{…Þ€Ø"#Wë"*]N8====>~~÷EˆÑ­WãqæÃAJSéì½CRS5C3cçˆÐTŒ…À3;fe01•Þ;""ž“{Í@UŒ‘.‚L眉…Õ5‘n jf˜ól"ÏOÏ××רžŸöyiÎù@Ä¢†XܸZâáx áùí›71xp Œ]åi÷ü7ÿçßÜÞÝ*èoþä·Ûë­ó¼Ù¬¼ç}Pc1n‚¥¶RËÒfHÁ£éÅ¥àƒçèÈ“¢*;ÇÌ^»v‡%çýî%ÏšDÏ­Õ*Ú§éÄÌÈD«¿½¿ ÃÓp>~pžC λÖÚ´L‡ý¡ÕŠˆÑ‡! !mRZ]¡ €!s`ç]à°hkSãgúðx Õäáés‘:lVœKq™ ¡ãàÒj@GÄ®I;ž¦Ýá°;T,ÄÈÎyÆ1¥´2b)&ª½I­½5pÀˆL@àãà¼32#3é ¥ë¹¨V´•%‹H­½ ÅuŽÍ1#`­u™£ „¨ÂDÈOèO@UÓbh‚a4fLÁˆ- ¸ÀèÀ Ï"¸²Ý ÖŠ ä½ˆ‡ª×±uj BwjÜ:XcϘ‚x ¦N…‰}`ï˜Ø+[p|™9/.......~)xôiX‰OoÂæ°È4«š@Ñåj5ÌÏófsàס³–^£÷_Üß¿¾¿Þ^mÿáq>é”™BD ‚òùå°qSïh®çÝRJ]¦¶tí>ø!…áø|èuÊó¼Ló,óOéÓ&Ý_]_st!¸œv‡ÝÃã‡×¯ïnn7ë8:Gï¾|·äeš Bx~Ùާ¥v+5]ªîŽKkuiÇî[7›‹l&Æçm^ëškuĦÒzžf !L¦ÚZw!ˆ˜)ð°¢*Rªe‘¥#“CvÞ‘©¦”æÓ1ù˜Ø;<(þœ:÷Ï»Gçèp8>½<»äïo®oE_ž_–\7«õëׯ¥w‡¼Ô9çÖEÓ´2Øl6qˆäYÀ µÖÕTz6$öÖT»«‰zï6Û”ÖÁD‰Ù©X+ÝĤ˲,ιÖZnJµÍ:Ê8&DW[ŸæB!²ZÆÆæFŸüv»Áã:Çë!”©„Úª‡£º†”ˆÀ’sȌҋ™®<Z©ÙAo¨ÍÔD}5èëÄqëÙ"híhÊÝ‘‘;Q3 7xïžZ75¼Ìœ¿ ¬Fáþùù¥.Εë]\ŒÛ×_}ýøé±•c`ïž`·ƒ?œNsÉW7[x|˜»ýóÃþ¥´ £¿Zo®®â¶~þIÀª0³J·yZûÓqß&ɽçÖh`O^›ZW0"&ç‘ï<ˆÔ¼”jÌì=çÖò2ãHL!zDZ¯×ÞûÕj¬µÇÆ´:5/ËþépØu}KôvcäõÓÃîÃOÏo^/Œƒ*Œãú·ò_±¶Û»Þ¿ÿéÇϟwÇÝñt¨uÅàqˆ‘ƒGïæ<‹)˜™ˆ˜˜‰:bˆiH£ŠªH¯UDJ)]dp,êAÑ{bì"*‚Ìœ"‹@®u0ÂÚ[S&0KΩXmÕÕ±Õr~5ïÝ0ÄÛÛÛœDšNsÎmž¦ÞÅ{ÿó@HDNUL Á÷Ö´5†Žbô£)4=O=Þ…:ÕiYŽÓ”kUSD<µVA0xúüøw]z)ËéäÉ9ÖÛë»Ö§eZj>ÍÓ<Ätµ]/65ÏÐk3í¨†ÁLUû1F P0@F`TU:;A5Õs*/ **©šŠ™™)zÏìñçÂSCP01C#FŠ>†à ͉È<ÏÒ{WmªM œûðù±´Ȫ°?ÿâ/þâíÛûÚï^m¿ýí—ÇÓãøx:Ìy®­ô®µêõê1MË<Í Ž+"†aÈA)MU ™MZoµ5õ10±!í‡ã< PH«¹Ô.òþýûç—§i>õÞ¤wéÒjÕ.LaˆŽƒw&°Ì¹7U"NÃà|@$6†( jØÅ”|£Vk+­»S ª¡¨bï×ãxµÙ®‡pØïö%kïѹÕ8ˆ ÆÉ;C`ÇÈc‘©ÕCZ¯¶Ë<×¥˜adö)ÞÝßßßßsð­w1í­ 1¡t‘Ú*s©µÔZZ—\Šø«›ëqÜl¶cˆŒ¬`Pk_–r•ÖÃÒbrªÍ‡Òj½¹&pš¤ï¥õ®Ò %Fç牛ءÎÐE¯ª@¼GRAP"GèZV"@dDÄsw«€©5iŒˆ &Ð¥wDD¹Ïyqqqqqqqñ‹ÑErÎ5wé„&]µ{öC ¥æi™WÛ¹p8Í»Ýjׇç—!ù!Òn÷ùãÓçç—ƒu[¥âbÁyäDA—¥ä>Œ«Íú:ø5jÛ1§èƒH—VÇ®×÷1zB®YÏåð2=|x(óru½‰Ñ÷ŠßÿáÃzuûë_ã8® Šóñþí[ô~Ü®‡Õ¢ Ÿ ûÖĹèBHÁsð4¹¥,]:™„Ì ÍÀûp}u­¢Ë²Ì"j¢]ö/;òÎïbˆ)1 †ZkÄÌÞ÷Þk­€èBð„棗.ÈÀÍ ÀˆHÍÄL‘h½^¿zuwssûüüòùá©”'èÂìTEÅÔŒ<¢¢€¡c¨äeð кèñ43øÍ0¹n%צÐcò<;§j½ 4 <Ž9g0sÎyçMa÷òòýw߃ÂÍö †q¸±Ûl—’_ö;UKìMô\¾Ñ–Z[fàóÓ}ôF‡„]»ª˜Ù9t˜Ÿ™Ù9þÀMAAàœ¨¤j­55¡ŽDì½&cJi`v*Zkm­ôÞ ˆPDBÁ;ç#ûÖò’íåùöÕ+ þ»ßÿîûï>><üóþ?ßÝÝú€ë«ø«_¿-uz÷ÅýËóËûÞÿôáÃ4-§ãR“cjUzU]ðŽØÐ%ô  ­Wd&"`&3TSëbÎ;d_{{ÙNK-]^½ÿ˜÷‡ÃËË ;v޼©½_KV2Ò®µÕ–»™ú<óùæp;¶¦Ò‰hñÁ{ßMEÕ-Ërš½÷!Ä”Òê&m7[3SµÂjjp’3J­½KJÑ9°äl`ì¶ëÕ*¥TrñÞ¯VëãRÍu>Í¥Vù¹]‡T•‰Iº"¢8"Cë?ÿȈ‰Ù1™ˆGÁ³ˆs—â<\ŧ©¨ZkR«GÒ֌ɯV›äll‰yÙÍ3«t`Ï‚†ˆ†hdf]€€˜19ÀÊÀ„†¨†h„`¦¦Ò;°GrŽˆÁ¤w­µhŒî2s^\\\\\\\üR<><ÜܼBôçÄÒà{Z iÞ¬?<=ÞÞÜ¥q5/µ×NÄÍäñpO)ÐtÚçbÀC G烩€„ÐM;!o×ÛëÛké–ücž`žJ¯ub ðY‡Û›«ë«ëèÇÏw¿ûO?¼ÿîÃû?üô˜Ò·ò-CúôqÏü{úêW_ë­¬¯6aˆÃ*­×Ãv;üþ÷Þ¬ö:/¹uíJÇWƒ‹ž‡i:€½ôNçKtÎiSGd­™iU]ŽGŸâööfˆ1xOD)%Sm­ÎäÎá·`ìØ3‚¡×jµ2#ÇL¥Z)åùéùñññ믿º¿¿!Ö"‡ÃŒ?Ÿ35PD FǤ2!™Z«:z‡µÍÕQö.€";C9¯ÎȇàˆÙQE€œsoÍT:8Ÿ>Y·ëíµOÃÝ0ÆEûóóS þéé‰=€ó^U´ªŠPoRZS³`ÚbJDÔ{k­ŸGJBP1Q#DvÌ΀ªˆêyÂ'rÒMYM="!š‰J±ÎAôCŒ«õzW„”s)¹ÖZ¥5üãÐ*¢ÃÎû4 F´ê՘ѱ)QëíáÓÃËÿþ¿5éÿä¿û˯¾ù2D¾¹[ÿ¦…ð«ã~ºZ]9ðÔ¹-úüy××Ò´5«VkVip@LÑœ?Ÿf©µ±‹’CFš–åãçSž}𢪦ÉÇŸ;qˆL úâÌ”JÎ€Š DŒÄn1¯¦µ.¥ehÍ3»&­d ÖÚ EÄ»»»W7wÑ…4$&òÞ1ªŠ;ív§ý®•cYtl„bV{S³âæêº«OÓá8µÖL¬LYDÀ€™UE̺ôR 8•\ЉöÖ¬Ë2Ï˼“óÞyvžàh½ÆÄd)µÔâ£ë T¸U4“®µ‹¦!x?l6è}l­Jmîü(hpËþÔç’›¨,Ð5Sg@ά6cA$$ô€ž‘("àùŒ-± Þ9"‡D̬fª †h¨—™óââââââââ—âûïß›ÑÕöÎDMd3ŽØEDSÜþt “)¸@èzÛçV€•}\_¹Áº²Ò`HÚ{·9«’ôh:ëûû×_}õEkfÂ|<íO§Ãa»z³Y­óÒTtÒo~óÍëû·ï¿û€†Ëq9=Ÿž»ë«}S«úùó‹‹?‚W¯î¡G¢¿¹½’_­Ckó~÷¸Û=µVΕÄcD¢Þ{ιu!##$BttN—µ1 m(­·Z2,óœÖ«AG€õzB8ó<÷ÞÄTÀ€D¤õŽªŽ™ÌPD‰Ì9603«µ©ÉÃÃÃííÍÍÍ ÓítʧÓ2¦RZ-*bFLŒ†¦h¦Mä¼͵¡Šq7Ë­"yï@z·Ú›ÔzÞ+Š1!mÖëàýä\^Scf眈œN“÷{çÂjµ~óæí«»[Sýøñ#š¡B)ÙÀœw¢*±aQLªœ/U¤ 3K—Ö; ¡ö."BDHtÞ|"€ý±C%°ªš€õÞÎ 4ÆŸ/L²ó!ÆaPU‰ù|­” ÌÔz—R«/ÁÅB6[Ñ6•²;VÃV«?üá÷/ÿëËÃãÃ?ýgÿý7ß~=Žã»w÷ÑË©:óÃʯÂi7õ¥W©U‹hSR?`ZGdtCòˆ‚sìªVr5UvÑ Ùy—Vk$ Ïbœcç\>…aHÉ‘ïE&šzíà1h—N@ˆ@£s¬i·^´å@àÅL͈˜U´«©a­­µ †«aÅįî¶×›õíÍu áz½²Ö´·÷fÇeî­* *9FæRÉùx:ŽG…&ó4@JÉ9'`=‚€‰HΙ=³’ë½Íóú¸ Ã:-‡)¦2•ÖºSd1§È u„Á9Çl*½Š§€ˆˆ`pn 2bfïœ÷þ|Êà¿_ŒÐáÒæËÌyqqqqqqqñKñÓ?zö`î\cxusÇXۜۉ‡¡Hÿôôy ëÞû(rhÝÜà óñêöz »MÇrš[Õš;j­ÕD|ôÃ8Ü\_½}ó¦ÔvØí×ë„&§ý¾^_ÅäY¦Ót{s»Y_½ûâ]+u™–Óó<¿,?|ÿÓ§·¯n]ô¹Ô~ü0·æÇøæÍ««íÚ;òž¶7ðãO?lÖc a NÔ¬‹x"fç ¹7QëÀĦ ¦ Ì.„Èì ½o­åeŽC¢à¢Yá¼;µCæ&âz't‘ÈÄìIÄì|0ÒLTj­–RªµžN§Þe†ÛÛ›iZ˜x¿?–\zk Áƒš‰j—®"Ú¥ !ÎKUGìSÆÜ›'NÉH©Ë’K)Ù È!€‚¶!%ïü0 Œ¤"Á§óJµ”ò²{…oVë/¿úò7ßü¦×ϧ©Lååå)çl¥+(!¥œ$Roç!S308‡õ&f]DÔÌ1‹œÓŽá×9Bè]zïfjfDBpÎÇ –z^»Ou":çR´·ŸoJW„R«žNŠÌÁ ÅЋîç‰_žn]]õßüí¿}9<æ—ÿáŸþ“?ÿó?ÿö«ß8ù›¯¿^ùÕ&n¥éáeÿ²©-[—š{Ç>@ÆØj퀆 ä)¦ÈäSÒ.C0@v&ö“cO>8ï<ïon®n®nÇeÊOøÜ‹N¨"9ÏÓì¥×®µ—¢ÍºÖ^ £ÆàUU ˆ88G¹Jk‚äI‡ã?¼¯¥ôZ£çwoîß½}swsó|}5ø˜BD¢øî½f3pÎ¥Ój\­×!Æyžs©­5Fì½åeaf¨L†<11 ª¶Ö‚÷)Äà}˹µÚ[£õŠ«½×Zò²0á2ÁqW­µôÖUíx˜ÏPâØ£«4—Bd@Ê|`$ÒÝà80'ÇÉ-û¹–RšJwÉPÙÌŒ°›€ˆDbD 8ô€*˜ž±{°‹#"°cyj—=çÅÅÅÅÅÅÅÅ/Æéxzÿý9÷›ë·_¼{ws{›†pZvO/½öV¥í÷‡§µ_AÇÃáT¤¥äTlðéöË_ÝŒ£ÍíCûñùñÓqª|!^r *~»)%—’ÕZ¶ÝÆû»õÃ&|úéñÓÇOÛív:´RÚî)ï^æÞúj»úòë·íØú©JmOûÝËËÓ°^§å¥~ÿÓûŸ~üö·¿þ曯ïïon®67×[v¸ZWÛÍz5,e®]å8MK©P[b0ÌsqÎVT`¦ÔZ-½µs­ˆjYò|šÈ»0ó<“ãa†a˜ŽGæÒª—´Z¯| jº²ÖØÐ Ù9EP0#4Ã&2çåÇŸ~"â»ÛW¥ôÞ{)E¤{ï|p½75øc/(˜™‰ 0 ¢C#­Òºª8ïÑ «Ñ9„ÞÅBÞûs~l©õáã§!`ôa³Ù0sïÝkëOw¯Þ¤4¾º{¥½—ižöG)º|ΧyiÒ:(8sÈÎâ9–Ö1;rÀαšgû 1Å”RðÞ;ODf¦zn$A"fçDLÕTU‰ˆ™=±‘E­wi"sÎf@Èf0®ÖW›ÖZ—e^æÜº‚í¥‹ ‡!6é»ýžÐn¯orkŸžž,Ž«›ÛÛÃñøü‹ñ²4€_¿û†ˆ áöv»‡x<ì¦ÃËþCS¨œ93o!…RÛþt(Ë‚ffÖ›x®6¶^o}J‰óÞ LM˜j«¤è<;çˆ0z¿Ww77«aSJâ*ºažmÒ{Ï!ïjÍÓ´_Ê©÷,ÚÌ$Œ¼Ù LкŠqô~¤Ü:’ï]KíP[[JÉ%×VD;‘Åîïî†c ¥æçà -Î9†4Žq¥ëãããóãÓËËKžæäƒ#^¯6Ž]HA@çZj­Óª«Í »´½^_]_m¶©è4ÍÇÓþЋõ´ ƒ'¿4÷ej§ T4 ºnÌæ˜\ðà¼$gB0S1T5m½ŸŸY™štU#Gçhà‹‹‹‹‹‹‹‹‹ÿ¢þ˜jóÿzåÿûi·ýáPš~ýÕŸüö·btJ]…d¿{ÿ=‘s>hÅyÉZº©{@gΟjûñÓcúêë›qss{Ÿga7Í][^òt@ªÚj9M‡Rç«íxÿjóë_¿9îwóq~~|ªY]Š7¦ñùù8Ïåêf½ÃbÔmˆþ»?|x|Ü÷ÆD›õ?üáwà‹/ï×ëa½Ï©&ã8n6Û"J)ež38ç˜Ù;c,¥ `)­·ÆD«Õ¨¦óœ§ÓÔ{wÌ%g‹îÜÅØZ+9?==ù˜yX>F˜g3›§IÀÐsB&jµjíjÿw{oÒdI–Ý÷éÞëîoˆ)3++k誮îEB¤Q”IäF…³ož€ IDAT “ÁDŠÆ­Vø4X‹62™–’™¤LÃ’¨À¦šl¢'tWWfVFfLoðáç-^6HP0îj¿E˜G˜/Þs¿îÇï¹ÿŸ£PD$o­@)ešŽH^s6Õ¼”ºRª™õ}w¾Ý®ú4Í“A2Sv”ÑK©Ãz‚˜jÕÖ–ÊÌC¨´Ù\v]œæ1—ÒZk­¥”±µVKqóeYj)µT©Uû¾'"af$Úo®¯?|þáfè׫õÇ}ŒÍŽ»Ýrœj©­©75oj ÝÝÁÁ XB$t@7³¦*AÞW¹DDà§Î“תpZîÊAøêéÓýÃÃR*ŽÓÒv½z~~ÑŰÛÝßÞßü£üƒÍöò‹oüÊw>ÿvê"’ûåÅæ;ßú¬Ô鸖:zÖ‚@)¬\3úˆÄ]œ—œó8NË\ÓÒë ‰ƒ « ¢„(§%ƒig2jm¿øÅ—û‡ÃáaÿáóηWOŸ>íâêúõ›woßµRÉfµ‘³Í´êŽÇ8Îûœ'³:tqµRšz.Ú”$ÄŽCÃÒšƒCì;"ŠAÔm<¼ywú°ºm†M×¥Íf½Z­ú.9£ Œ+1ÆõÅæp8¨ÚiÓJM¸yÓY›kÖÚÉ*¥Ôu]HÉÝ ‘‰SŒy^ò¼äe‘˜YUÓø°{»(xuyžR Kn¹LË’Ã4d$#30µÐÐË\vû¢s·Iq8ßP9Nã~œmjªîLCGeª­™#1‚8°£pì;ÉóähÀ§v$³f€æpJŠv@FF–€Z­UmîÀB<òÈ#<òÈ#þ\]^ÞÜÞþ‹¹¼¸ø3v»zRKàRjŒñòâ æ»Ã4M»Ý.{0GkæUÑ0¥¾Õº”5Fäæt˜JÓ(<ûàØö¯Þ¾óÚ@ˆšji•Ø»ŽDôêéjš®îoŸÜß<2¹vZüþvùé_®7Ãßø÷þÊóO7¡ïXB@Ñùîþ˜suuo-FVÝj5 C™Ç‡eHýzµI©wÇ\kìÓx¿¯µ¦˜RJ„8ôC qš¦²ÌVryxØ!BmÕÜÍí”yÃÄŒ„H§åm9gVCßõëõz™çåáÁ,†R ‡B`æ X[+¥Zs„šB[¯7!ÆižjkØZÓR^½z½,ål{I$̼ÝnÝ@#öS?mL‚æÞ\‰:"t0@àÀÚª’³Ïy¹»¿‹,ãÓ>˜Æiš§ã413 8šª¸c)íööHˆ)výÀ’8¤Òê?û£,Óø­Ï>¿Üžõ}¿Ýnõßø+›aý£?þ±Þ݈ÈbUR*¦¹¶“‚ÜçqšÜX$¦SB&@@&(­1s£ å’U" ±»±;¼OôÂ÷PfDlµÕV™Dͦe^r©Ú†õCŒùâòr7S+‘‰CLCº„DsÉÛóS5lK-4QIIBw8Ìßÿ'?üýßÿ?Wiý⃱{Ûlã'Ÿ>[Úþvw}XÊ»â€Ýz³,õíÝ}5ëºÅ ;€›Ù’3Ðä@19©HŒç«!¤s>Ž;èW+d:ÓaÜß÷wûûûÝëW×gW<ûð|s©ªÌl,] ëu_ÊWC¨mSÛbZŠ.›³Íj³jfÓ\K¶ªÄ¤ƒ¬æ¹êRûRJAx™Çë›·Í2’#º™>òÁÐ fºÙ¬Ÿ\=¹?ŒÐ™Àñx<æ¼0’ åyV¬«4a5Æ~èÓ L[-ÇšKFf"‹‹³e—yw+%ÓÉŒ Î,,„,è`µdsZ;¨Y«Í3H œ)ÕÀBd$„†ìÎuDiÚ¥N»q|gÀZµÌEAB3ZÔÝÔ½ÕVµUpåÖRŒ}JBÔ›º™3!#;88xní´”XR‡ŒkÎGyä‘Gyä‘?>ÿü³©æüæçŸýw;¿¸8ÆRÚÍÍ»×o^‡S/¥ÕqÇ㾊ºH#r–aH^ëZk›çrùbµó~Õ‡.Ä$$¹‰ZÓR«ª":¡ÆÀ«_^ }ôZWrœF߯»ÛIýkNðô£ígŸ|puµ]ßÜž­0Ñ¢ËÝáaÙK-Î ‘S ÂäÞZ-Ððx<ö‡ýþ0ŽsÎÍ܉TõÑ)RŒªÄ\–RJk•…Üí´DÜÁ‘‚„„‰O³…¹–Ú*ð^¯Ëñh­¹¹5uUN©‹±i…‰ÌÉÀàôˆð4û'ŒˆXkÝï%×e®ëõ6J<;;s«1q˜xš¦y™ÝÍ]1‰QÔ€;(!q`$!R 3—¹ s×1& aGS@pïû¾ÖŠXO³µ©˜#IpV»¹y·ŒÇép„¦_|㳋íù‹/^¼xSš–ÙÝËXÇ#"6pp¯Ë¬­µ€#¸{3m§Z÷ bàBTJq5a @TjQsSJ1F"¤÷,¥¸»;Šp«ÚZ† vûº­úˆs;íàÄBd&æ €…ÜMÁæœÝZ3»Çúýüðòüê/çÛßøø£íj ½Ê§Ÿ¿Xt6VùQxùö­ªå¥åYI¨ëh«­7”1“ ÕVçe®Z—<ÇØ Ì˼ÌË2Í5ëܲ™Óîá—RžÕýaàÛ³Íùv³Y‡Ã=@›çâÎ!ôql§ùaR'Ï¥N¥†b-[E¤$}:…fµŒËòêÍ×÷w7ïÞ}òáÇë~]k;ŒÇÍv×CnuÊ%×ÚšÞ¼{·xXÆ ÜSLdÐJu7‘Ô¥žs ÑZ­¥@«¥ä%¹€#€»"žš ¥Y]–©4ÇÃ8DAµÕ’Í\Ájõœ½Ôˆb$n] æCç €ÄÄÁ:#dp˜×s?vrFÚ€²ÆVÜ ݳ674¯µT€¸™C>¥p:kݙȵ=ú9yä‘Gyä‘Gþü‰!ü;ÿö¯ù‹¯öûýùùù§Ÿ||Ò!þKl¶çjTãøòå«õzsõô‘˜Y8,»©yì)u’RêCˆT«×œ]k.GÙ0*@ƒ-ÏEÕЬYÎåxoïîïî„WL1^\n>ûŒW]¾¹.ïÞŽ‡Ã2ÏMïs|ùõ~üÓ˜`óîü|ÃüüvÿðG?ý±yÍyn¦"1ÅÐjžÆÃq¿'WA:÷o®ß¼zùêæævžˆhj!7!öýp¾=[¯VÓ4E‰¨§VCS@@ D@dÄ“ƒ‰ µ–[m¦ó<ý@ˆ)¥0 eµ”•…Ž„HÈÌŽˆ0MGrÛí®ß]?½ºúôã_|ð¼”âfûÃNÁ®oߎ%«; ‡˜¡µÆnÅÁIDb@B5k~ =RPð%/à¦MM•‘„EBÐî@ÌQ‚: :¸š sêR×'w’<¶€¥æýÁoîR 2.3®Ök "wh¥¹»0;"KŒnÚ\OýÍÒK'œB÷»ã÷¾ÿO¦éXëüÙ§¯W]ä"l¿ÀÏ*h;–òîîÁ ’tNÀ¢P‹õ£#QB )Jw?ŒGwSSs/¥´–Í´µ¦ÍÜÐÕ¬™æZŽãápØÁÙùù“ËËíf%ŒÌZë<Ïû’  Akº,Å™›C.­4˵.%™‚S ‘säúVÈ´=ìö·7ù°?ÜÝ>ô¡s@^m7ëÕæé8Íy^r)»ý¡•æ Rêc\ÆÉTY8Ä€BH,"]מóŒœs­µä\ri¹î–yîúÞÝ‘jk¥ÖfQMsÉóRÇÃ8SìÝ‚‡Àh ÖÜ\›j­†šB(gÍÎÇzbqv$@\ ¹€" =ÊæÐ ]‹£8 !@sË%'³>u!FrôÖJmˆHÈ„ðþêP37h¦5ç#<òÈ#<òÈ_HÙã·¿õÅ¿zŸ³ós Çéþ~ÚŽ÷»Ýúlà ëÍæüâòÝ®ÕÅ”œ{Ùl71&§FÎn \s}ÉÞ0K«¹NK®Km¹šckþîæþç?{ùìé…àGéùå0 ~È—g¸êŒ»¦òp§r¬­>ìǯ^¿yññÓÛ³;ÐÆ((^[1·D0¦¾ë‡nÿ°»}ûöêlSŒ5×ÛÛÛ7oÞ>Üïr.B¢U…&Š7ëí‡Ï?|rùd¿ß__¿i¥•\NÊx‰‚^½´jà,QN3œîÚš»&9K)`Þ¥$¬ú•͹å2©¶ÖNá·ªUÍ(Š ˆ©—V BBä §ÞÔZò.cU1ða½6k É¥Nã\jUk ¦Ú0 #¡;ºcˆ)ö½)Æ¡ëñëëëy>ìw·wßúËé;Ÿ|üÑ8çtþbùðÝîáúön\JiSŠ £0˜ p!æHH‚D !Ô¦ó<ÕÖ$H×w¦¹ä¥ÖênfîŠîl,Ì€ž\]~ó³Ïž=}*L9ÏÈš.¥ÌÓ|t7SXr3®À쀎„Â#RàHb7 €H¨„­Z-µÕ:N˵ß22"¥®»"2ÄeÎãaÜíwKεèÐ%î¡ ‚9ƒÙ2MÍZ+dLC߯W›í6v sÎàNH0ûý~Y–˜’™‘bDs33C0°\—i>Îó‰ˆ<&f‰ÔªÚ©É™JUWÓêZÁ*wc¯QbB"@$" BW$ÖkÐÅ>ïÆº_*gÌêŠM­ª¹™2Òûlg3 4‡jˆ N5UmîÀ5ç#<òÈ#<òÈÿ_Øží£š›ù´,×oßI¢ÕZRêÎÏÎ.ÎZÍ{71]^]v©sDKs­÷ûC] #×Ò&NجVG €aª%×<-s-u=¬Ö}qv¹Y¯VýFhØ®sŒ×Èi\fÅì÷M]H®®.?ý죳ËmÑú°Ûq(„Å r®ˆÄ$MUõÔÜê§0t s4Âf–K>uϲHŒ}`~¸»G¦˜" ¢ –º°šÎÓüæúÍ~2|øüùóçl·gÏ>|>.óÒê\óÝ~7_—Òª¹;B)e¿LÌÌ"…ˆ‰˜ ™$„”RŒRJ)9"€UÕÖqp©µj3bDò““ó¤|ÇqØå¥K×õ)ö)u«õºï: ìŒïÓ€9ˆBBÇÞŽãžä}%ÔªVÖCß­–¹•lÈŒ,èápøGßÿþ××_Ë|õìÆÈÝj8¿¼xöüƒww»ÃqfÄÖš)‰ÄbDGb᥶Rk6·ÓzÕçk®nµ©›a Fû˜º’°Àæbõü£g_|þùÐwÓñxs{þôÉåÙv%B_}õåq<ôÃV±1Ç’#‰%퉃#•ªKY\=3aˆÌZÉî˜sq§¾ïS }·ßåœÍ ÔØQ‡õz»ZÕÚö»iµµB‹±”ÅÐc×…ÎÏÏ//.‘±©ÖZ±ï·›m`9îöµVwGBDŒ1t]—ºÄ"ê¾,Ëw»ýñ8îJ-= æ­êÒ4צˆ()  B™ÊîvŸR¶AÙ£‰3¶”¸ C߯–î0¥Cé[ªæV¦\ª5S DLŒB yÐf èêD8 "¹6…¢æêì!t¿¬9ëqä‘Gyä‘Gù×̒˼Ì»]UŒ©Ÿ–ù0Žýúâìì|.z~k‡‡š—âÃöüLDú>íÇ |Ê!f5 Êê¥doæ¥Õ¬­j­UÍÑñxl¯^=|õÁîÙÕ0n7q»] ý¶Ô:.óÍC7µŽgkïî~ðG?]õ Ìnï¿÷ýúãŸþìþv"L1alNÈÛÕ Ôë²”ei1& ëõz³Ùë,“¹km˜·ÖZih%n7›Vk)Ëœ§Ãt,K)TÐ@ݘµ7‘¾ïãªwa$\rž–%†àî)ÆŽÃ Íãáõõõ«ëë—×׿õ[¿u¶9;;×Íù]×w)…³mßuAͪUmˆBa=¤¾s„ÜŠ™™õÊ»Î6«íz³ˆ€#¡äœK­’bˆ1ô‘"Øa>Ô·¹´¨­6éW¾øÖóçOÏÎ×o†DL÷o®¯—»{Žéa<Æ\c_|ÊKnŠ!B57"Ý0lW뀼LÓÁIܼh눻a•R²¦MúnH’˜èü|ÛTk)]AŽÇ#®Vý¼ÌCì;é1.Ë”kÙöµÖUß}f€.BH©º®‹ýÐ+X?ô«õªKa©eÊË”¢ ÑÔ¥mÓ²SIVͪ5s`Ä"¹ ™O‡ñ¸?€{S3Œ3ϱ™ ™3ñÐugç—çç—g»‡Ý²ÌC×3a­¥”ÂAz8µÖÇýRó\ò´,D”$ä’½©j !D¢®ëbŠ1E©9Æ».DavÀ Ì"]YP½ªÕZ+€©Š6;ÕÀMUµ!xÎó³å 4ô-H.†=„ûØYiTDh膾® wÑ…(…:--mꆤÍÕD@Ab¦àUÑÝ´µV­UwÇ¿ýÛ¿ýg.aä‘Gyä‘Gyä/†iš~ï÷~ïöö¶šÎKžæÌœÒ°áaݯ7CêB^Z}ó²,E«Y¡³ÍfˆÑJ;¦ýa\j¥Ô+QijêäŒÅÀ]ÁP„¹Cëk¦åØ(EYoºí¶«íª·9Ï»Ãîííí´,†„D¦m·ß¿yóîíõnXî“t]:5_p Œ­æû»»ÝÃnÇyÉù}›i1Ó.v¦VKE .õëõz³Ù¤”ˆɉÐY8¥.¥DL†hà†P[›¦©å¬¥@ 1ЏšÕÖZSU3uÀÐG$6wUÓffÞªBJ1uI˜ÝÔÍr.­4pdLÌ"s·q<ŽÓ¼”R‹â€ÈàhާÉIb$D$$rÇRêÉÂÂÂ)D!"7oµÌË’óRk=‰;UÕ\‘…ChM¼µê)Å®ïDxœç×_¿f‘³ó3b>÷»Ý®¶JˆMk­ÅLOËL%†Ø¥®ïRßž 1 ƒ‘ÀŽîînvò[¸"¨Ú4MóýäÃçÏ.ÁU„k3ÕëV=·Ür#‚jÕªâÉ2J§Ø´YkXj-¥´ÚPˆEB PÊR—ÅZqWdÖV¯¯ßînnó’¿õÅ·Ï·—WŸÓøÝ»wÓ<^¿»¾ß?¨{’êÍK­ežQ‚¸¹Ö’—ù8‡2ç¸à‚±ª.9ƒ9'4wìvÓ8!™jˆA‚¼{ûÖ̱iÝn·µæ¯ß¼i­CßÅäfèpw—s^o6Ož>!–\Æéø°{¨µ®7›?ý¤ÕòÕ«¯rYÖ›ÕÙvëàDìŠ#“ÔRîîîú®û›ëùßýÿdw{ý~¼Ç?ùÿùÖ¿¸ùÿ3¶þd³[o¾÷ûÿÃL"I°BIDAT÷èéjÕ 3¹çœ‰ÈUPDq™gSs&w­ ÌܽµêfnÂt<cL!¦¦¶,%Ä(16s@tà(xò°&&B l,í8C©½H/¡ŒÇ<ÿÚoü‡ïïþýÿåýŸÍíôøƒgÏŸ|qy~yqqÙ¯#øÅË_üä~ôòg_å© Ð4Ï‹fNüâ“ç¿ùýƯÿÕsÞ¾÷Ý?øá~tH €xÊñsp3{oWS@`fSs3f:p!˜)3ŸÚ¾À=¦Úþ$DU•‰™YÐÌj«îÀÄ!ššº‰ˆÿò€°6;þÓ'9¹ÜÌyå à?¿‡8¨ù舧¸Ip435s7&Ž1˜AkJDÌ €­ªƒŸ¢.Á½Öâ'ÿ„›™3‘ˆœÔ†µ–ÒÊŸa$"æ€Hªšs&„ØEB<=ã !©œØTÁˆÑ„í½<щ˜0FiÚZ­ˆ€„Z+€ÓéßOH˜ù4GNîà€H'÷œ›9¨™š7sSGˆ"H„p²ž8º #!ºck DNÖÇÖZu0"wW$ ""<8‰OŸû—¢ &¦Sv œb23’;ž¤Ž’Z ÅÈ4 ‹½ xó¢VšgÃ*  NÖúˆÛþ£.¾õù‹O>~™§ã<Žy:–W/ß¾yóvèûO>ùè³Ï>zñâéåEçÚ–Qß^ßýâË—ü󟽽ywùììÓo~Š1h·eª¥ÖÖJÜaDmÇX½yýn¿[Œ)ô= ß ¿¹×Åk«µ K $î,h„¨:5×t1e•ã6¦´T{x8¾|ùõj­}oÏ?Ú«×7o^?÷#8F™sçf¥¥Tup@åàÃ*œŸ 1ò’÷Ìqè·«¡›ŽånÜ! ¡):hmdÐ…()qJ!¬:ÁÌ$„ZsÇV@£ÈÄ\šª»™asÑ j€µÁ²@U ±Õ à}ß!AÑRZnm±2oÕšvëM‰D„Á\ÕZä®ë;s#a B$¡ ’‚$q´y™|™Rê¯./‡¾73Älªî–órʆ (§‡[<9-… …@›¶R±Ki½ZuÃ0#ó²4­@ŒÌŽhæäˆHæ$"(º8YóyÎßûÞ÷W«í¯þê¯ÓÅåeß›íV[ËóRK[jÑæóq2pG ÀÒ…4ôièSêQ«5«%—ã8–e"&j­Ë©Í7„H"‚­–VŠN³9ªy£P—¢µ•˜‘JYBßI Í6ÃjÓõáòÉÓ'WëaÕÅtµ?º»ÖºÀ\–r؇ª¯‡•õë!ö=€×ZKÍ‘¹¶pœ¦w7w!¤Ë³«ËËgC·ùúõÛÄ}”nÕ­¸ÎÇy,e–ÔwnVsÝ?<,óRûAÔ½¯«¾gwu×¢Ùæ9Ek:öm.‚4týЛÍV›GDRõeÉÌ­5mZ‰Ð\YˆH´9± ž^, æ4Î¥ö ¬žk]æe )¬Ö¹¹CˆDÄÄB AbHC•>q¥ ­(9zµ– 8Š37mE(ÈɇËØàÿûz²fezÃŽIEND®B`‚mupen64plus-core-src-2.6.0/tools/m64p_helper_scripts.tar.gz000066400000000000000000000033451464506436200236360ustar00rootroot00000000000000‹4¢Sí[mOã8Þ¯äWÌuù°»"MÓWÝ"¤ ¥°Õµ¥j‹VètBiâ6>’8rØ.â¿ß8-4eÒ…–}ñT"q?ÇÎó$!¨–£³aB}7{oÖc´Z¥"·f­RHËf¹œnѪ…ZùY, ¥b¡VÃóÒÂ(¬ÉŸKbas€7Ñ„³ÇÏ#<Þ„C›µ·C±§½5>À‹ý´·ø D$Ä ó“t²¹O·;h]‰æ±€Dö˜|Oˆè£a8Ì%ù1ccŸä‘Ì/n܃Vg8ätì xWÅBáO½ˆi =êx6wሗœ“ði¾½ŒÝ  <CÄÙ˜Ûàîˆ1‰K›“]˜°;N\ N‡‰ @Ø¡k0séh2GÚ$t á„1°QZ8êœÀ ·}è&CŸ:Т c6: Äqa˜A“í¥?ý™?pÈÞ”…»@(Ös¸ÀÉ‚e(Þ\i»è_¶§ïl!»ÃEà=öa¾-æùâ¶ÞQ˜Û¦ÝòX„!õ°äKêû0$€KÅ(ñwî a;øÜ|:>€Õ9…ÏV¯gu§»ØNx kÉ™¢Ò ò)^£ËíPLdï µ½ú'lní7[ÍÁ© ëasÐiôûpxÜ ºVoЬŸ´¬tOzÝã~Ù'$½À]´Gò`”&޲K„Mýø‘áXÏ(œb²ÇßϾ ˜ô¡œÂOHå,ší³pœF[͇wèB&và’SœL‚-Äé!ßš;Ð ü΃íïG«˜h‡ç>&W_ 4ºsHGèê¡Ïß} Þ¶ P4Í‚n– æœô­ü]´ûâÉEƒ†¶˜fOìp 19Yq± pá‰q`DÂC–…úWÂÎ1{äʬÅD€N4 ýúWÈm·­¿9øwWB†Ú–,îö9ÑF4{®÷gõãv÷¸Óè úÙ‹5{9Gf)g$TwX3W±Ä¥L]'l”ˆtÇ‘îaÝu Ó9&Élwìã¦Z΋9鄜»”ƒAÞ$†&}BÜ‹ñÌBÇcûðƒ}y£§8Ùdì wÜÆël}Rô*Â;[Â’½aëx]#å ò´3,å/ªål+ &ä1ßçyðXF¡tºibrÏ)èј†X/³â»bõ-[H/pÈ7óA¯ßls—¬ÿˆ#b# ép|‚L`û¯g@ØxÛz ‘D§ 2E3“äýLðÜö»èÒ}??Ìío2ÁeÆ3wd®·šõF§ßèC¯a´¸i5¬~cšðÓŒ×q–,stû ñ®³ã/îÉÍrsïfÇô‡ÚÈôÆüØr±8íIœ gG¾îßÞP1Ýn ~¶y[â×}Æ}â¼ø"VíòÔ×éÅWïùÖ™þgû—þymí¢ìù–®±c"Ö§þ—êÿr¹REý_¬”KÅJ­Œõ¦Y«Ö”þß„m\ÿOsí;tÀºÕÿŠÂíeL©¥þ•ú_DSêÿWRÿ+H§:'L-” ¨4§$Îi<fòd&Ðg…ä¡Á(ÚïB<ÚöõEó» }f?M7qåupV“” ÄHðˆ— Så ž¼DX"Ф:þEOÊÉfú}]`ÿ/™%äÿ¦Y*š(Lùþ¯Zª*þ¿ Û8ÿŸçÚÊ\@)¥^s”P `Ñ7¥ÖóþOqù‡¹üÏðÞ«9½É¯÷Í×ü­Ó¯JÎ7`·ïX×ø` ÿ/™f ù¡X*«5³*ù¿YQü#¶qþ?˵ïaŠÿ+þÿ𣠸¿âÿ‹¾ýüßqÓo¸´|vI…ü·ßgiŠƒýl–Ž!Òéu>^íù¯üÿR±PQüo¶qþ—͵×GÅÿÿ{ÍQPüOñ¿Eß~þ§žÿªç¿«=ÿí‘€]¬÷éï-PÏŸcSNá²EÖöx)ÿ/o¾ÿ®¡ ÏËõý÷Flóüÿ&×VgŠÿ+þÿ𣠸¿âÿ‹¾)þÿ þ¯ˆýOü‘öIz_Îï#[x·ÿü»ŒáϾçÖõKÆÏu9°é•„Ànë:Öé.å·Ç ùívoS¸ìêúh¤³ÐŸ(9 L™2eÊ”-µÿŒê@°Pmupen64plus-core-src-2.6.0/tools/osx_build_bundle.sh000077500000000000000000000036301464506436200224700ustar00rootroot00000000000000#!/bin/sh ./m64p_build.sh APP_CONTENTS="./mupen64plus.app/Contents" rm -rf $APP_CONTENTS mkdir -p $APP_CONTENTS/MacOS/ mkdir -p $APP_CONTENTS/Frameworks/ mv test/mupen64plus $APP_CONTENTS/MacOS/ mv test/*.dylib $APP_CONTENTS/Frameworks/ FIX_LIST="-x $APP_CONTENTS/MacOS/mupen64plus \ -x $APP_CONTENTS/Frameworks/libmupen64plus.dylib \ -x $APP_CONTENTS/Frameworks/mupen64plus-audio-sdl.dylib \ -x $APP_CONTENTS/Frameworks/mupen64plus-input-sdl.dylib \ -x $APP_CONTENTS/Frameworks/mupen64plus-rsp-hle.dylib \ -x $APP_CONTENTS/Frameworks/mupen64plus-video-rice.dylib \ -x $APP_CONTENTS/Frameworks/mupen64plus-video-glide64mk2.dylib" dylibbundler -of -b $FIX_LIST -p @executable_path/../Frameworks/ -d $APP_CONTENTS/Frameworks/ mkdir -p $APP_CONTENTS/Resources mv test/*.ini test/*.ttf $APP_CONTENTS/Resources mv test/mupen* $APP_CONTENTS/Resources mv test $APP_CONTENTS/SharedSupport mv $APP_CONTENTS/SharedSupport/m64p_test_rom.v64 ./example.v64 echo './mupen64plus.app/Contents/MacOS/mupen64plus --gfx mupen64plus-video-rice "$@"' > run_rice.sh echo './mupen64plus.app/Contents/MacOS/mupen64plus --gfx mupen64plus-video-glide64mk2 "$@"' > run_glide.sh echo "Note that Mupen64Plus requires an Intel mac and will not run on PPC macs.\nIt also requires OS X 10.9 or later.\n\nThis application can NOT be opened in the Finder by double-clicking.\n To use, launch the terminal, then cd into the directory that contains mupen64plus.app and use a command like :\n\n $ ./run_rice.sh example.v64 # for the Rice video plugin\n $ ./run_glide.sh example.v64 # for the Glide64mk2 video plugin\n\n Note that at this point, the only way to configure Mupen64Plus is to edit the config files in ~/Library/Application Support/Mupen64Plus/\n\n" > Readme.txt chmod +x run_rice.sh run_glide.sh CURDATE=`date +%Y%m%d` zip -r mupen64plus-bundle-osx-$CURDATE.zip mupen64plus.app Readme.txt run_rice.sh run_glide.sh example.v64 mupen64plus-core-src-2.6.0/tools/osx_build_instructions.txt000066400000000000000000000014741464506436200241710ustar00rootroot00000000000000Mupen64plus build under OSX 10.9.5 (Mavericks) with Xcode 6.1.1 1. Install command-line tools through xcode - Xcode --> Preferences... --> Downloads tab --> Components page --> Command Line Tools 2. Install mac ports - download page: http://www.macports.org/install.php - .pkg installer for Mavericks 3. Install Git via macports - command line: "sudo port install git†4. Get m64p_helper_scripts.tar.gz from https://mupen64plus.org/wiki/index.php/CompilingFromGit - unzip into build folder - run "./m64p_get.sh" 5. Install other build dependencies: - sudo port install pkgconfig - sudo port install libpng - edit /opt/local/etc/macports/variants.conf: - add: +no_x11 +quartz - sudo port install libSDL2 - sudo port install freetype - sudo port install boost 6. Run "./m64p_build.sh" mupen64plus-core-src-2.6.0/tools/profiling.txt000066400000000000000000000111441464506436200213410ustar00rootroot00000000000000How to profile R4300 instructions with mupen64plus: Pre-requisites: - either 32-bit (x86) or 64-bit (amd64) Linux system - Lots of memory. It doesn't cause swapping in a machine with 2GB of ram, but it probably would with 1GB - OProfile (http://oprofile.sourceforge.net/) - Mupen64plus source code Procedure: 1. Install OProfile linux tool 2. Build r4300 profile tool with "gcc -o r4300prof r4300prof.c" 3. Build mupen64plus with "make DBGSYM=1 DBG_PROFILE=1" 4. Delete any pre-existing profiling files: "rm instructionaddrs.dat" 5. Clear any residual profiling data in oprofile: "sudo opcontrol --reset" 6. Make profiling run by typing in console: sudo opcontrol --start ; ./mupen64plus --nogui --emumode 2 --audio ./plugins/dummyaudio.so ; sudo opcontrol --stop 7. Exit emulator with Escape key after running for desired time 7. Move data file into tools folder: "mv instructionaddrs.dat tools/" 8. Dump instruction-level profiling data for mupen64plus with oprofile: opreport -d -l ./mupen64plus > ./tools/prof-mupen64-detail.txt 9. Run tool to generate r4300 instruction profile report: cd tools ; ./r4300prof instructionaddrs.dat prof-mupen64-detail.txt Example profile output: Loading instructionaddrs.dat... 283844 r4300 instruction locations read. 247911 non-empty MIPS instructions. Loading prof-mupen64-detail.txt... 118181 lines in sample data file. Found 117905 profile hits. Instruction time (samples): reserved: 00007515 NI: 00000000 J: 00000043 JAL: 00003345 BEQ: 00004498 BNE: 00003424 BLEZ: 00000222 BGTZ: 00000029 ADDI: 00000585 ADDIU: 00017439 SLTI: 00000765 SLTIU: 00000089 ANDI: 00003847 ORI: 00000381 XORI: 00000035 LUI: 00010389 BEQL: 00001873 BNEL: 00002617 BLEZL: 00000013 BGTZL: 00000010 DADDI: 00000000 DADDIU: 00000000 LDL: 00000000 LDR: 00000000 LB: 00002600 LH: 00006653 LW: 00024840 LWL: 00000001 LBU: 00003525 LHU: 00004954 LWU: 00000000 LWR: 00000003 SB: 00003007 SH: 00004133 SW: 00023221 SWL: 00000000 SWR: 00000000 SDL: 00000000 SDR: 00000000 LWC1: 00012405 LDC1: 00001855 LD: 00000815 LL: 00000000 SWC1: 00007671 SDC1: 00001326 SD: 00001233 SC: 00000000 BLTZ: 00000383 BGEZ: 00000331 BLTZL: 00000161 BGEZL: 00000168 BLTZAL: 00000000 BGEZAL: 00000115 BLTZALL: 00000000 BGEZALL: 00000000 SLL: 00003376 SRL: 00000604 SRA: 00000686 SLLV: 00000015 SRLV: 00000039 SRAV: 00000000 JR: 00001358 JALR: 00000004 SYSCALL: 00000000 MFHI: 00000058 MTHI: 00000002 MFLO: 00000277 MTLO: 00000004 DSLLV: 00000000 DSRLV: 00000000 DSRAV: 00000000 MULT: 00000000 MULTU: 00000583 DIV: 00000941 DIVU: 00000000 DMULT: 00000000 DMULTU: 00000000 DDIV: 00000000 DDIVU: 00000000 ADD: 00000170 ADDU: 00001706 SUB: 00000037 SUBU: 00000833 AND: 00000909 OR: 00006360 XOR: 00000079 NOR: 00000004 SLT: 00000925 SLTU: 00001401 DADD: 00000000 DADDU: 00000000 DSUB: 00000000 DSUBU: 00000000 DSLL: 00000000 DSRL: 00000000 DSRA: 00000000 TEQ: 00000000 DSLL32: 00000000 DSRL32: 00000000 DSRA32: 00000000 BC1F: 00000286 BC1T: 00000032 BC1FL: 00000775 BC1TL: 00000077 TLBWI: 00000000 TLBP: 00000000 TLBR: 00000000 TLBWR: 00000000 ERET: 00000036 MFC0: 00000396 MTC0: 00000034 MFC1: 00000929 DMFC1: 00000000 CFC1: 00000141 MTC1: 00003081 DMTC1: 00000000 CTC1: 00000163 f.CVT: 00001113 f.CMP: 00002149 f.ADD: 00001387 f.SUB: 00000947 f.MUL: 00002696 f.DIV: 00000315 f.SQRT: 00000025 f.ABS: 00000000 f.MOV: 00000631 f.NEG: 00000323 f.ROUND: 00000000 f.TRUNC: 00000867 f.CEIL: 00000000 f.FLOOR: 00000000 Special code samples: Regcache flushing: 12371 Jump wrappers: 15520 NOTCOMPILED: 33 block postfix & link samples: 619 Unaccounted samples: 19929 Total accounted instruction samples: 221836 Load: 35.2% (68040) Store: 21.0% (40591) Data move/convert: 03.5% (6829) 32-bit math: 16.0% (30861) 64-bit math: 05.7% (10948) Float Math: 04.5% (8709) Jump: 02.5% (4750) Branch: 07.8% (15014) Exceptions: 00.0% (36) Reserved: 03.9% (7515) Other: 00.0% (0) mupen64plus-core-src-2.6.0/tools/r4300prof.c000066400000000000000000000422561464506436200204220ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - r4300prof.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include /* Global data */ unsigned int instr_samples[132]; char instr_name[][10] = { "reserved", "NI", "J", "JAL", "BEQ", "BNE", "BLEZ", "BGTZ", "ADDI", "ADDIU", "SLTI", "SLTIU", "ANDI", "ORI", "XORI", "LUI", "BEQL", "BNEL", "BLEZL", "BGTZL", "DADDI", "DADDIU", "LDL", "LDR", "LB", "LH", "LW", "LWL", "LBU", "LHU", "LWU", "LWR", "SB", "SH", "SW", "SWL", "SWR", "SDL", "SDR", "LWC1", "LDC1", "LD", "LL", "SWC1", "SDC1", "SD", "SC", "BLTZ", "BGEZ", "BLTZL", "BGEZL", "BLTZAL", "BGEZAL", "BLTZALL", "BGEZALL", "SLL", "SRL", "SRA", "SLLV", "SRLV", "SRAV", "JR", "JALR", "SYSCALL", "MFHI", "MTHI", "MFLO", "MTLO", "DSLLV", "DSRLV", "DSRAV", "MULT", "MULTU", "DIV", "DIVU", "DMULT", "DMULTU", "DDIV", "DDIVU", "ADD", "ADDU", "SUB", "SUBU", "AND", "OR", "XOR", "NOR", "SLT", "SLTU", "DADD", "DADDU", "DSUB", "DSUBU", "DSLL", "DSRL", "DSRA", "TEQ", "DSLL32", "DSRL32", "DSRA32", "BC1F", "BC1T", "BC1FL", "BC1TL", "TLBWI", "TLBP", "TLBR", "TLBWR", "ERET", "MFC0", "MTC0", "MFC1", "DMFC1", "CFC1", "MTC1", "DMTC1", "CTC1", "f.CVT", "f.CMP", "f.ADD", "f.SUB", "f.MUL", "f.DIV", "f.SQRT", "f.ABS", "f.MOV", "f.NEG", "f.ROUND", "f.TRUNC", "f.CEIL", "f.FLOOR" }; unsigned int instr_type[131] = { 9, 10, 6, 6, 7, 7, 7, 7, 3, 3, 4, 4, 3, 4, 4, 0, 7, 7, 7, 7, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 6, 6, 10, 2, 2, 2, 2, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 7, 7, 7, 7, 10, 10, 10, 10, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5 }; char instr_typename[][20] = { "Load", "Store", "Data move/convert", "32-bit math", "64-bit math", "Float Math", "Jump", "Branch", "Exceptions", "Reserved", "Other" }; /* Global functions */ int GetInstrType(int opcode); int AddrCompare(const void *, const void *); int ParseProfLine(const char *pchIn, long *plAddress, int *piSamples, float *pfPercentage); /* defined types */ typedef struct __attribute__ ((__packed__)) { int mipsop; long x86addr; } r4300op; typedef struct { long x86addr; int samples; } profilehit; /* static functions */ static int isSpace(char ch) { return (ch == ' ' || ch == '\t' ? 1 : 0); } static int isNum(char ch) { return (ch >= '0' && ch <= '9' ? 1 : 0); } static int isFloat(char ch) { return ((ch >= '0' && ch <= '9') || ch == '.' || ch == '+' || ch == '-' || ch == 'e' ? 1 : 0); } static int isHex(char ch) { return ((ch >= '0' && ch <= '9') || ((ch & 0xdf) >= 'A' && (ch & 0xdf) <= 'F') ? 1 : 0); } /* main */ int main(int argc, void *argv[]) { long lOpStart, lOpEnd; int flength, oplistlength, totaltime, proflistlength; int samp_unknown, samp_blockend, samp_notcompiled, samp_wrappers, samp_flush; int i, j; FILE *pfIn; r4300op *pOpAddrTable; profilehit *pProfTable; char *pch, *pchSampleData; /* check arguments */ if (argc < 3) { printf("Usage: r4300prof r4300addr.dat x86profile.txt\n\n"); printf("r4300addr.dat - binary table of r4300 opcodes and corresponding x86 starting addresses\n"); printf("x86profile.txt - text file containing a list of profile sample counts by x86 address on the heap\n\n"); return 1; } /* open r4300 opcode/x86 address table generated from emulator run */ printf("Loading %s...\n", argv[1]); pfIn = osal_file_open(argv[1], "rb"); if (pfIn == NULL) { printf("Couldn't open input file: %s\n", argv[1]); return 2; } /* get file length and calculate number of r4300op table entries */ fseek(pfIn, 0L, SEEK_END); flength = (int) ftell(pfIn); fseek(pfIn, 0L, SEEK_SET); oplistlength = flength / sizeof(r4300op); /* read the file */ pOpAddrTable = (r4300op *) malloc(flength); if (pOpAddrTable == NULL) { printf("Failed to allocate %i bytes for OpAddrTable!\n", flength); fclose(pfIn); return 3; } fread(pOpAddrTable, 1, flength, pfIn); fclose(pfIn); printf("%i r4300 instruction locations read.\n", oplistlength); /* sort the opcode/address table according to x86addr */ qsort(pOpAddrTable, oplistlength, sizeof(r4300op), AddrCompare); /* remove any 0-length r4300 instructions */ i = 0; j = 0; while (i < oplistlength) { pOpAddrTable[j].mipsop = pOpAddrTable[i].mipsop; pOpAddrTable[j].x86addr = pOpAddrTable[i].x86addr; i++; if (pOpAddrTable[j].x86addr != pOpAddrTable[i].x86addr) j++; } oplistlength = j; printf("%i non-empty MIPS instructions.\n", oplistlength); /* convert each r4300 opcode to an instruction type index */ for (i = 0; i < oplistlength; i++) if (pOpAddrTable[i].mipsop > 0 || pOpAddrTable[i].mipsop < -16) pOpAddrTable[i].mipsop = GetInstrType(pOpAddrTable[i].mipsop); /* open the profiling sample data file */ printf("Loading %s...\n", argv[2]); pfIn = osal_file_open(argv[2], "rb"); if (pfIn == NULL) { printf("Couldn't open input file: %s\n", argv[2]); free(pOpAddrTable); return 4; } /* load it */ fseek(pfIn, 0L, SEEK_END); flength = (int) ftell(pfIn); fseek(pfIn, 0L, SEEK_SET); pchSampleData = (char *) malloc(flength + 16); if (pchSampleData == NULL) { printf("Failed to allocate %i bytes for pchSampleData!\n", flength + 16); fclose(pfIn); free(pOpAddrTable); return 5; } fread(pchSampleData, 1, flength, pfIn); pchSampleData[flength] = 0; fclose(pfIn); /* count the number of newlines in the ascii-formatted sample data file */ proflistlength = 1; pch = pchSampleData; while (pch = strchr(pch, '\n')) { proflistlength++; pch++; } printf("%i lines in sample data file.\n", proflistlength); /* extract text data into binary table */ pProfTable = (profilehit *) malloc(proflistlength * sizeof(profilehit)); if (pProfTable == NULL) { printf("Failed to allocate %i bytes for pProfTable!\n", proflistlength * sizeof(profilehit)); free(pOpAddrTable); free(pchSampleData); return 6; } pch = pchSampleData; j = 0; long long llOffset = 0; while (j < proflistlength) { long lAddress; int iSamples; float fPercentage; char *pchNext = strchr(pch, '\n'); if (pchNext != NULL) *pchNext++ = 0; // null-terminate this line if (strstr(pch, "range:0x") != NULL) // search for offset change { pch = strstr(pch, "range:0x") + 8; // extract hex value and update our offset char *pch2 = pch; while (isHex(*pch2)) pch2++; *pch2 = 0; llOffset = strtoll(pch, NULL, 16); } else // parse line for sample point { int rval = ParseProfLine(pch, &lAddress, &iSamples, &fPercentage); if (rval != 0) { pProfTable[j].x86addr = (unsigned long) (lAddress + llOffset); pProfTable[j].samples = iSamples; j++; } } pch = pchNext; if (pch == NULL) break; } free(pchSampleData); proflistlength = j; printf("Found %i profile hits.\n", proflistlength); /* clear r4300 instruction sample data table */ for (i = 0; i < 132; i++) instr_samples[i] = 0; /* calculate r4300 instruction profiling data by merging the tables */ samp_unknown = 0; samp_blockend = 0; samp_notcompiled = 0; samp_wrappers = 0; samp_flush = 0; i = 0; // i == OpAddrTable index lOpStart = pOpAddrTable[0].x86addr; lOpEnd = pOpAddrTable[1].x86addr; for (j = 0; j < proflistlength; j++) // j == pProfTable index { long lOpx86addr = pProfTable[j].x86addr; if (lOpx86addr >= lOpStart && lOpx86addr <= lOpEnd) /* these profile samples lie within current r4300 instruction */ { int instr = pOpAddrTable[i].mipsop; if (instr == -1) printf("%lx sample point lies between %i/%lx and %i/%lx\n", lOpx86addr, instr, lOpStart, pOpAddrTable[i+1].mipsop, lOpEnd); if (instr == -1) samp_unknown += pProfTable[j].samples; else if (instr == -2) samp_notcompiled += pProfTable[j].samples; else if (instr == -3) samp_blockend += pProfTable[j].samples; else if (instr == -4) samp_wrappers += pProfTable[j].samples; else if (instr == -5) samp_flush += pProfTable[j].samples; else instr_samples[instr] += pProfTable[j].samples; continue; } if (lOpx86addr < pOpAddrTable[0].x86addr || lOpx86addr >= pOpAddrTable[oplistlength-1].x86addr) { /* outside the range of all recompiled instructions */ samp_unknown += pProfTable[j].samples; continue; } if (lOpx86addr < lOpStart) /* discontinuity in profile list, go back to start */ { i = 0; lOpStart = pOpAddrTable[0].x86addr; lOpEnd = pOpAddrTable[1].x86addr; j--; continue; } /* this profile point is ahead of current r4300 instruction */ do /* race ahead in r4300 opcode list until we hit this profile sample point */ { i++; } while (i+1 < oplistlength && lOpx86addr > pOpAddrTable[i+1].x86addr); lOpStart = pOpAddrTable[i].x86addr; lOpEnd = pOpAddrTable[i+1].x86addr; if (lOpx86addr < lOpStart || lOpx86addr > lOpEnd) { printf("Error: lOpx86addr = %lx but lOpStart, lOpEnd = %lx, %lx\n", lOpx86addr, lOpStart, lOpEnd); return 7; } /* we have found the correct r4300 instruction corresponding to this profile point */ j--; } /* print the results */ unsigned int iTypeCount[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; printf("\nInstruction time (samples):\n"); totaltime = 0; for (i = 0; i < 131; i++) { printf("%8s: %08i ", instr_name[i], instr_samples[i]); if (i % 5 == 4) printf("\n"); iTypeCount[instr_type[i]] += instr_samples[i]; totaltime += instr_samples[i]; } int special = samp_flush + samp_wrappers + samp_notcompiled + samp_blockend; printf("\n\nSpecial code samples:\n"); printf(" Regcache flushing: %i\n", samp_flush); printf(" Jump wrappers: %i\n", samp_wrappers); printf(" NOTCOMPILED: %i\n", samp_notcompiled); printf(" block postfix & link samples: %i\n", samp_blockend); printf("\nUnaccounted samples: %i\n", samp_unknown); printf("Total accounted instruction samples: %i\n", totaltime + special); for (i = 0; i < 11; i++) { printf("%20s: %04.1f%% (%i)\n", instr_typename[i], (float) iTypeCount[i] * 100.0 / totaltime, iTypeCount[i]); } free(pOpAddrTable); free(pProfTable); return 0; } int AddrCompare(const void *p1, const void *p2) { const r4300op *pOp1 = (const r4300op *) p1; const r4300op *pOp2 = (const r4300op *) p2; if (pOp1->x86addr < pOp2->x86addr) return -1; else if (pOp1->x86addr == pOp2->x86addr) return (int) (pOp1 - pOp2); /* this forces qsort to be stable */ else return 1; } int ParseProfLine(const char *pchIn, long *plAddress, int *piSamples, float *pfPercentage) { char chVal[128], *pchOut; /* skip any initial whitespace */ while (isSpace(*pchIn)) pchIn++; if (!isHex(*pchIn)) return 0; /* parse hexadecimal address value */ pchOut = chVal; while (isHex(*pchIn)) *pchOut++ = *pchIn++; *pchOut = 0; if (!isSpace(*pchIn)) return 0; *plAddress = strtol(chVal, NULL, 16); /* skip more whitespace */ while (isSpace(*pchIn)) pchIn++; if (!isNum(*pchIn)) return 0; /* parse decimal sample count value */ pchOut = chVal; while (isNum(*pchIn)) *pchOut++ = *pchIn++; *pchOut = 0; if (!isSpace(*pchIn)) return 0; *piSamples = atoi(chVal); /* skip more whitespace */ while (isSpace(*pchIn)) pchIn++; if (!isFloat(*pchIn)) return 0; /* parse floating-point percentage value */ pchOut = chVal; while (isFloat(*pchIn)) *pchOut++ = *pchIn++; *pchOut = 0; if (!isSpace(*pchIn) && *pchIn != '\r' && *pchIn != '\n' && *pchIn != 0) return 0; *pfPercentage = atof(chVal); /* if this isn't the end of the line, it's not a valid sample point */ while (isSpace(*pchIn)) pchIn++; if (*pchIn != '\r' && *pchIn != '\n' && *pchIn != 0) return 0; return 1; } static int InstrTypeStd[64] = { -1, -1, 02, 03, 04, 05, 06, 07, 8, 9, 10, 11, 12, 13, 14, 15, -1, -1, 00, 00, 16, 17, 18, 19, 20, 21, 22, 23, 00, 00, 00, 00, 24, 25, 27, 26, 28, 29, 31, 30, 32, 33, 35, 34, 37, 38, 36, 01, 42, 39, 00, 00, 01, 40, 00, 41, 46, 43, 00, 00, 01, 44, 00, 45 }; static int InstrTypeSpecial[64] = { 55, 00, 56, 57, 58, 00, 59, 60, 61, 62, 00, 00, 63, 01, 00, 00, 64, 65, 66, 67, 68, 00, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 00, 00, 87, 88, 89, 90, 91, 92, 01, 01, 01, 01, 96, 00, 01, 00, 93, 00, 94, 95, 97, 00, 98, 99 }; static int InstrTypeRegImm[32] = { 47, 48, 49, 50, 00, 00, 00, 00, 01, 01, 01, 01, 01, 00, 01, 00, 51, 52, 53, 54, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 }; static int InstrTypeCop1[32] = { 111, 112, 113, 00, 114, 115, 116, 00, -1, 00, 00, 00, 00, 00, 00, 00, -1, -1, 00, 00, -1, -1, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 }; static int InstrTypeCop1Math[64] = { 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 127, 128, 129, 130, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 117, 117, 00, 00, 117, 117, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118 }; int GetInstrType(int opcode) { int iType = (opcode >> 26) & 63; if (iType == 0) { /* SPECIAL instruction */ iType = opcode & 63; return InstrTypeSpecial[iType]; } else if (iType == 1) { /* REGIMM instruction */ iType = (opcode >> 16) & 31; return InstrTypeRegImm[iType]; } else if (iType == 16) { /* COP0 instruction */ int iType1 = opcode & 0x01FFFFFF; int iType2 = (opcode >> 21) & 31; if (iType1 == 1) return 106; // TLBR else if (iType1 == 2) return 104; // TLBWI else if (iType1 == 6) return 107; // TLBWR else if (iType1 == 8) return 105; // TLBP else if (iType1 == 24) return 108; // ERET else if ((opcode & 0x7FF) == 0 && iType2 == 0) return 109; // MFC0 else if ((opcode & 0x7FF) == 0 && iType2 == 4) return 110; // MTC0 else return 0; // reserved } else if (iType == 17) { /* COP1 instruction */ int iType1 = (opcode >> 21) & 31; if (iType1 == 8) { /* conditional branch */ int iType2 = (opcode >> 16) & 31; if (iType2 == 0) return 100; // BC1F else if (iType2 == 1) return 101; // BC1T else if (iType2 == 2) return 102; // BC1FL else if (iType2 == 3) return 103; // BC1TL else return 0; // reserved } else if (iType1 == 16 || iType1 == 17 || iType1 == 20 || iType1 == 21) { /* Single, Double, Word, Long instructions */ int iType2 = opcode & 63; return InstrTypeCop1Math[iType2]; } else { /* other Cop1 (move) */ return InstrTypeCop1[iType1]; } } /* standard MIPS instruction */ return InstrTypeStd[iType]; } mupen64plus-core-src-2.6.0/tools/regtests/000077500000000000000000000000001464506436200204465ustar00rootroot00000000000000mupen64plus-core-src-2.6.0/tools/regtests/daily-tests.cfg000066400000000000000000000157741464506436200234070ustar00rootroot00000000000000#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # * Mupen64plus - daily-tests.cfg * # * Mupen64Plus homepage: https://mupen64plus.org/ * # * Copyright (C) 2008-2009 Richard Goedeken * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ # Daily regression test config file for Mupen64Plus # # To set up an automatic nightly test, run "crontab -e" and add a line like this: # # 30 03 * * * export DISPLAY=:0 ; /home/username/software/regtests/regression-video.py # # This will launch the test at 3:30am each night. You will need to replace the path to the # regression-video.py script with the correct path for your system. You may also need to # disable your screen saver to make this work. # Global test settings rompath = /path/to/N64/ROMs sendemail = me@mydomain.com videobuild = 64-bit basic build videobuildparams = all numspeedbuilds = 3 speedbuild0params = all BITS=32 SDL_CONFIG="sdl-config" speedbuild0tests = 3 speedbuild0test0name = 32-bit Pure Interpreter speedbuild0test0options = --emumode 0 speedbuild0test1name = 32-bit Cached Interpreter speedbuild0test1options = --emumode 1 speedbuild0test2name = 32-bit Old Dynarec speedbuild0test2options = --emumode 2 speedbuild1params = all BITS=32 NEW_DYNAREC=1 SDL_CONFIG="sdl-config" speedbuild1tests = 1 speedbuild1test0name = 32-bit New Dynarec speedbuild1test0options = --emumode 2 speedbuild2params = all speedbuild2tests = 3 speedbuild2test0name = 64-bit Pure Interpreter speedbuild2test0options = --emumode 0 speedbuild2test1name = 64-bit Cached Interpreter speedbuild2test1options = --emumode 1 speedbuild2test2name = 64-bit Old Dynarec speedbuild2test2options = --emumode 2 {Core Library} url = https://github.com/mupen64plus/mupen64plus-core outputfiles = libmupen64plus.so.2 testbuilds = 32-bit build on 64-bit system, LIRC build, No Assembly build, Debug Info build, R4300 Debugger build testbuildparams = all BITS=32, all LIRC=1, all NO_ASM=1, all DEBUG=1 DBG_CORE=1 DBG_COUNT=1 DBG_COMPARE=1 DBG_PROFILE=1, all DEBUGGER=1 {Console UI} url = https://github.com/mupen64plus/mupen64plus-ui-console outputfiles = mupen64plus testbuilds = 32-bit build testbuildparams = all BITS=32 {Video-Rice} url = https://github.com/mupen64plus/mupen64plus-video-rice outputfiles = mupen64plus-video-rice.so testbuilds = 32-bit build, no assembly build, debug build testbuildparams = all BITS=32, all NO_ASM=1, all DEBUG=1 {Video-Glide64mk2} url = https://github.com/mupen64plus/mupen64plus-video-glide64mk2 outputfiles = mupen64plus-video-glide64mk2.so testbuilds = 32-bit build testbuildparams = all BITS=32 {Audio-SDL} url = https://github.com/mupen64plus/mupen64plus-audio-sdl outputfiles = mupen64plus-audio-sdl.so testbuilds = 32-bit build testbuildparams = all BITS=32 {Input-SDL} url = https://github.com/mupen64plus/mupen64plus-input-sdl outputfiles = mupen64plus-input-sdl.so testbuilds = 32-bit build testbuildparams = all BITS=32 {RSP-HLE} url = https://github.com/mupen64plus/mupen64plus-rsp-hle outputfiles = mupen64plus-rsp-hle.so testbuilds = 32-bit build testbuildparams = all BITS=32 # Game-specific settings [1080 Snowboarding (E) (M4) [!].z64] screenshots = 22, 147, 276, 354, 540, 684 [Airboarders 64.z64] screenshots = 46, 450, 475, 508, 548, 632 [Automobili Lamborghini.z64] screenshots = 35, 226, 532, 586, 632, 682, 752, 838 [Banjo-Kazooie.z64] screenshots = 26, 129, 287, 536, 581, 627 [Batman Beyond - Return of the Joker.z64] screenshots = 42, 352, 613, 1178 [Bomberman 64 (U) [!].z64] screenshots = 72, 578, 767, 950, 1110, 1219 [Bust-A-Move '99.z64] screenshots = 119,966,1186,1282,1378,1479,1691,2082 [Cruis'n USA.z64] screenshots = 0, 93, 191, 250, 308, 420 [Doom 64.z64] screenshots = 18, 364, 469 [Earthworm Jim 3D.z64] screenshots = 42, 354, 770, 877, 991, 1285, 1364, 1487 [Elmo's Letter Adventure.z64] screenshots = 49, 393, 1389 [Fighting Force 64.z64] screenshots = 35, 353, 919 ,1044, 1401, 2267 [Forsaken 64.z64] screenshots = 27, 527 [Gauntlet Legends.v64] screenshots = 31, 503, 792, 929, 1038, 1228, 1284, 1412, 1589 skipvideo = glN64 [Iggy's Reckin' Balls.z64] screenshots = 142, 493, 531, 726, 824 [Kirby 64 - The Crystal Shards (U) [!].z64] screenshots = 28, 164, 439, 606, 859, 979, 1115, 1203, 1384, 1612, 1921, 2170 [Mario Kart 64 (U) [!].z64] screenshots = 41, 104, 260, 572, 629, 897, 961 speedtest = 3000 [Micro Machines 64 Turbo.z64] screenshots = 52, 142, 250, 511, 623, 690, 743 [Mischief Makers.z64] screenshots = 85, 360, 607, 882, 1043, 1155, 1259, 1334, 1489 [Mortal Kombat 4 (U) [!].z64] screenshots = 37, 171, 319, 517 [Paper Mario (U) [!].z64] screenshots = 57, 235, 595, 843, 1177, 1401 [Penny Racers.z64] screenshots = 24, 462, 620, 755 skipvideo = rice, glide64 [Quake 64 (U) [!].z64] screenshots = 35, 319, 427 [Road Rash 64.z64] screenshots = 44, 330, 459, 634 [San Francisco Rush - Extreme Racing.z64] screenshots = 17, 93, 246, 282, 397, 509, 704 [Star Fox 64 (U) (V1.1) [!].z64] screenshots = 35, 295, 458, 794, 929, 1390 [Super Mario 64 (U) [!].z64] screenshots = 17, 119, 199, 330, 421 [Super Smash Bros..z64] screenshots = 40, 78, 185, 590, 1008, 1117, 1349, 1566, 1639, 1683, 1745, 1805 [Taz Express (E) (M6) [!].z64] screenshots = 25, 119, 167, 322 [TheLegendofZeldaOcarinaofTime.v64] screenshots = 84, 299, 380, 513, 601, 706, 770 [Top Gear Rally.z64] screenshots = 62, 194, 299, 454, 557, 861, 937, 970, 1072, 1228, 1273, 1342 [Turok - Dinosaur Hunter.z64] screenshots = 51, 222, 301, 438, 554, 910, 975, 1004 [Turok 2 - Seeds of Evil.z64] speedtest = 3000 [Vigilante 8.z64] speedtest = 3000 [Wave Race 64.z64] screenshots = 25, 99, 214, 275, 333, 389, 426 [Wetrix.N64] screenshots = 66, 176, 353, 440, 545, 742, 827, 863 [Worms - Armageddon (U) (M3) [!].z64] screenshots = 38, 375 [Yoshi's Story (U) (M2) [!].z64] screenshots = 68, 276, 340, 572, 638 mupen64plus-core-src-2.6.0/tools/regtests/regression-video.py000077500000000000000000000734361464506436200243240ustar00rootroot00000000000000#!/usr/bin/env python #/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # * Mupen64plus - regression-video.py * # * Mupen64Plus homepage: https://mupen64plus.org/ * # * Copyright (C) 2008-2012 Richard Goedeken * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ from optparse import OptionParser from threading import Thread from datetime import date import subprocess import commands import shutil import stat import time import sys import os # set global report string report = "Mupen64Plus Regression Test report\n----------------------------------\n" #****************************************************************************** # main functions # def main(rootdir, cfgfile, nogit, nobuild, nospeed, novidcheck, noemail): global report # set up child directory paths srcdir = os.path.join(rootdir, "source") shotdir = os.path.join(rootdir, "current") refdir = os.path.join(rootdir, "reference") archivedir = os.path.join(rootdir, "archive") # run the test procedure tester = RegTester(rootdir, srcdir, shotdir) rval = 0 while True: # Step 1: load the test config file if not tester.LoadConfig(cfgfile): rval = 1 break # Step 2: check out from Git if not nogit: if not tester.CheckoutSource(srcdir): rval = 2 break # Step 3: run test builds if not nobuild: for modname in tester.modulesAndParams: module = tester.modulesAndParams[modname] if "testbuilds" not in module: continue modurl = module["url"] modfilename = modurl.split('/')[-1] testlist = [ name.strip() for name in module["testbuilds"].split(',') ] makeparams = [ params.strip() for params in module["testbuildparams"].split(',') ] if len(testlist) != len(makeparams): report += "Config file error for test builds in %s. Build name list and makefile parameter list have different lengths.\n" % modname testbuilds = min(len(testlist), len(makeparams)) for i in range(testbuilds): buildname = testlist[i] buildmake = makeparams[i] BuildSource(srcdir, modfilename, modname, buildname, buildmake, module["outputfiles"], True, False) # Step 4: run speed tests if not nospeed: SpeedTestResults = [ ] # we iterate over each separate build numSpeedBuilds = int(tester.generalParams["numspeedbuilds"]) for buildIdx in range(numSpeedBuilds): buildname = "Speedtest Build #%i" % (buildIdx+1) buildmake = tester.generalParams["speedbuild%iparams" % buildIdx] # build all modules for modname in tester.modulesAndParams: module = tester.modulesAndParams[modname] modurl = module["url"] modfilename = modurl.split('/')[-1] if not BuildSource(srcdir, modfilename, modname, buildname, buildmake, module["outputfiles"], False, False): rval = 3 break if rval > 0: break # then we iterate over each separate test case for this build numCases = int(tester.generalParams["speedbuild%itests" % buildIdx]) for caseIdx in range(numCases): caseName = tester.generalParams["speedbuild%itest%iname" % (buildIdx, caseIdx)] caseOptions = tester.generalParams["speedbuild%itest%ioptions" % (buildIdx, caseIdx)].split(" ") oneRunResults = tester.RunSpeedTests(caseName, caseOptions) SpeedTestResults.append((caseName, oneRunResults)) # now we summarize the results if numSpeedBuilds > 0 and SpeedTestResults[0][1] is not None: numGames = len(SpeedTestResults[0][1]) gameNames = [result[0] for result in SpeedTestResults[0][1]] gameNameLengths = [len(name) for name in gameNames] maxTestNameLength = max([len(case[0]) for case in SpeedTestResults]) report += "Run %i speed test cases with %i games (best of 3 trials)\n" % (len(SpeedTestResults),numGames) tableHeader = (" " * (maxTestNameLength + 2)) + " ".join(gameNames) report += tableHeader + "\n" + ("=" * len(tableHeader)) + "\n" for (caseName, runResults) in SpeedTestResults: report += caseName + (" " * (maxTestNameLength - len(caseName) + 2)) if runResults == None: report += "Failed!\n" continue for (gameName, testTime) in runResults: strTime = "%.2f" % testTime report += strTime + (" " * (len(gameName) - len(strTime) + 2)) report += "\n" report += "\n" # Step 5: build the binary for the video regression test if not novidcheck: videobuild = tester.generalParams["videobuild"] videomake = tester.generalParams["videobuildparams"] for modname in tester.modulesAndParams: module = tester.modulesAndParams[modname] modurl = module["url"] modfilename = modurl.split('/')[-1] if not BuildSource(srcdir, modfilename, modname, videobuild, videomake, module["outputfiles"], False, True): rval = 3 break if rval != 0: break # Step 6: run the tests, check the results if not tester.RunTests(): rval = 4 break if not tester.CheckResults(refdir): rval = 5 break # test procedure is finished break # Step 7: send email report and archive the results if not noemail: if not tester.SendReport(): rval = 6 if not novidcheck: if not tester.ArchiveResults(archivedir): rval = 7 # all done with test process return rval #****************************************************************************** # Checkout & build functions # def BuildSource(srcdir, moddir, modname, buildname, buildmake, outputfiles, isbuildtest, isvideotest): global report makepath = os.path.join(srcdir, moddir, "projects", "unix") # to start, clean up os.system("make -C %s clean" % makepath) # print build report message and clear counters testbuildcommand = "make -C %s %s" % (makepath, buildmake) if isbuildtest: report += "Running %s test build \"%s\"\n" % (modname, buildname) elif isvideotest: report += "Building %s \"%s\" for video test\n" % (modname, buildname) warnings = 0 errors = 0 # run make and capture the output output = commands.getoutput(testbuildcommand) makelines = output.split("\n") # print warnings and errors for line in makelines: if "error:" in line: report += " " + line + "\n" errors += 1 if "warning:" in line and (isbuildtest or isvideotest): report += " " + line + "\n" warnings += 1 if isbuildtest or isvideotest: report += "%i errors. %i warnings.\n" % (errors, warnings) if errors > 0 and not isbuildtest: return False # check for output files for filename in outputfiles.split(','): if not os.path.exists(os.path.join(makepath, filename)): report += "Build failed: '%s' not found\n" % filename errors += 1 if errors > 0 and not isbuildtest: return False # if this wasn't a build test, then copy our output files and data files if not isbuildtest: for filename in outputfiles.split(','): try: os.unlink(os.path.join(srcdir, filename)) except: pass shutil.move(os.path.join(makepath, filename), srcdir) datapath = os.path.join(srcdir, moddir, "data") if os.path.isdir(datapath): copytree(datapath, os.path.join(srcdir, "data")) # build was successful! return True #****************************************************************************** # Test execution classes # class RegTester: def __init__(self, rootdir, bindir, screenshotdir): self.rootdir = rootdir self.bindir = bindir self.screenshotdir = screenshotdir self.generalParams = { } self.gamesAndParams = { } self.modulesAndParams = { } self.videoplugins = [ "mupen64plus-video-rice.so", "mupen64plus-video-glide64mk2.so" ] self.thisdate = str(date.today()) def LoadConfig(self, filename): global report # read the config file report += "\nLoading regression test configuration.\n" try: cfgfile = open(os.path.join(self.rootdir, filename), "r") cfglines = cfgfile.read().split("\n") cfgfile.close() except Exception, e: report += "Error in RegTestConfigParser::LoadConfig(): %s" % e return False # parse the file GameFilename = None ModuleName = None for line in cfglines: # strip leading and trailing whitespace line = line.strip() # test for comment if len(line) == 0 or line[0] == '#': continue # test for new game filename if line[0] == '[' and line [-1] == ']': GameFilename = line[1:-1] if GameFilename in self.gamesAndParams: report += " Warning: Config file '%s' contains duplicate game entry '%s'\n" % (filename, GameFilename) else: self.gamesAndParams[GameFilename] = { } continue # test for new source module build if line[0] == '{' and line [-1] == '}': ModuleName = line[1:-1] if ModuleName in self.modulesAndParams: report += " Warning: Config file '%s' contains duplicate source module '%s'\n" % (filename, ModuleName) else: self.modulesAndParams[ModuleName] = { } continue # print warning and continue if it's not a (key = value) pair pivot = line.find('=') if pivot == -1: report += " Warning: Config file '%s' contains unrecognized line: '%s'\n" % (filename, line) continue # parse key, value key = line[:pivot].strip().lower() value = line[pivot+1:].strip() if ModuleName is None: paramDict = self.generalParams elif GameFilename is None: paramDict = self.modulesAndParams[ModuleName] else: paramDict = self.gamesAndParams[GameFilename] if key in paramDict: report += " Warning: duplicate key '%s'\n" % key continue paramDict[key] = value # check for required parameters if "rompath" not in self.generalParams: report += " Error: rompath is not given in config file\n" return False # config is loaded return True def CheckoutSource(self, srcdir): global report # remove any current source directory if not deltree(srcdir): return False os.mkdir(srcdir) os.mkdir(os.path.join(srcdir, "data")) # loop through all of the source modules for modname in self.modulesAndParams: module = self.modulesAndParams[modname] if "url" not in module: report += "Error: no Git repository URL for module %s\n\n" % modname return False modurl = module["url"] modfilename = modurl.split("/")[-1] # call Git to checkout Mupen64Plus source module (status, output) = commands.getstatusoutput("git clone %s %s/%s" % (modurl, srcdir, modfilename)) # parse the output lastline = output.split("\n")[-1] if 0 != os.WEXITSTATUS(status): report += "Git Error: %s\n\n" % lastline return False # get the revision info RevFound = False output = commands.getoutput("git --git-dir=%s/.git log HEAD~1..HEAD" % os.path.join(srcdir, modfilename)) for line in output.split('\n'): words = line.split() if len(words) == 2 and words[0] == 'commit': report += "Git Checkout %s: changeset %s\n" % (modfilename, words[1]) RevFound = True if not RevFound: report += "Git Error: couldn't find revision information\n\n" return False return True def RunTests(self): global report rompath = self.generalParams["rompath"] if not os.path.exists(rompath): report += " Error: ROM directory '%s' does not exist!\n" % rompath return False # Remove any current screenshot directory if not deltree(self.screenshotdir): return False # Data initialization and start message os.mkdir(self.screenshotdir) for plugin in self.videoplugins: videoname = plugin[:plugin.find('.')] os.mkdir(os.path.join(self.screenshotdir, videoname)) report += "\nRunning regression tests on %i games.\n" % len(self.gamesAndParams) # loop over each game filename given in regtest config file for GameFilename in self.gamesAndParams: GameParams = self.gamesAndParams[GameFilename] # if no screenshots parameter given for this game then skip it if "screenshots" not in GameParams: continue # make a list of screenshots and check it shotlist = [ str(int(framenum.strip())) for framenum in GameParams["screenshots"].split(',') ] if len(shotlist) < 1 or (len(shotlist) == 1 and shotlist[0] == '0'): report += " Warning: invalid screenshot list for game '%s'\n" % GameFilename continue # run a test for each video plugin for plugin in self.videoplugins: videoname = plugin[:plugin.find('.')] # check if this plugin should be skipped if "skipvideo" in GameParams: skipit = False skiplist = [ name.strip() for name in GameParams["skipvideo"].split(',') ] for skiptag in skiplist: if skiptag.lower() in plugin.lower(): skipit = True if skipit: continue # construct the command line exepath = os.path.join(self.bindir, "mupen64plus") exeparms = [ "--corelib", os.path.join(self.bindir, "libmupen64plus.so.2") ] exeparms += [ "--testshots", ",".join(shotlist) ] exeparms += [ "--sshotdir", os.path.join(self.screenshotdir, videoname) ] exeparms += [ "--plugindir", self.bindir ] exeparms += [ "--datadir", os.path.join(self.bindir, "data") ] myconfig = os.path.join(self.rootdir, "config") #if os.path.exists(myconfig): exeparms += [ "--configdir", myconfig ] exeparms += [ "--gfx", plugin ] exeparms += [ "--emumode", "2" ] exeparms += [ os.path.join(rompath, GameFilename) ] # run it, but if it takes too long print an error and kill it testrun = RegTestRunner(exepath, exeparms) testrun.start() testrun.join(60.0) if testrun.isAlive(): report += " Error: Test run timed out after 60 seconds: '%s'\n" % " ".join(exeparms) os.kill(testrun.pid, 9) testrun.join(10.0) # all tests have been run return True def RunSpeedTests(self, caseName, caseOptions): global report rompath = self.generalParams["rompath"] if not os.path.exists(rompath): report += " Error: ROM directory '%s' does not exist!\n" % rompath return None # Remove any current screenshot directory if not deltree(self.screenshotdir): return None # Data initialization and start message os.mkdir(self.screenshotdir) # figure out which games to test testGames = [] for GameFilename in sorted(self.gamesAndParams.iterkeys()): GameParams = self.gamesAndParams[GameFilename] if "speedtest" not in GameParams: continue numFrames = int(GameParams["speedtest"]) # clean up the game's name GameName = GameFilename for charDelimiter in [".","-","("]: pivot = GameName.find(charDelimiter) if pivot != -1: GameName = GameName[:pivot] testGames.append((GameName, GameFilename,numFrames)) # run the tests speedResults = [ ] for (gameName, gameFilename, numFrames) in testGames: # construct the command line exepath = os.path.join(self.bindir, "mupen64plus") exeparms = [ "--corelib", os.path.join(self.bindir, "libmupen64plus.so.2") ] exeparms += [ "--testshots", ("%i" % numFrames) ] exeparms += [ "--sshotdir", self.screenshotdir ] exeparms += [ "--plugindir", self.bindir ] exeparms += [ "--datadir", os.path.join(self.bindir, "data") ] exeparms += [ "--configdir", os.path.join(self.rootdir, "config") ] exeparms += [ "--gfx", "mupen64plus-video-rice" ] exeparms += [ "--nospeedlimit", "--noosd", "--nosaveoptions" ] exeparms += [ "--audio", "dummy" ] exeparms += caseOptions exeparms += [ os.path.join(rompath, gameFilename) ] # make 3 runs, take best of them bestTime = None for i in range(3): # run it, but if it takes too long print an error and kill it testrun = RegTestRunner(exepath, exeparms) startTime = time.time() testrun.start() testrun.join(360.0) if testrun.isAlive(): report += " Error: Test run timed out after 360 seconds: '%s'\n" % " ".join(exeparms) os.kill(testrun.pid, 9) testrun.join(10.0) break endTime = time.time() thisTime = endTime - startTime if bestTime is None or thisTime < bestTime: bestTime = thisTime # save the best of 3 times speedResults.append((gameName,bestTime)) return speedResults def CheckResults(self, refdir): global report # print message warnings = 0 errors = 0 report += "\nChecking regression test results\n" # get lists of files in the reference folders refshots = { } if not os.path.exists(refdir): os.mkdir(refdir) for plugin in self.videoplugins: videoname = plugin[:plugin.find('.')] videodir = os.path.join(refdir, videoname) if not os.path.exists(videodir): os.mkdir(videodir) refshots[videoname] = [ ] else: refshots[videoname] = [ filename for filename in os.listdir(videodir) ] # get lists of files produced by current test runs newshots = { } for plugin in self.videoplugins: videoname = plugin[:plugin.find('.')] videodir = os.path.join(self.screenshotdir, videoname) if not os.path.exists(videodir): newshots[videoname] = [ ] else: newshots[videoname] = [ filename for filename in os.listdir(videodir) ] # make list of matching ref/test screenshots, and look for missing reference screenshots checklist = { } for plugin in self.videoplugins: videoname = plugin[:plugin.find('.')] checklist[videoname] = [ ] for filename in newshots[videoname]: if filename in refshots[videoname]: checklist[videoname] += [ filename ] else: report += " Warning: reference screenshot '%s/%s' missing. Copying from current test run\n" % (videoname, filename) shutil.copy(os.path.join(self.screenshotdir, videoname, filename), os.path.join(refdir, videoname)) warnings += 1 # look for missing test screenshots for plugin in self.videoplugins: videoname = plugin[:plugin.find('.')] for filename in refshots[videoname]: if filename not in newshots[videoname]: report += " Error: Test screenshot '%s/%s' missing.\n" % (videoname, filename) errors += 1 # do image comparisons for plugin in self.videoplugins: videoname = plugin[:plugin.find('.')] for filename in checklist[videoname]: refimage = os.path.join(refdir, videoname, filename) testimage = os.path.join(self.screenshotdir, videoname, filename) diffimage = os.path.join(self.screenshotdir, videoname, os.path.splitext(filename)[0] + "_DIFF.png") if videoname.find("rice") != -1: # we have to escape some characters in here for the shell escrefimage = refimage.replace("'", "\\'") esctestimage = testimage.replace("'", "\\'") escdiffimage = diffimage.replace("'", "\\'") # we do a center crop to ignore the outer 1 pixel border, because it often contains garbage in rice video cmd = ("/bin/bash", "-c", "/usr/bin/compare -metric PSNR <( /usr/bin/convert " + escrefimage + " -crop 638x478+1+1 - ) <( /usr/bin/convert " + esctestimage + " -crop 638x478+1+1 - ) " + escdiffimage) else: cmd = ("/usr/bin/compare", "-metric", "PSNR", refimage, testimage, diffimage) pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout similarity = pipe.read().strip() pipe.close() try: db = float(similarity) except: db = 0 if db > 60.0: os.unlink(diffimage) else: report += " Warning: test image '%s/%s' does not match reference. PSNR = %s\n" % (videoname, filename, similarity) warnings += 1 # give report and return report += "%i errors. %i warnings.\n" % (errors, warnings) return True def SendReport(self): global report # if there are no email addresses in the config file, then just we're done if "sendemail" not in self.generalParams: return True if len(self.generalParams["sendemail"]) < 5: return True # construct the email message header emailheader = "To: %s\n" % self.generalParams["sendemail"] emailheader += "From: Mupen64Plus-Tester@fascination.homelinux.net\n" emailheader += "Subject: %s Regression Test Results for Mupen64Plus\n" % self.thisdate emailheader += "Reply-to: do-not-reply@fascination.homelinux.net\n" emailheader += "Content-Type: text/plain; charset=UTF-8\n" emailheader += "Content-Transfer-Encoding: 8bit\n\n" # open a pipe to sendmail and dump our report try: pipe = subprocess.Popen(("/usr/sbin/sendmail", "-t"), stdin=subprocess.PIPE).stdin pipe.write(emailheader) pipe.write(report) pipe.close() except Exception, e: report += "Exception encountered when calling sendmail: '%s'\n" % e report += "Email header:\n%s\n" % emailheader return False return True def ArchiveResults(self, archivedir): global report # create archive dir if it doesn't exist if not os.path.exists(archivedir): os.mkdir(archivedir) # move the images into a subdirectory of 'archive' given by date subdir = os.path.join(archivedir, self.thisdate) if os.path.exists(subdir): if not deltree(subdir): return False if os.path.exists(self.screenshotdir): shutil.move(self.screenshotdir, subdir) # copy the report into the archive directory f = open(os.path.join(archivedir, "report_%s.txt" % self.thisdate), "w") f.write(report) f.close() # archival is complete return True class RegTestRunner(Thread): def __init__(self, exepath, exeparms): self.exepath = exepath self.exeparms = exeparms self.pid = 0 self.returnval = None Thread.__init__(self) def run(self): # start the process testprocess = subprocess.Popen([self.exepath] + self.exeparms) # get the PID of the new test process self.pid = testprocess.pid # wait for the test to complete self.returnval = testprocess.wait() #****************************************************************************** # Generic helper functions # def deltree(dirname): global report if not os.path.exists(dirname): return True try: for path in (os.path.join(dirname, filename) for filename in os.listdir(dirname)): if os.path.isdir(path): if not deltree(path): return False else: os.unlink(path) os.rmdir(dirname) except Exception, e: report += "Error in deltree(): %s\n" % e return False return True def copytree(srcpath, dstpath): if not os.path.isdir(srcpath) or not os.path.isdir(dstpath): return False for filename in os.listdir(srcpath): filepath = os.path.join(srcpath, filename) if os.path.isdir(filepath): subdstpath = os.path.join(dstpath, filename) if not os.path.exists(subdstpath): os.mkdir(subdstpath) copytree(filepath, subdstpath) else: dstfile = os.path.join(dstpath, filename) if os.path.exists(dstfile): os.unlink(dstfile) shutil.copy(filepath, dstpath) return True #****************************************************************************** # main function call for standard script execution # if __name__ == "__main__": # parse the command-line arguments parser = OptionParser() parser.add_option("-g", "--nogit", dest="nogit", default=False, action="store_true", help="Assume source code is present; don't check out latest from Git") parser.add_option("-b", "--nobuild", dest="nobuild", default=False, action="store_true", help="Do not run build tests") parser.add_option("-s", "--nospeed", dest="nospeed", default=False, action="store_true", help="Do not run speed regression test suite") parser.add_option("-v", "--novidcheck", dest="novidcheck", default=False, action="store_true", help="Do not run video screenshot comparison tests") parser.add_option("-e", "--noemail", dest="noemail", default=False, action="store_true", help="don't send email or archive results") parser.add_option("-t", "--testpath", dest="testpath", help="Set root of testing directory to PATH", metavar="PATH") parser.add_option("-c", "--cfgfile", dest="cfgfile", default="daily-tests.cfg", help="Use regression test config file FILE", metavar="FILE") (opts, args) = parser.parse_args() # check test path if opts.testpath is None: # change directory to the directory containing this script and set root test path to "." scriptdir = os.path.dirname(sys.argv[0]) os.chdir(scriptdir) rootdir = "." else: rootdir = opts.testpath # call the main function rval = main(rootdir, opts.cfgfile, opts.nogit, opts.nobuild, opts.nospeed, opts.novidcheck, opts.noemail) sys.exit(rval) mupen64plus-core-src-2.6.0/tools/savestate_convert.c000066400000000000000000000257131464506436200225210ustar00rootroot00000000000000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - savestate_convert.c * * Mupen64Plus homepage: https://mupen64plus.org/ * * Copyright (C) 2008 Richard Goedeken * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include /* savestate file header: magic number and version number */ const char *savestate_magic = "M64+SAVE"; const int savestate_newest_version = 0x00010000; // 1.0 /* Data field lengths */ #define SIZE_REG_RDRAM 40 #define SIZE_REG_MIPS 36 #define SIZE_REG_PI 52 #define SIZE_REG_SP 52 #define SIZE_REG_RSP 8 #define SIZE_REG_SI 16 #define SIZE_REG_VI 60 #define SIZE_REG_RI 32 #define SIZE_REG_AI 40 #define SIZE_REG_DPC 48 #define SIZE_REG_DPS 16 #define SIZE_FLASHRAM_INFO 24 #define SIZE_TLB_ENTRY 52 #define SIZE_MAX_EVENTQUEUE 1024 /* Arrays and pointers for savestate data */ char rom_md5[32]; char rdram_register[SIZE_REG_RDRAM]; char mips_register[SIZE_REG_MIPS]; char pi_register[SIZE_REG_PI]; char sp_register[SIZE_REG_SP]; char rsp_register[SIZE_REG_RSP]; char si_register[SIZE_REG_SI]; char vi_register[SIZE_REG_VI]; char ri_register[SIZE_REG_RI]; char ai_register[SIZE_REG_AI]; char dpc_register[SIZE_REG_DPC]; char dps_register[SIZE_REG_DPS]; char *rdram; /* 0x800000 bytes */ char SP_DMEM[0x1000]; char SP_IMEM[0x1000]; char PIF_RAM[0x40]; char flashram[SIZE_FLASHRAM_INFO]; char *tlb_LUT_r; /* 0x400000 bytes */ char *tlb_LUT_w; /* 0x400000 bytes */ char llbit[4]; char reg[32][8]; char reg_cop0[32][4]; char lo[8]; char hi[8]; char reg_cop1_fgr_64[32][8]; char FCR0[4]; char FCR31[4]; char tlb_e[32][SIZE_TLB_ENTRY]; char PCaddr[4]; char next_interrupt[4]; char next_vi[4]; char vi_field[4]; char eventqueue[SIZE_MAX_EVENTQUEUE]; /* savestate data parameters calculated from file contents */ int queuelength = 0; /* Forward declarations for functions */ void printhelp(const char *progname); int allocate_memory(void); void free_memory(void); int load_original_mupen64(const char *filename); int save_newest(const char *filename); /* Main Function - parse arguments, check version, load state file, overwrite state file with new one */ int main(int argc, char *argv[]) { FILE *pfTest; gzFile f; char *filename; char magictag[8]; unsigned char inbuf[4]; int (*load_function)(const char *) = NULL; int iVersion; /* start by parsing the command-line arguments */ if (argc != 2 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--help", 6) == 0) { printhelp(argv[0]); return 1; } filename = argv[1]; pfTest = osal_file_open(filename, "rb"); if (pfTest == NULL) { printf("Error: cannot open savestate file '%s' for reading.\n", filename); return 2; } fclose(pfTest); /* try to determine the version of this savestate file */ f = gzopen(filename, "rb"); if (f == NULL) { printf("Error: state file '%s' is corrupt\n", filename); return 3; } if (gzread(f, magictag, 8) != 8 || gzread(f, inbuf, 4) != 4) { printf("Error: state file '%s' is corrupt: end of savestate file while reading header.\n", filename); gzclose(f); return 4; } gzclose(f); iVersion = inbuf[0]; iVersion = (iVersion << 8) | inbuf[1]; iVersion = (iVersion << 8) | inbuf[2]; iVersion = (iVersion << 8) | inbuf[3]; /* determine which type of savestate file to load, based on savestate version */ if (strncmp(magictag, savestate_magic, 8) != 0) { printf("Warning: old savestate file format. This is presumed to be from the original Mupen64 or Mupen64Plus version 1.4 or earlier.\n"); load_function = load_original_mupen64; } else if (iVersion == savestate_newest_version) { printf("This savestate file is already up to date (version %08x)\n", savestate_newest_version); return 0; } else { printf("This savestate file uses an unknown version (%08x)\n", iVersion); return 5; } /* allocate memory for savestate data */ if (allocate_memory() != 0) { printf("Error: couldn't allocate memory for savestate data storage.\n"); return 6; } /* load the savestate file */ if (load_function(filename) != 0) { free_memory(); return 7; } /* write new updated savestate file */ if (save_newest(filename) != 0) { free_memory(); return 8; } /* free the memory and return */ printf("Savestate file '%s' successfully converted to latest version (%08x).\n", filename, savestate_newest_version); free_memory(); return 0; } void printhelp(const char *progname) { printf("%s - convert older Mupen64Plus savestate files to most recent version.\n\n", progname); printf("Usage: %s [-h] [--help] \n\n", progname); printf(" -h, --help: display this message\n"); printf(" : full path to savestate file which will be overwritten with latest version.\n"); } int allocate_memory(void) { rdram = malloc(0x800000); if (rdram == NULL) return 1; tlb_LUT_r = malloc(0x400000); if (tlb_LUT_r == NULL) { free_memory(); return 2; } tlb_LUT_w = malloc(0x400000); if (tlb_LUT_w == NULL) { free_memory(); return 3; } return 0; } void free_memory(void) { if (rdram != NULL) { free(rdram); rdram = NULL; } if (tlb_LUT_r != NULL) { free(tlb_LUT_r); tlb_LUT_r = NULL; } if (tlb_LUT_w != NULL) { free(tlb_LUT_w); tlb_LUT_w = NULL; } } /* State Loading Functions */ int load_original_mupen64(const char *filename) { char buffer[4]; int i; gzFile f; f = gzopen(filename, "rb"); if (f == NULL) { printf("Error: savestate file '%s' is corrupt.\n", filename); return 1; } gzread(f, rom_md5, 32); gzread(f, rdram_register, SIZE_REG_RDRAM); gzread(f, mips_register, SIZE_REG_MIPS); gzread(f, pi_register, SIZE_REG_PI); gzread(f, sp_register, SIZE_REG_SP); gzread(f, rsp_register, SIZE_REG_RSP); gzread(f, si_register, SIZE_REG_SI); gzread(f, vi_register, SIZE_REG_VI); gzread(f, ri_register, SIZE_REG_RI); gzread(f, ai_register, SIZE_REG_AI); gzread(f, dpc_register, SIZE_REG_DPC); gzread(f, dps_register, SIZE_REG_DPS); gzread(f, rdram, 0x800000); gzread(f, SP_DMEM, 0x1000); gzread(f, SP_IMEM, 0x1000); gzread(f, PIF_RAM, 0x40); gzread(f, flashram, SIZE_FLASHRAM_INFO); memset(tlb_LUT_r, 0, 0x400000); memset(tlb_LUT_w, 0, 0x400000); gzread(f, tlb_LUT_r, 0x100000); gzread(f, tlb_LUT_w, 0x100000); gzread(f, llbit, 4); gzread(f, reg, 32*8); for (i = 0; i < 32; i++) { gzread(f, reg_cop0[i], 4); gzread(f, buffer, 4); /* for compatibility with older versions. */ } gzread(f, lo, 8); gzread(f, hi, 8); gzread(f, reg_cop1_fgr_64[0], 32 * 8); gzread(f, FCR0, 4); gzread(f, FCR31, 4); gzread(f, tlb_e[0], 32 * SIZE_TLB_ENTRY); gzread(f, PCaddr, 4); gzread(f, next_interrupt, 4); gzread(f, next_vi, 4); gzread(f, vi_field, 4); queuelength = 0; while(queuelength < SIZE_MAX_EVENTQUEUE) { if (gzread(f, eventqueue + queuelength, 4) != 4) { printf("Error: savestate file '%s' is corrupt.\n", filename); return 2; } if (*((unsigned int*) &eventqueue[queuelength]) == 0xFFFFFFFF) { queuelength += 4; break; } gzread(f, eventqueue + queuelength + 4, 4); queuelength += 8; } if (queuelength >= SIZE_MAX_EVENTQUEUE) { printf("Error: savestate file '%s' has event queue larger than %i bytes.\n", filename, SIZE_MAX_EVENTQUEUE); return 3; } gzclose(f); return 0; } /* State Saving Functions */ int save_newest(const char *filename) { unsigned char outbuf[4]; gzFile f; f = gzopen(filename, "wb"); /* write magic number */ gzwrite(f, savestate_magic, 8); /* write savestate file version in big-endian */ outbuf[0] = (savestate_newest_version >> 24) & 0xff; outbuf[1] = (savestate_newest_version >> 16) & 0xff; outbuf[2] = (savestate_newest_version >> 8) & 0xff; outbuf[3] = (savestate_newest_version >> 0) & 0xff; gzwrite(f, outbuf, 4); gzwrite(f, rom_md5, 32); gzwrite(f, rdram_register, SIZE_REG_RDRAM); gzwrite(f, mips_register, SIZE_REG_MIPS); gzwrite(f, pi_register, SIZE_REG_PI); gzwrite(f, sp_register, SIZE_REG_SP); gzwrite(f, rsp_register, SIZE_REG_RSP); gzwrite(f, si_register, SIZE_REG_SI); gzwrite(f, vi_register, SIZE_REG_VI); gzwrite(f, ri_register, SIZE_REG_RI); gzwrite(f, ai_register, SIZE_REG_AI); gzwrite(f, dpc_register, SIZE_REG_DPC); gzwrite(f, dps_register, SIZE_REG_DPS); gzwrite(f, rdram, 0x800000); gzwrite(f, SP_DMEM, 0x1000); gzwrite(f, SP_IMEM, 0x1000); gzwrite(f, PIF_RAM, 0x40); gzwrite(f, flashram, SIZE_FLASHRAM_INFO); gzwrite(f, tlb_LUT_r, 0x400000); gzwrite(f, tlb_LUT_w, 0x400000); gzwrite(f, llbit, 4); gzwrite(f, reg[0], 32*8); gzwrite(f, reg_cop0[0], 32*4); gzwrite(f, lo, 8); gzwrite(f, hi, 8); gzwrite(f, reg_cop1_fgr_64[0], 32*8); gzwrite(f, FCR0, 4); gzwrite(f, FCR31, 4); gzwrite(f, tlb_e[0], 32 * SIZE_TLB_ENTRY); gzwrite(f, PCaddr, 4); gzwrite(f, next_interrupt, 4); gzwrite(f, next_vi, 4); gzwrite(f, vi_field, 4); gzwrite(f, eventqueue, queuelength); gzclose(f); return 0; } mupen64plus-core-src-2.6.0/tools/savestate_convert.txt000066400000000000000000000027451464506436200231160ustar00rootroot00000000000000============================================================================== savestate_convert.txt - Mupen64Plus - July 12th, 2008 This conversion tool was written to help users migrate their savestate files when there are changes to the savestate file format which break backward compatibility. To compile the conversion tool, open a console window, go to the root of your Mupen64Plus source code, and type: gcc -o savestate_convert -lz tools/savestate_convert.c This will create a small command-line application called 'savestate_convert'. This program takes only one command-line parameter, which is a path to the savestate file that you want to update. The old savestate file will be overwritten with the new one, so you may wish to first make a backup copy of the savestate file. If you update a savestate file to a newer version, older versions of Mupen64Plus will not be able to load it. If you wish to update all of the savestate files in your home directory, you may do so with the following bash command: for file in ~/.mupen64plus/save/*.st*; do ./savestate_convert "${file}"; done ============================================================================== Savestate File Format History: version 0: - Original (Unversioned) file format - used by Mupen64 v0.5 and Mupen64Plus up to v1.4 version 1.0: - bugfix: TLB was not being entirely saved and restored - added small header with magic number and version number - introduced in rev 758 of Mupen64Plus SVN repository (trunk) mupen64plus-core-src-2.6.0/tools/uninstall_binary_bundle.sh000077500000000000000000000112671464506436200240620ustar00rootroot00000000000000#!/bin/sh # # mupen64plus binary bundle uninstall script # # Copyright 2007-2014 The Mupen64Plus Development Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # set -e export PATH=/bin:/usr/bin usage() { printf "usage: $(basename $0) [PREFIX] [SHAREDIR] [BINDIR] [LIBDIR] [PLUGINDIR] [MANDIR] \tPREFIX - installation directories prefix (default: /usr/local) \tSHAREDIR - path to Mupen64Plus shared data files (default: \$PREFIX/share/mupen64plus) \tBINDIR - path to Mupen64Plus binary program files (default: \$PREFIX/bin) \tLIBDIR - path to Mupen64Plus core library (default: \$PREFIX/lib) \tPLUGINDIR - path to Mupen64Plus plugin libraries (default: \$PREFIX/lib/mupen64plus) \tMANDIR - path to manual files (default: \$PREFIX/man) \tAPPSDIR - path to install desktop file (default: \$PREFIX/share/applications) \tICONSDIR - path to install icon files (default: \$PREFIX/share/icons/hicolor) " } if [ $# -gt 8 ]; then usage exit 1 fi PREFIX="${1:-/usr/local}" SHAREDIR="${2:-${PREFIX}/share/mupen64plus}" BINDIR="${3:-${PREFIX}/bin}" LIBDIR="${4:-${PREFIX}/lib}" PLUGINDIR="${5:-${PREFIX}/lib/mupen64plus}" MANDIR="${6:-${PREFIX}/share/man}" APPSDIR="${7:-${PREFIX}/share/applications}" ICONSDIR="${8:-${PREFIX}/share/icons/hicolor}" # simple check for some permissions if [ -d "${SHAREDIR}" -a ! -w "${SHAREDIR}" ]; then printf "Error: you do not have permission to uninstall from: ${SHAREDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${BINDIR}" -a ! -w "${BINDIR}" ]; then printf "Error: you do not have permission to uninstall from: ${BINDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${LIBDIR}" -a ! -w "${LIBDIR}" ]; then printf "Error: you do not have permission to uninstall from: ${LIBDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${PLUGINDIR}" -a ! -w "${PLUGINDIR}" ]; then printf "Error: you do not have permission to uninstall from: ${PLUGINDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${MANDIR}" -a ! -w "${MANDIR}" ]; then printf "Error: you do not have permission to uninstall from: ${MANDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${APPSDIR}" -a ! -w "${APPSDIR}" ]; then printf "Error: you do not have permission to install at: ${APPSDIR}\nMaybe you need to be root?\n" exit 1 fi if [ -d "${ICONSDIR}" -a ! -w "${ICONSDIR}" ]; then printf "Error: you do not have permission to install at: ${ICONSDIR}\nMaybe you need to be root?\n" exit 1 fi printf "Uninstalling Mupen64Plus Binary Bundle from ${PREFIX}\n" # Mupen64Plus-Core rm -f "${LIBDIR}"/libmupen64plus.so* /sbin/ldconfig rm -f "${SHAREDIR}/font.ttf" rm -f "${SHAREDIR}/mupencheat.txt" rm -f "${SHAREDIR}/mupen64plus.ini" rm -f "${SHAREDIR}"/doc/* # Mupen64Plus-ROM rm -f "${SHAREDIR}/m64p_test_rom.v64" # Mupen64Plus-UI-Console rm -f "${BINDIR}/mupen64plus" rm -f "${MANDIR}/man6/mupen64plus.6" rm -f "${APPSDIR}/mupen64plus.desktop" rm -f "${ICONSDIR}/48x48/apps/mupen64plus.png" rm -f "${ICONSDIR}/scalable/apps/mupen64plus.svg" # Plugins rm -f "${PLUGINDIR}/mupen64plus-audio-sdl.so" rm -f "${PLUGINDIR}/mupen64plus-input-sdl.so" rm -f "${PLUGINDIR}/mupen64plus-rsp-hle.so" rm -f "${PLUGINDIR}/mupen64plus-video-rice.so" rm -f "${PLUGINDIR}/mupen64plus-video-glide64mk2.so" rm -f "${SHAREDIR}/RiceVideoLinux.ini" rm -f "${SHAREDIR}/InputAutoCfg.ini" rm -f "${SHAREDIR}/Glide64mk2.ini" # get rid of the empty dirs # ignore directories if they are really symbolic links [ ! -L "${SHAREDIR}/doc" ] && rmdir --ignore-fail-on-non-empty "${SHAREDIR}/doc" [ ! -L "${SHAREDIR}" ] && rmdir --ignore-fail-on-non-empty "${SHAREDIR}" [ ! -L "${BINDIR}" ] && rmdir --ignore-fail-on-non-empty "${BINDIR}" [ ! -L "${LIBDIR}" ] && rmdir --ignore-fail-on-non-empty "${LIBDIR}" [ ! -L "${PLUGINDIR}" ] && rmdir --ignore-fail-on-non-empty "${PLUGINDIR}" [ ! -L "${MANDIR}/man6" ] && rmdir --ignore-fail-on-non-empty "${MANDIR}/man6" [ ! -L "${MANDIR}" ] && rmdir --ignore-fail-on-non-empty "${MANDIR}" [ ! -L "${APPSDIR}" ] && rmdir --ignore-fail-on-non-empty "${APPSDIR}" [ ! -L "${ICONSDIR}" ] && rmdir --ignore-fail-on-non-empty "${ICONSDIR}" printf "Uninstall successful.\n"